// RUN: %clang_cc1 -no-opaque-pointers -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 %0*, // CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]], // self nil-check // CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** [[SELFADDR]], // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq %0* [[SELF]], null // CHECK-NEXT: br i1 [[NILCHECK]], // setting return value to nil // CHECK-LABEL: objc_direct_method.self_is_nil: // CHECK: [[RET0:%.*]] = bitcast{{.*}}[[RETVAL]] // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RET0]], 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 i8*, // CHECK-NEXT: store i8* %{{.*}}, i8** [[SELFADDR]], // [self self] // CHECK-NEXT: [[SELF:%.*]] = load i8*, i8** [[SELFADDR]], // CHECK-NEXT: [[SELFSEL:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ // CHECK-NEXT: [[SELF0:%.*]] = call {{.*}} @objc_msgSend // CHECK-NEXT: store i8* [[SELF0]], i8** [[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 %0*, // CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]], // self nil-check // CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** [[SELFADDR]], // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq %0* [[SELF]], null // CHECK-NEXT: br i1 [[NILCHECK]], // setting return value to nil // CHECK-LABEL: objc_direct_method.self_is_nil: // CHECK: [[RET0:%.*]] = bitcast{{.*}}[[RETVAL]] // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RET0]], i8 0, // CHECK-NEXT: br label // set value // CHECK-LABEL: objc_direct_method.cont: // CHECK: [[RET1:%.*]] = bitcast{{.*}}[[RETVAL]] // CHECK-NEXT: call void @llvm.memcpy{{[^(]*}}({{[^,]*}}[[RET1]], // CHECK-NEXT: br label // return // CHECK-LABEL: return: // CHECK: [[RET2:%.*]] = bitcast{{.*}}[[RETVAL]] // CHECK-NEXT: {{%.*}} = load{{.*}}[[RET2]], // 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: %struct.my_aggregate_struct* noalias sret(%struct.my_aggregate_struct) align 4 [[RETVAL:%[^,]*]], // loading parameters // CHECK-LABEL: entry: // CHECK-NEXT: [[SELFADDR:%.*]] = alloca %0*, // CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]], // self nil-check // CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** [[SELFADDR]], // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq %0* [[SELF]], null // CHECK-NEXT: br i1 [[NILCHECK]], // setting return value to nil // CHECK-LABEL: objc_direct_method.self_is_nil: // CHECK: [[RET0:%.*]] = bitcast{{.*}}[[RETVAL]] // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RET0]], i8 0, // CHECK-NEXT: br label // set value // CHECK-LABEL: objc_direct_method.cont: // CHECK: [[RET1:%.*]] = bitcast{{.*}}[[RETVAL]] // 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 %0*, // CHECK-NEXT: [[CMDVAL:%_cmd]] = alloca i8*, // loading the _cmd selector // CHECK-LABEL: objc_direct_method.cont: // CHECK-NEXT: [[CMD1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ // CHECK-NEXT: store i8* [[CMD1]], i8** [[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 i8* @"\01-[Root objectProperty]"( // CHECK-LABEL: objc_direct_method.cont: // CHECK-NEXT: [[SELFVAL:%.*]] = load {{.*}} %self.addr, // CHECK-NEXT: [[SELF:%.*]] = bitcast {{.*}} [[SELFVAL]] to i8* // CHECK-NEXT: [[IVAR:%.*]] = load {{.*}} @"OBJC_IVAR_$_Root._objectProperty", // CHECK-NEXT: call i8* @objc_getProperty(i8* noundef [[SELF]], i8* noundef poison, i64 noundef [[IVAR]], {{.*}}) @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 bitcast {{.*}} @"\01-[Root getInt]" to i32 (i8*) // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty]" to i32 (i8*) // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty2]" to i32 (i8*) return [r getInt] + [r intProperty] + [r intProperty2]; } int useFoo(Foo *f) { // CHECK-LABEL: define{{.*}} i32 @useFoo // CHECK: call void bitcast {{.*}} @"\01-[Foo setGetDynamic_setDirect:]" to void (i8*, i32) // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo getDirect_setDynamic]" to i32 (i8*) // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInExtension]" to i32 (i8*) // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategory]" to i32 (i8*) // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategoryNoDecl]" to i32 (i8*) [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 bitcast {{.*}} @"\01-[RootDeclOnly intProperty]" return [r intProperty]; }