238 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
| // 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;
 | |
| @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: [[_CMDADDR:%.*]] = alloca i8*,
 | |
|   // CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]],
 | |
|   // CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
 | |
| 
 | |
|   // 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: [[_CMDADDR:%.*]] = alloca i8*,
 | |
|   // CHECK-NEXT: store i8* %{{.*}}, i8** [[SELFADDR]],
 | |
|   // CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
 | |
| 
 | |
|   // [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: [[_CMDADDR:%.*]] = alloca i8*,
 | |
|   // CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]],
 | |
|   // CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
 | |
| 
 | |
|   // 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 [[RETVAL:%[^,]*]],
 | |
| 
 | |
|   // loading parameters
 | |
|   // CHECK-LABEL: entry:
 | |
|   // CHECK-NEXT: [[SELFADDR:%.*]] = alloca %0*,
 | |
|   // CHECK-NEXT: [[_CMDADDR:%.*]] = alloca i8*,
 | |
|   // CHECK-NEXT: store %0* %{{.*}}, %0** [[SELFADDR]],
 | |
|   // CHECK-NEXT: store i8* %{{.*}}, i8** [[_CMDADDR]],
 | |
| 
 | |
|   // 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
 | |
| }
 | |
| 
 | |
| @end
 | |
| // CHECK-LABEL: define hidden i32 @"\01-[Root intProperty]"
 | |
| 
 | |
| @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]"
 | |
|   // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty]"
 | |
|   // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Root intProperty2]"
 | |
|   return [r getInt] + [r intProperty] + [r intProperty2];
 | |
| }
 | |
| 
 | |
| int useFoo(Foo *f) {
 | |
|   // CHECK-LABEL: define i32 @useFoo
 | |
|   // CHECK: call void bitcast {{.*}} @"\01-[Foo setGetDynamic_setDirect:]"
 | |
|   // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo getDirect_setDynamic]"
 | |
|   // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInExtension]"
 | |
|   // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\01-[Foo directMethodInCategory]"
 | |
|   // CHECK: %{{[^ ]*}} = call i32 bitcast {{.*}} @"\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 bitcast {{.*}} @"\01-[RootDeclOnly intProperty]"
 | |
|   return [r intProperty];
 | |
| }
 |