| // RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -o - | FileCheck %s | |
| struct my_complex_struct { | |
| int a, b; | |
| }; | |
| struct my_aggregate_struct { | |
| int a, b; | |
| char buf[128]; | |
| }; | |
| __attribute__((objc_root_class)) | |
| @interface Root | |
| - (int)getInt __attribute__((objc_direct)); | |
| @property(direct, readonly) int intProperty; | |
| @property(direct, readonly) int intProperty2; | |
| @property(direct, readonly) id objectProperty; | |
| @end | |
| @implementation Root | |
| // CHECK-LABEL: define hidden i32 @"\01-[Root intProperty2]" | |
| - (int)intProperty2 { | |
| return 42; | |
| } | |
| // CHECK-LABEL: define hidden i32 @"\01-[Root getInt]"( | |
| - (int)getInt __attribute__((objc_direct)) { | |
| // loading parameters | |
| // CHECK-LABEL: entry: | |
| // CHECK-NEXT: [[RETVAL:%.*]] = alloca | |
| // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr, | |
| // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]], | |
| // self nil-check | |
| // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]], | |
| // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq ptr [[SELF]], null | |
| // CHECK-NEXT: br i1 [[NILCHECK]], | |
| // setting return value to nil | |
| // CHECK-LABEL: objc_direct_method.self_is_nil: | |
| // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RETVAL]], i8 0, | |
| // CHECK-NEXT: br label | |
| // set value | |
| // CHECK-LABEL: objc_direct_method.cont: | |
| // CHECK: store{{.*}}[[RETVAL]], | |
| // CHECK-NEXT: br label | |
| // return | |
| // CHECK-LABEL: return: | |
| // CHECK: {{%.*}} = load{{.*}}[[RETVAL]], | |
| // CHECK-NEXT: ret | |
| return 42; | |
| } | |
| // CHECK-LABEL: define hidden i32 @"\01+[Root classGetInt]"( | |
| + (int)classGetInt __attribute__((objc_direct)) { | |
| // loading parameters | |
| // CHECK-LABEL: entry: | |
| // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr, | |
| // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]], | |
| // [self self] | |
| // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]], | |
| // CHECK-NEXT: [[SELFSEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_ | |
| // CHECK-NEXT: [[SELF0:%.*]] = call {{.*}} @objc_msgSend | |
| // CHECK-NEXT: store ptr [[SELF0]], ptr [[SELFADDR]], | |
| // return | |
| // CHECK-NEXT: ret | |
| return 42; | |
| } | |
| // CHECK-LABEL: define hidden i64 @"\01-[Root getComplex]"( | |
| - (struct my_complex_struct)getComplex __attribute__((objc_direct)) { | |
| // loading parameters | |
| // CHECK-LABEL: entry: | |
| // CHECK-NEXT: [[RETVAL:%.*]] = alloca | |
| // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr, | |
| // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]], | |
| // self nil-check | |
| // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]], | |
| // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq ptr [[SELF]], null | |
| // CHECK-NEXT: br i1 [[NILCHECK]], | |
| // setting return value to nil | |
| // CHECK-LABEL: objc_direct_method.self_is_nil: | |
| // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RETVAL]], i8 0, | |
| // CHECK-NEXT: br label | |
| // set value | |
| // CHECK-LABEL: objc_direct_method.cont: | |
| // CHECK-NEXT: call void @llvm.memcpy{{[^(]*}}({{[^,]*}}[[RETVAL]], | |
| // CHECK-NEXT: br label | |
| // return | |
| // CHECK-LABEL: return: | |
| // CHECK-NEXT: {{%.*}} = load{{.*}}[[RETVAL]], | |
| // CHECK-NEXT: ret | |
| struct my_complex_struct st = {.a = 42}; | |
| return st; | |
| } | |
| // CHECK-LABEL: define hidden i64 @"\01+[Root classGetComplex]"( | |
| + (struct my_complex_struct)classGetComplex __attribute__((objc_direct)) { | |
| struct my_complex_struct st = {.a = 42}; | |
| return st; | |
| // CHECK: ret i64 | |
| } | |
| // CHECK-LABEL: define hidden void @"\01-[Root getAggregate]"( | |
| - (struct my_aggregate_struct)getAggregate __attribute__((objc_direct)) { | |
| // CHECK: ptr dead_on_unwind noalias writable sret(%struct.my_aggregate_struct) align 4 [[RETVAL:%[^,]*]], | |
| // loading parameters | |
| // CHECK-LABEL: entry: | |
| // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr, | |
| // CHECK-NEXT: store ptr %{{.*}}, ptr [[SELFADDR]], | |
| // self nil-check | |
| // CHECK-NEXT: [[SELF:%.*]] = load ptr, ptr [[SELFADDR]], | |
| // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq ptr [[SELF]], null | |
| // CHECK-NEXT: br i1 [[NILCHECK]], | |
| // setting return value to nil | |
| // CHECK-LABEL: objc_direct_method.self_is_nil: | |
| // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RETVAL]], i8 0, | |
| // CHECK-NEXT: br label | |
| // set value | |
| // CHECK-LABEL: objc_direct_method.cont: | |
| // CHECK: br label | |
| // return | |
| // CHECK-LABEL: return: | |
| // CHECK: ret void | |
| struct my_aggregate_struct st = {.a = 42}; | |
| return st; | |
| } | |
| // CHECK-LABEL: define hidden void @"\01+[Root classGetAggregate]"( | |
| + (struct my_aggregate_struct)classGetAggregate __attribute__((objc_direct)) { | |
| struct my_aggregate_struct st = {.a = 42}; | |
| return st; | |
| // CHECK: ret void | |
| } | |
| // CHECK-LABEL: define hidden void @"\01-[Root accessCmd]"( | |
| - (void)accessCmd __attribute__((objc_direct)) { | |
| // CHECK-LABEL: entry: | |
| // CHECK-NEXT: [[SELFADDR:%.*]] = alloca ptr, | |
| // CHECK-NEXT: [[CMDVAL:%_cmd]] = alloca ptr, | |
| // loading the _cmd selector | |
| // CHECK-LABEL: objc_direct_method.cont: | |
| // CHECK-NEXT: [[CMD1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_ | |
| // CHECK-NEXT: store ptr [[CMD1]], ptr [[CMDVAL]], | |
| SEL sel = _cmd; | |
| } | |
| @end | |
| // CHECK-LABEL: define hidden i32 @"\01-[Root intProperty]" | |
| // Check the synthesized objectProperty calls objc_getProperty(); this also | |
| // checks that the synthesized method passes undef for the `cmd` argument. | |
| // CHECK-LABEL: define hidden ptr @"\01-[Root objectProperty]"( | |
| // CHECK-LABEL: objc_direct_method.cont: | |
| // CHECK-NEXT: [[SELFVAL:%.*]] = load {{.*}} %self.addr, | |
| // CHECK-NEXT: call ptr @objc_getProperty(ptr noundef [[SELFVAL]], ptr noundef poison, i64 noundef 8, {{.*}}) | |
| @interface Foo : Root { | |
| id __strong _cause_cxx_destruct; | |
| } | |
| @property(nonatomic, readonly, direct) int getDirect_setDynamic; | |
| @property(nonatomic, readonly) int getDynamic_setDirect; | |
| @end | |
| @interface Foo () | |
| @property(nonatomic, readwrite) int getDirect_setDynamic; | |
| @property(nonatomic, readwrite, direct) int getDynamic_setDirect; | |
| - (int)directMethodInExtension __attribute__((objc_direct)); | |
| @end | |
| @interface Foo (Cat) | |
| - (int)directMethodInCategory __attribute__((objc_direct)); | |
| @end | |
| __attribute__((objc_direct_members)) | |
| @implementation Foo | |
| // CHECK-LABEL: define hidden i32 @"\01-[Foo directMethodInExtension]"( | |
| - (int)directMethodInExtension { | |
| return 42; | |
| } | |
| // CHECK-LABEL: define hidden i32 @"\01-[Foo getDirect_setDynamic]"( | |
| // CHECK-LABEL: define internal void @"\01-[Foo setGetDirect_setDynamic:]"( | |
| // CHECK-LABEL: define internal i32 @"\01-[Foo getDynamic_setDirect]"( | |
| // CHECK-LABEL: define hidden void @"\01-[Foo setGetDynamic_setDirect:]"( | |
| // CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]"( | |
| @end | |
| @implementation Foo (Cat) | |
| // CHECK-LABEL: define hidden i32 @"\01-[Foo directMethodInCategory]"( | |
| - (int)directMethodInCategory { | |
| return 42; | |
| } | |
| // CHECK-LABEL: define hidden i32 @"\01-[Foo directMethodInCategoryNoDecl]"( | |
| - (int)directMethodInCategoryNoDecl __attribute__((objc_direct)) { | |
| return 42; | |
| } | |
| @end | |
| int useRoot(Root *r) { | |
| // CHECK-LABEL: define{{.*}} i32 @useRoot | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Root getInt]" | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Root intProperty]" | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Root intProperty2]" | |
| return [r getInt] + [r intProperty] + [r intProperty2]; | |
| } | |
| int useFoo(Foo *f) { | |
| // CHECK-LABEL: define{{.*}} i32 @useFoo | |
| // CHECK: call void @"\01-[Foo setGetDynamic_setDirect:]" | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo getDirect_setDynamic]" | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo directMethodInExtension]" | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo directMethodInCategory]" | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[Foo directMethodInCategoryNoDecl]" | |
| [f setGetDynamic_setDirect:1]; | |
| return [f getDirect_setDynamic] + | |
| [f directMethodInExtension] + | |
| [f directMethodInCategory] + | |
| [f directMethodInCategoryNoDecl]; | |
| } | |
| __attribute__((objc_root_class)) | |
| @interface RootDeclOnly | |
| @property(direct, readonly) int intProperty; | |
| @end | |
| int useRootDeclOnly(RootDeclOnly *r) { | |
| // CHECK-LABEL: define{{.*}} i32 @useRootDeclOnly | |
| // CHECK: %{{[^ ]*}} = call i32 @"\01-[RootDeclOnly intProperty]" | |
| return [r intProperty]; | |
| } |