-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[GNU ObjC] Clang 14 regression: class methods always return nil object with ARC and optimization #56952
Comments
Additionally I’m seeing some very strange behavior calling class methods in GNUstep Base with Clang 14 and 15rc1 using ARC and -O1 or -O2, which might be related to the above: @try {
id processInfoClass = [NSProcessInfo class];
NSLog(@"processInfoClass: %@ (%p)", processInfoClass, processInfoClass);
id processInfo = [NSProcessInfo processInfo];
NSLog(@"processInfo: %@ (%p)", processInfo, processInfo);
id arguments = [processInfo arguments];
NSLog(@"arguments: %@", arguments);
} @catch (id exc) {
NSLog(@"Exception: %@", exc);
} This will result in the following exception when calling
I can work around that by replacing
In summary it seems like there’s some mixup with what kind of class objects the compiler returns, but it depends on the exact code, e.g. when calling just one of these methods above individually it works fine. |
@llvm/issue-subscribers-clang-codegen |
Is this Windows-only? Can you run clang with My guess is that LLVM is seeing that the class global variable is initialized to a null pointer and somehow missing the fact that the function that sets it is called from the runtime. |
Looks like this is a Windows-only issue, at least we were unable to reproduce it on Debian 11 aarch64 using Clang 15.0.0-rc2. This is the LLVM IR dump of a further reduced test case printed below, though unfortunately I’m not fully sure how to read it: #import "objc/runtime.h"
__attribute__((objc_root_class))
@interface TestObj { id isa; }
+ (Class)class;
+ (id)testObj;
@end
@implementation TestObj
+ (Class)class {
return self;
}
+ (id)testObj {
id testObj = @"Test";
return testObj;
}
@end
int main() {
TestObj *testObj = [TestObj testObj];
return testObj ? 0 : 1;
} |
One quick find in the assembly of the Here is an annotated assembly diff that omits some non-printable characters from the -ClassMethods_arc_clang13_release.m.obj: file format coff-x86-64
+ClassMethods_arc_clang14_release.m.obj: file format coff-x86-64
@@ -92,7 +92,7 @@
7: 48 8b 0d 00 00 00 00 movq (%rip), %rcx # $_OBJC_REF_CLASS_TestObj
e: 48 8d 15 00 00 00 00 leaq (%rip), %rdx # .objc_selector_class___ (1)
15: e8 00 00 00 00 callq 0x1a <main+0x1a> # objc_msgSend
- 1a: 48 89 c1 movq %rax, %rcx
+ 1a: 48 89 c7 movq %rax, %rdi
1d: e8 00 00 00 00 callq 0x22 <main+0x22> # objc_retainAutoreleasedReturnValue
22: 48 89 c6 movq %rax, %rsi
25: 48 89 c1 movq %rax, %rcx
@@ -104,7 +104,7 @@
40: 48 8b 0d 00 00 00 00 movq (%rip), %rcx # $_OBJC_REF_CLASS_TestObj
47: 48 8d 15 00 00 00 00 leaq (%rip), %rdx # .objc_selector_testObj___ (2)
4e: e8 00 00 00 00 callq 0x53 <main+0x53> # objc_msgSend
- 53: 48 89 c1 movq %rax, %rcx
+ 53: 48 89 c7 movq %rax, %rdi
56: e8 00 00 00 00 callq 0x5b <main+0x5b> # objc_retainAutoreleasedReturnValue
5b: 48 89 c7 movq %rax, %rdi
5e: 48 8d 0d 00 00 00 00 leaq (%rip), %rcx The difference is in two places between the calls to
|
I used the above assembly difference for bisectioning the clang history and arrived at this commit: d61eb6c On the current release/15.x version, I tested a change that lets Windows targets opt-out from using My guess is that this can only be a temporary fix as it likely has an impact on performance of compiled output. A proper solution would teach the x86_64 backend for Windows how to handle the operand bundle correctly. |
This usage of RDI seems like the bug: That was added in c2d44bd by @fhahn . The first parameter register on Windows is RCX, not RDI. |
As discussed in https://reviews.llvm.org/D134441, if the runtime on windows excepts a different marker instruction, we should update |
Thanks for your feedback everyone!
Yes, I tested this and it gives the correct output as well!
On Windows it just looks like a regular call following the x64 calling convention and I didn't see anything in the implementation that inspects instruction opcodes on the caller side (so far). @davidchisnall Is GNUstep checking for optimized callers like the |
Basically, this is the attempt from my first review D134441. The bundle only makes sure that the instruction sequence ends up unmodified in the binary right? Could it have any other/non-obvious side-effects? There are several places that check for the presence of the bundle. Most of them appear to make sure the instruction sequence stays intact, but is it the case for the following two as well? Also, it looks like the inliner can insert these bundles as well -- would I need to suppress this? I guess without a marker, GNUstep wouldn't have a chance to implement ObjC ARC autorelease optimization and always miss autorelease elision like this: #31273 |
…on Windows Fix regression llvm#56952 for Clang CodeGen on Windows. In the Windows ABI the instruction sequence that is expanded from CALL_RVMARKER should use RCX as target register and not RDI. Differential Revision: https://reviews.llvm.org/D134441
Known issues: #7 llvm/llvm-project#43828 llvm/llvm-project#51899 llvm/llvm-project#54556 llvm/llvm-project#56952 gnustep/libobjc2#222 Also removed copy about GNUstep test failures, as they have been fixed.
…on Windows Fix regression #56952 for Clang CodeGen on Windows. In the Windows ABI the instruction sequence that is expanded from CALL_RVMARKER should use RCX as target register and not RDI. Reviewed By: rnk, fhahn Differential Revision: https://reviews.llvm.org/D134441
This should be fixed with commit https://reviews.llvm.org/rGed8409dfa0a92d80c021f13ca271737492522cc7. It doesn't look like GNUstep checks for optimized callers, but we keep the marker so that it will remain possible. Please find more details in the review. |
Thanks for the fix! |
@llvm/issue-subscribers-backend-x86 |
…on Windows Fix regression llvm#56952 for Clang CodeGen on Windows. In the Windows ABI the instruction sequence that is expanded from CALL_RVMARKER should use RCX as target register and not RDI. Reviewed By: rnk, fhahn Differential Revision: https://reviews.llvm.org/D134441
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE ``` Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] ``` Only support single use base, multi-use scenes are supported by PR74046. Fix llvm#71917 TODO: support the multiple-uses with reuseing common base offset. https://gcc.godbolt.org/z/Mr7srTjnz
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] Only LDRBBroX is supported for the first time. Fix llvm#71917
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] Only LDRBBroX is supported for the first time. Fix llvm#71917
…on Windows Fix regression llvm/llvm-project#56952 for Clang CodeGen on Windows. In the Windows ABI the instruction sequence that is expanded from CALL_RVMARKER should use RCX as target register and not RDI. Reviewed By: rnk, fhahn Differential Revision: https://reviews.llvm.org/D134441
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] Only LDRBBroX is supported for the first time. Fix llvm#71917 Note: This PR is try relanding the commit 32878c2 with fix crash for PR79756 this crash is exposes when there is MOVKWi instruction in the head of a block, but without MOVZWi
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] Only LDRBBroX is supported for the first time. Fix llvm#71917 Note: This PR is try relanding the commit 32878c2 with fix crash for PR79756 this crash is exposes when there is MOVKWi instruction in the head of a block, but without MOVZWi
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] Only LDRBBroX is supported for the first time. Fix llvm#71917 Note: This PR is try relanding the commit 32878c2 with fix crash for PR79756 this crash is exposes when there is MOVKWi instruction in the head of a block, but without MOVZWi
Using using Automatic Reference Counting and
-O1
or better optimization using Clang 14.0.5 or 15.0 rc1 causes class methods returning an ObjC object type to always return a null pointer.This works correctly with Clang 13, or when not using ARC, or when using
-O0
optimization. Methods returning C primitive types are not affected.The following code reproduces the issue:
Build command:
Output:
The text was updated successfully, but these errors were encountered: