| // Test variadic direct methods - use inline preconditions instead of thunks |
| // to avoid musttail complexity across different architectures. |
| // RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple arm64-apple-darwin10 \ |
| // RUN: -fobjc-direct-precondition-thunk %s -o - | FileCheck %s |
| |
| __attribute__((objc_root_class)) |
| @interface Root |
| - (int)varMethod:(int)first, ... __attribute__((objc_direct)); |
| + (void)printf:(Root *)format, ... __attribute__((objc_direct)); |
| @end |
| |
| // Add a weakly linked class and a weakly linked class method |
| __attribute__((objc_root_class, weak_import)) |
| @interface WeakRoot |
| + (int)weakPrintf:(int)first, ... __attribute__((objc_direct, weak_import)); |
| @end |
| |
| |
| @implementation Root |
| |
| // Variadic methods use inline preconditions instead of thunks |
| // to avoid musttail complexity across different architectures. |
| // CHECK-LABEL: define hidden i32 @"-[Root varMethod:]D"( |
| // CHECK-NOT: @"\01-[Root varMethod:]" |
| // CHECK-NOT: @"-[Root varMethod:]D_thunk" |
| - (int)varMethod:(int)first, ... { |
| // Should NOT have nil check (moved to caller) |
| // CHECK-NOT: icmp eq ptr {{.*}}, null |
| // CHECK-NOT: objc_direct_method.self_is_nil |
| return first; |
| } |
| |
| // CHECK-LABEL: define hidden void @"+[Root printf:]D"( |
| // CHECK-NOT: @"\01+[Root printf:]" |
| // CHECK-NOT: @"+[Root printf:]D_thunk" |
| // Class realization should be at the call site, not in the implementation. |
| // CHECK-NOT: objc_msgSend |
| + (void)printf:(Root *)format, ... {} |
| |
| @end |
| |
| // Test: Nullable receiver should have inline nil check |
| // CHECK-LABEL: define{{.*}} void @useRoot( |
| void useRoot(Root *_Nullable root) { |
| // For nullable receivers, we should emit nil check inline |
| // CHECK: icmp eq ptr %{{[0-9]+}}, null |
| // CHECK: br i1 %{{[0-9]+}}, label %msgSend.null-receiver, label %msgSend.call |
| |
| // CHECK: msgSend.call: |
| // CHECK: call i32 (ptr, i32, ...) @"-[Root varMethod:]D"(ptr noundef %{{[0-9]+}}, i32 noundef 1, i32 noundef 2, double noundef 3.0{{.*}}) |
| // CHECK: br label %msgSend.cont |
| |
| // CHECK: msgSend.null-receiver: |
| // CHECK: br label %msgSend.cont |
| |
| // CHECK: msgSend.cont: |
| [root varMethod:1, 2, 3.0]; |
| |
| // Class realization before call |
| // CHECK: %{{.*}} = load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$ |
| // CHECK: %{{.*}} = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, |
| // CHECK: %{{.*}} = call ptr @objc_msgSend |
| // CHECK: call void (ptr, ptr, ...) @"+[Root printf:]D"( |
| [Root printf:root, "hello", root]; |
| |
| // For weakly linked class, inline realization first |
| // CHECK: %{{.*}} = load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$ |
| // CHECK: %{{.*}} = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, |
| // CHECK: %{{.*}} = call ptr @objc_msgSend |
| |
| // Then perform nil check |
| // CHECK: %{{.*}} = icmp eq ptr %{{.*}}, null |
| // CHECK: br i1 %{{.*}}, label %msgSend.null-receiver{{.*}}, label %msgSend.call{{.*}} |
| |
| // Finally call the class method |
| // CHECK: %{{.*}} = call i32 (ptr, i32, ...) @"+[WeakRoot weakPrintf:]D" |
| [WeakRoot weakPrintf: 1, 2, 3.0]; |
| } |
| |
| // Test: Non-null receiver |
| |
| // CHECK-LABEL: define{{.*}} void @useRootNonNull( |
| void useRootNonNull(Root *_Nonnull root) { |
| // TODO: For nonnull receivers, we should not emit nil check inline |
| // CHECK: icmp eq ptr %{{[0-9]+}}, null |
| // CHECK: br i1 %{{[0-9]+}}, label %msgSend.null-receiver, label %msgSend.call |
| |
| // CHECK: msgSend.call: |
| // CHECK: call i32 (ptr, i32, ...) @"-[Root varMethod:]D"(ptr noundef %{{[0-9]+}}, i32 noundef 1, i32 noundef 2, double noundef 3.0{{.*}}) |
| // CHECK: br label %msgSend.cont |
| |
| // CHECK: msgSend.null-receiver: |
| // CHECK: br label %msgSend.cont |
| |
| // CHECK: msgSend.cont: |
| [root varMethod:1, 2, 3.0]; |
| |
| // Class realization before call |
| // CHECK: %{{.*}} = load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$ |
| // CHECK: %{{.*}} = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, |
| // CHECK: %{{.*}} = call ptr @objc_msgSend |
| // CHECK: call void (ptr, ptr, ...) @"+[Root printf:]D"( |
| [Root printf:root, "hello", root]; |
| } |