1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MODERN |
2 | // RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-FRAGILE |
3 | |
4 | @interface Object |
5 | - (instancetype) retain; |
6 | - (void) run; |
7 | @end |
8 | |
9 | // The ivars in HighlyAlignedSubclass should be placed in the tail-padding |
10 | // of the superclass. Ensure that they're still covered by layouts. |
11 | @interface HighlyAligned : Object { |
12 | __attribute__((aligned(32))) void *array[2]; |
13 | } |
14 | @end |
15 | // CHECK-MODERN: @"OBJC_IVAR_$_HighlyAlignedSubclass.ivar2" = global i64 24, |
16 | // CHECK-MODERN: @"OBJC_IVAR_$_HighlyAlignedSubclass.ivar" = global i64 16, |
17 | // CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\02\00" |
18 | // CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_HighlyAlignedSubclass" = {{.*}} { |
19 | // CHECK-FRAGILE: @OBJC_INSTANCE_VARIABLES_HighlyAlignedSubclass = {{.*}}, i32 8 }, {{.*}}, i32 12 }] |
20 | // CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\02\00" |
21 | // CHECK-FRAGILE: @OBJC_CLASS_HighlyAlignedSubclass |
22 | @interface HighlyAlignedSubclass : HighlyAligned { |
23 | __weak id ivar; |
24 | __weak id ivar2; |
25 | } |
26 | @end |
27 | @implementation HighlyAlignedSubclass @end |
28 | |
29 | // CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00" |
30 | // CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_Foo" = {{.*}} { i32 772 |
31 | // 772 == 0x304 |
32 | // ^ HasMRCWeakIvars |
33 | // ^ HasCXXDestructorOnly |
34 | // ^ HasCXXStructors |
35 | |
36 | // CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00" |
37 | // CHECK-FRAGILE: @OBJC_CLASS_Foo = {{.*}} i32 134225921, |
38 | // 134225921 == 0x08002001 |
39 | // ^ HasMRCWeakIvars |
40 | // ^ HasCXXStructors |
41 | // ^ Factory |
42 | @interface Foo : Object { |
43 | __weak id ivar; |
44 | } |
45 | @end |
46 | |
47 | @implementation Foo |
48 | // CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]" |
49 | // CHECK: call void @llvm.objc.destroyWeak |
50 | @end |
51 | |
52 | |
53 | void test1(__weak id x) {} |
54 | // CHECK-LABEL: define void @test1 |
55 | // CHECK: [[X:%.*]] = alloca i8*, |
56 | // CHECK-NEXT: @llvm.objc.initWeak |
57 | // CHECK-NEXT: @llvm.objc.destroyWeak |
58 | // CHECK-NEXT: ret void |
59 | |
60 | void test2(id y) { |
61 | __weak id z = y; |
62 | } |
63 | // CHECK-LABEL: define void @test2 |
64 | // CHECK: [[Y:%.*]] = alloca i8*, |
65 | // CHECK-NEXT: [[Z:%.*]] = alloca i8*, |
66 | // CHECK-NEXT: store |
67 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] |
68 | // CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** [[Z]], i8* [[T0]]) |
69 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[Z]]) |
70 | // CHECK-NEXT: ret void |
71 | |
72 | void test3(id y) { |
73 | __weak id z; |
74 | z = y; |
75 | } |
76 | // CHECK-LABEL: define void @test3 |
77 | // CHECK: [[Y:%.*]] = alloca i8*, |
78 | // CHECK-NEXT: [[Z:%.*]] = alloca i8*, |
79 | // CHECK-NEXT: store |
80 | // CHECK-NEXT: store i8* null, i8** [[Z]] |
81 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] |
82 | // CHECK-NEXT: call i8* @llvm.objc.storeWeak(i8** [[Z]], i8* [[T0]]) |
83 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[Z]]) |
84 | // CHECK-NEXT: ret void |
85 | |
86 | void test4(__weak id *p) { |
87 | id y = *p; |
88 | } |
89 | // CHECK-LABEL: define void @test4 |
90 | // CHECK: [[P:%.*]] = alloca i8**, |
91 | // CHECK-NEXT: [[Y:%.*]] = alloca i8*, |
92 | // CHECK-NEXT: store |
93 | // CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]] |
94 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.loadWeak(i8** [[T0]]) |
95 | // CHECK-NEXT: store i8* [[T1]], i8** [[Y]] |
96 | // CHECK-NEXT: ret void |
97 | |
98 | void test5(__weak id *p) { |
99 | id y = [*p retain]; |
100 | } |
101 | // CHECK-LABEL: define void @test5 |
102 | // CHECK: [[P:%.*]] = alloca i8**, |
103 | // CHECK-NEXT: [[Y:%.*]] = alloca i8*, |
104 | // CHECK-NEXT: store |
105 | // CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]] |
106 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.loadWeakRetained(i8** [[T0]]) |
107 | // CHECK-NEXT: store i8* [[T1]], i8** [[Y]] |
108 | // CHECK-NEXT: ret void |
109 | |
110 | void test6(__weak Foo **p) { |
111 | Foo *y = [*p retain]; |
112 | } |
113 | // CHECK-LABEL: define void @test6 |
114 | // CHECK: [[P:%.*]] = alloca [[FOO:%.*]]**, |
115 | // CHECK-NEXT: [[Y:%.*]] = alloca [[FOO]]*, |
116 | // CHECK-NEXT: store |
117 | // CHECK-NEXT: [[T0:%.*]] = load [[FOO]]**, [[FOO]]*** [[P]] |
118 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[FOO]]** [[T0]] to i8** |
119 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.loadWeakRetained(i8** [[T1]]) |
120 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[FOO]]* |
121 | // CHECK-NEXT: store [[FOO]]* [[T3]], [[FOO]]** [[Y]] |
122 | // CHECK-NEXT: ret void |
123 | |
124 | extern id get_object(void); |
125 | extern void use_block(void (^)(void)); |
126 | |
127 | void test7(void) { |
128 | __weak Foo *p = get_object(); |
129 | use_block(^{ [p run ]; }); |
130 | } |
131 | // CHECK-LABEL: define void @test7 |
132 | // CHECK: [[P:%.*]] = alloca [[FOO]]*, |
133 | // CHECK: [[T0:%.*]] = call i8* @get_object() |
134 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[FOO]]* |
135 | // CHECK-NEXT: [[T2:%.*]] = bitcast [[FOO]]** [[P]] to i8** |
136 | // CHECK-NEXT: [[T3:%.*]] = bitcast [[FOO]]* [[T1]] to i8* |
137 | // CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** [[T2]], i8* [[T3]]) |
138 | // CHECK: call void @llvm.objc.copyWeak |
139 | // CHECK: call void @use_block |
140 | // CHECK: call void @llvm.objc.destroyWeak |
141 | |
142 | // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block |
143 | // CHECK: @llvm.objc.copyWeak |
144 | |
145 | // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block |
146 | // CHECK: @llvm.objc.destroyWeak |
147 | |
148 | void test8(void) { |
149 | __block __weak Foo *p = get_object(); |
150 | use_block(^{ [p run ]; }); |
151 | } |
152 | // CHECK-LABEL: define void @test8 |
153 | // CHECK: call i8* @llvm.objc.initWeak |
154 | // CHECK-NOT: call void @llvm.objc.copyWeak |
155 | // CHECK: call void @use_block |
156 | // CHECK: call void @llvm.objc.destroyWeak |
157 | |
158 | // CHECK-LABEL: define internal void @__Block_byref_object_copy |
159 | // CHECK: call void @llvm.objc.moveWeak |
160 | |
161 | // CHECK-LABEL: define internal void @__Block_byref_object_dispose |
162 | // CHECK: call void @llvm.objc.destroyWeak |
163 | |
164 | // CHECK-LABEL: define void @test9_baseline() |
165 | // CHECK: define linkonce_odr hidden void @__copy_helper |
166 | // CHECK: define linkonce_odr hidden void @__destroy_helper |
167 | void test9_baseline(void) { |
168 | Foo *p = get_object(); |
169 | use_block(^{ [p run]; }); |
170 | } |
171 | |
172 | // CHECK-LABEL: define void @test9() |
173 | // CHECK-NOT: define linkonce_odr hidden void @__copy_helper |
174 | // CHECK-NOT: define linkonce_odr hidden void @__destroy_helper |
175 | // CHECK: define void @test9_fin() |
176 | void test9(void) { |
177 | __unsafe_unretained Foo *p = get_object(); |
178 | use_block(^{ [p run]; }); |
179 | } |
180 | void test9_fin() {} |
181 | |
182 | // CHECK-LABEL: define void @test10() |
183 | // CHECK-NOT: define linkonce_odr hidden void @__copy_helper |
184 | // CHECK-NOT: define linkonce_odr hidden void @__destroy_helper |
185 | // CHECK: define void @test10_fin() |
186 | void test10(void) { |
187 | typedef __unsafe_unretained Foo *UnsafeFooPtr; |
188 | UnsafeFooPtr p = get_object(); |
189 | use_block(^{ [p run]; }); |
190 | } |
191 | void test10_fin() {} |
192 | |