llvm-project

Форк
0
700 строк · 32.6 Кб
1
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-HEAP -check-prefix=CHECK-COMMON %s
2
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -fobjc-avoid-heapify-local-blocks -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-NOHEAP -check-prefix=CHECK-COMMON %s
3
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s
4

5
// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, i64 } { i64 0, i64 40, ptr @__copy_helper_block_8_32s, ptr @__destroy_helper_block_8_32s, ptr @{{.*}}, i64 256 }, align 8
6
// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, i64 } { i64 0, i64 40, ptr @__copy_helper_block_8_32r, ptr @__destroy_helper_block_8_32r, ptr @{{.*}}, i64 16 }, align 8
7
// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP46:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 48, ptr @__copy_helper_block_8_32s, ptr @__destroy_helper_block_8_32s, ptr @{{.*}}, ptr @{{.*}} }, align 8
8
// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP48:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, i64 } { i64 0, i64 40, ptr @__copy_helper_block_8_32b, ptr @__destroy_helper_block_8_32s, ptr @{{.*}}, i64 256 }, align 8
9

10
// Check that no copy/dispose helpers are emitted for this block.
11

12
// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP10:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr } { i64 0, i64 40, ptr @{{.*}}, ptr @{{.*}} }, align 8
13

14
// This shouldn't crash.
15
void test0(id (^maker)(void)) {
16
  maker();
17
}
18

19
int (^test1(int x))(void) {
20
  // CHECK-LABEL:    define{{.*}} ptr @test1(
21
  // CHECK:      [[X:%.*]] = alloca i32,
22
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
23
  // CHECK-NEXT: store i32 {{%.*}}, ptr [[X]]
24
  // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]]) [[NUW:#[0-9]+]]
25
  // CHECK-NEXT: [[T5:%.*]] = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr [[T2]]) [[NUW]]
26
  // CHECK-NEXT: ret ptr [[T5]]
27
  return ^{ return x; };
28
}
29

30
void test2(id x) {
31
// CHECK-LABEL:    define{{.*}} void @test2(
32
// CHECK:      [[X:%.*]] = alloca ptr,
33
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
34
// CHECK-NEXT: [[PARM:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})
35
// CHECK-NEXT: store ptr [[PARM]], ptr [[X]]
36
// CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
37
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],
38
// CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])
39
// CHECK-NEXT: store ptr [[T1]], ptr [[SLOT]],
40
// CHECK-NEXT: call void @test2_helper(
41
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]]
42
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
43
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]
44
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
45
// CHECK-NEXT: ret void
46
  extern void test2_helper(id (^)(void));
47
  test2_helper(^{ return x; });
48

49
// CHECK:    define linkonce_odr hidden void @__copy_helper_block_8_32s(ptr noundef %0, ptr noundef %1) unnamed_addr #{{[0-9]+}} {
50
// CHECK:      [[SRC:%.*]] = load ptr, ptr
51
// CHECK-NEXT: [[DST:%.*]] = load ptr, ptr
52
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[SRC]], i32 0, i32 5
53
// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]
54
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]]) [[NUW]]
55
// CHECK-NEXT: ret void
56

57

58
// CHECK:    define linkonce_odr hidden void @__destroy_helper_block_8_32s(ptr noundef %0) unnamed_addr #{{[0-9]+}} {
59
// CHECK:      [[T0:%.*]] = load ptr, ptr
60
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[T0]], i32 0, i32 5
61
// CHECK-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]
62
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T3]])
63
// CHECK-NEXT: ret void
64
}
65

66
void test3(void (^sink)(id*)) {
67
  __strong id strong;
68
  sink(&strong);
69

70
  // CHECK-LABEL:    define{{.*}} void @test3(
71
  // CHECK:      [[SINK:%.*]] = alloca ptr
72
  // CHECK-NEXT: [[STRONG:%.*]] = alloca ptr
73
  // CHECK-NEXT: [[TEMP:%.*]] = alloca ptr
74
  // CHECK-NEXT: call ptr @llvm.objc.retain(
75
  // CHECK-NEXT: store ptr {{%.*}}, ptr [[SINK]]
76
  // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[STRONG]])
77
  // CHECK-NEXT: store ptr null, ptr [[STRONG]]
78

79
  // CHECK-NEXT: [[BLOCK:%.*]] = load ptr, ptr [[SINK]]
80
  // CHECK-NEXT: getelementptr
81
  // CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[STRONG]]
82
  // CHECK-NEXT: store ptr [[V]], ptr [[TEMP]]
83
  // CHECK-NEXT: [[F0:%.*]] = load ptr, ptr
84
  // CHECK-NEXT: call void [[F0]](ptr noundef [[BLOCK]], ptr noundef [[TEMP]])
85
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[TEMP]]
86
  // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])
87
  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[V]]) [[NUW]]
88
  // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[STRONG]]
89
  // CHECK-NEXT: store ptr [[T1]], ptr [[STRONG]]
90
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T2]])
91

92
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[STRONG]]
93
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
94
  // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[STRONG]])
95

96
  // CHECK-NEXT: load ptr, ptr [[SINK]]
97
  // CHECK-NEXT: call void @llvm.objc.release
98
  // CHECK-NEXT: ret void
99

100
}
101

102
void test4(void) {
103
  id test4_source(void);
104
  void test4_helper(void (^)(void));
105
  __block id var = test4_source();
106
  test4_helper(^{ var = 0; });
107

108
  // CHECK-LABEL:    define{{.*}} void @test4()
109
  // CHECK:      [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
110
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
111
  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[VAR]], i32 0, i32 2
112
  // 0x02000000 - has copy/dispose helpers strong
113
  // CHECK-NEXT: store i32 838860800, ptr [[T0]]
114
  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[VAR]], i32 0, i32 6
115
  // CHECK-NEXT: [[T0:%.*]] = call ptr @test4_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
116
  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
117
  // CHECK-NEXT: store ptr [[T0]], ptr [[SLOT]]
118
  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[VAR]], i32 0, i32 6
119
  // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
120
  // CHECK:      store i32 -1040187392,
121
  // CHECK: store ptr [[VAR]], ptr
122
  // CHECK:      call void @test4_helper(
123
  // CHECK: call void @_Block_object_dispose(ptr [[VAR]], i32 8)
124
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]]
125
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
126
  // CHECK: ret void
127

128
  // CHECK-LABEL:    define internal void @__Block_byref_object_copy_(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {
129
  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6
130
  // CHECK-NEXT: load ptr, ptr
131
  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6
132
  // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T1]]
133
  // CHECK-NEXT: store ptr [[T2]], ptr [[T0]]
134
  // CHECK-NEXT: store ptr null, ptr [[T1]]
135

136
  // CHECK-LABEL:    define internal void @__Block_byref_object_dispose_(ptr noundef %0) #{{[0-9]+}} {
137
  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6
138
  // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]
139
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])
140

141
  // CHECK-LABEL:    define internal void @__test4_block_invoke
142
  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
143
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align 8
144
  // CHECK-NEXT: store ptr null, ptr [[SLOT]],
145
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
146
  // CHECK-NEXT: ret void
147

148
  // CHECK-LABEL:    define linkonce_odr hidden void @__copy_helper_block_8_32r(ptr noundef %0, ptr noundef %1) unnamed_addr #{{[0-9]+}} {
149
  // CHECK:      call void @_Block_object_assign(ptr {{%.*}}, ptr {{%.*}}, i32 8)
150

151
  // CHECK-LABEL:    define linkonce_odr hidden void @__destroy_helper_block_8_32r(ptr noundef %0) unnamed_addr #{{[0-9]+}} {
152
  // CHECK:      call void @_Block_object_dispose(ptr {{%.*}}, i32 8)
153
}
154

155
void test5(void) {
156
  extern id test5_source(void);
157
  void test5_helper(void (^)(void));
158
  __unsafe_unretained id var = test5_source();
159
  test5_helper(^{ (void) var; });
160

161
  // CHECK-LABEL:    define{{.*}} void @test5()
162
  // CHECK:      [[VAR:%.*]] = alloca ptr
163
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
164
  // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[VAR]])
165
  // CHECK: [[T1:%.*]] = call ptr @test5_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
166
  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])
167
  // CHECK-NEXT: store ptr [[T1]], ptr [[VAR]],
168
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])
169
  // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT
170
  // CHECK:      store i32 -1073741824, ptr
171
  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
172
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[VAR]]
173
  // CHECK-NEXT: store ptr [[T0]], ptr [[CAPTURE]]
174
  // CHECK: call void @test5_helper
175
  // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[VAR]])
176
  // CHECK-NEXT: ret void
177
}
178

179
void test6(void) {
180
  id test6_source(void);
181
  void test6_helper(void (^)(void));
182
  __block __weak id var = test6_source();
183
  test6_helper(^{ var = 0; });
184

185
  // CHECK-LABEL:    define{{.*}} void @test6()
186
  // CHECK:      [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
187
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
188
  // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 48, ptr [[VAR]])
189
  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[VAR]], i32 0, i32 2
190
  // 0x02000000 - has copy/dispose helpers weak
191
  // CHECK-NEXT: store i32 1107296256, ptr [[T0]]
192
  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[VAR]], i32 0, i32 6
193
  // CHECK-NEXT: [[T1:%.*]] = call ptr @test6_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
194
  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])
195
  // CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[SLOT]], ptr [[T1]])
196
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])
197
  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[VAR]], i32 0, i32 6
198
  // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
199
  // CHECK:      store i32 -1040187392,
200
  // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4
201
// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP9]], ptr %[[BLOCK_DESCRIPTOR]], align 8
202
  // CHECK: store ptr [[VAR]], ptr
203
  // CHECK:      call void @test6_helper(
204
  // CHECK: call void @_Block_object_dispose(ptr [[VAR]], i32 8)
205
  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[SLOT]])
206
  // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 48, ptr [[VAR]])
207
  // CHECK-NEXT: ret void
208

209
  // CHECK-LABEL:    define internal void @__Block_byref_object_copy_.{{[0-9]+}}(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {
210
  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6
211
  // CHECK-NEXT: load ptr, ptr
212
  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6
213
  // CHECK-NEXT: call void @llvm.objc.moveWeak(ptr [[T0]], ptr [[T1]])
214

215
  // CHECK-LABEL:    define internal void @__Block_byref_object_dispose_.{{[0-9]+}}(ptr noundef %0) #{{[0-9]+}} {
216
  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6
217
  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[T0]])
218

219
  // CHECK-LABEL:    define internal void @__test6_block_invoke
220
  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
221
  // CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr [[SLOT]], ptr null)
222
  // CHECK-NEXT: ret void
223
}
224

225
void test7(void) {
226
  id test7_source(void);
227
  void test7_helper(void (^)(void));
228
  void test7_consume(id);
229
  __weak id var = test7_source();
230
  test7_helper(^{ test7_consume(var); });
231

232
  // CHECK-LABEL:    define{{.*}} void @test7()
233
  // CHECK:      [[VAR:%.*]] = alloca ptr,
234
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
235
  // CHECK:      [[T1:%.*]] = call ptr @test7_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
236
  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])
237
  // CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[VAR]], ptr [[T1]])
238
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])
239
  // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
240
  // CHECK:      store i32 -1040187392,
241
  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
242
  // CHECK-NEXT: call void @llvm.objc.copyWeak(ptr [[SLOT]], ptr [[VAR]])
243
  // CHECK:      call void @test7_helper(
244
  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr {{%.*}})
245
  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[VAR]])
246
  // CHECK: ret void
247

248
  // CHECK-LABEL:    define internal void @__test7_block_invoke
249
  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr {{%.*}}, i32 0, i32 5
250
  // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.loadWeakRetained(ptr [[SLOT]])
251
  // CHECK-NEXT: call void @test7_consume(ptr noundef [[T0]])
252
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
253
  // CHECK: ret void
254

255
  // CHECK-LABEL:    define linkonce_odr hidden void @__copy_helper_block_8_32w(ptr noundef %0, ptr noundef %1) unnamed_addr #{{[0-9]+}} {
256
  // CHECK:      getelementptr
257
  // CHECK-NEXT: getelementptr
258
  // CHECK-NEXT: call void @llvm.objc.copyWeak(
259

260
  // CHECK-LABEL:    define linkonce_odr hidden void @__destroy_helper_block_8_32w(ptr noundef %0) unnamed_addr #{{[0-9]+}} {
261
  // CHECK:      getelementptr
262
  // CHECK-NEXT: call void @llvm.objc.destroyWeak(
263
}
264

265
@interface Test8 @end
266
@implementation Test8
267
- (void) test {
268
// CHECK:    define internal void @"\01-[Test8 test]"
269
// CHECK:      [[SELF:%.*]] = alloca ptr,
270
// CHECK-NEXT: alloca ptr
271
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
272
// CHECK: store
273
// CHECK-NEXT: store
274
// CHECK:      [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
275
// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]],
276
// CHECK-NEXT: store ptr [[T1]], ptr [[T0]]
277
// CHECK: call void @test8_helper(
278
// CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T0]]
279
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[T2]])
280
// CHECK: ret void
281

282
  extern void test8_helper(void (^)(void));
283
  test8_helper(^{ (void) self; });
284
}
285
@end
286

287
id test9(void) {
288
  typedef id __attribute__((ns_returns_retained)) blocktype(void);
289
  extern void test9_consume_block(blocktype^);
290
  return ^blocktype {
291
      extern id test9_produce(void);
292
      return test9_produce();
293
  }();
294

295
// CHECK-LABEL:    define{{.*}} ptr @test9(
296
// CHECK:      load ptr, ptr getelementptr
297
// CHECK-NEXT: call ptr
298
// CHECK-NEXT: tail call ptr @llvm.objc.autoreleaseReturnValue
299
// CHECK-NEXT: ret ptr
300

301
// CHECK:      call ptr @test9_produce() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
302
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(
303
// CHECK-NEXT: ret ptr
304
}
305

306
// Test that we correctly initialize __block variables
307
// when the initialization captures the variable.
308
void test10a(void) {
309
  __block void (^block)(void) = ^{ block(); };
310
  // CHECK-LABEL:       define{{.*}} void @test10a()
311
  // CHECK:             [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
312
  // CHECK-NOHEAP:      [[BLOCK1:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
313

314
  // Zero-initialization before running the initializer.
315
  // CHECK:             [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6
316
  // CHECK-NEXT:        store ptr null, ptr [[T0]], align 8
317

318
  // Run the initializer as an assignment.
319
  // CHECK-HEAP:   [[T1:%.*]] = call ptr @llvm.objc.retainBlock(ptr {{%.*}})
320
  // CHECK:        [[T3:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1
321
  // CHECK-NEXT:        [[T4:%.*]] = load ptr, ptr [[T3]]
322
  // CHECK-NEXT:        [[T5:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[T4]], i32 0, i32 6
323
  // CHECK-NEXT:        [[T6:%.*]] = load ptr, ptr [[T5]], align 8
324
  // CHECK-HEAP-NEXT:   store ptr {{%.*}}, ptr [[T5]], align 8
325
  // CHECK-NOHEAP-NEXT: store ptr [[BLOCK1]], ptr [[T5]], align 8
326
  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T6]])
327

328
  // Destroy at end of function.
329
  // CHECK-NEXT:        [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6
330
  // CHECK-NEXT:        call void @_Block_object_dispose(ptr [[BYREF]], i32 8)
331
  // CHECK-NEXT:        [[T1:%.*]] = load ptr, ptr [[SLOT]]
332
  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T1]])
333
  // CHECK: ret void
334
}
335

336
// do this copy and dispose with objc_retainBlock/release instead of
337
// _Block_object_assign/destroy. We can also use _Block_object_assign/destroy
338
// with BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER.
339

340
// CHECK-LABEL: define internal void @__Block_byref_object_copy_.{{[0-9]+}}(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {
341
// CHECK:      [[D0:%.*]] = load ptr, ptr {{%.*}}
342
// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[D0]], i32 0, i32 6
343
// CHECK-NEXT: [[S0:%.*]] = load ptr, ptr {{%.*}}
344
// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[S0]], i32 0, i32 6
345
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[S2]], align 8
346
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[T0]])
347
// CHECK-NEXT: store ptr [[T2]], ptr [[D2]], align 8
348
// CHECK: ret void
349

350
// CHECK-LABEL: define internal void @__Block_byref_object_dispose_.{{[0-9]+}}(ptr noundef %0) #{{[0-9]+}} {
351
// CHECK:      [[T0:%.*]] = load ptr, ptr {{%.*}}
352
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[T0]], i32 0, i32 6
353
// CHECK-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]
354
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T3]])
355
// CHECK-NEXT: ret void
356

357
// Test that we correctly assign to __block variables when the
358
// assignment captures the variable.
359
void test10b(void) {
360
  __block void (^block)(void);
361
  block = ^{ block(); };
362

363
  // CHECK-LABEL:       define{{.*}} void @test10b()
364
  // CHECK:             [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
365
  // CHECK-NOHEAP:      [[BLOCK3:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
366

367
  // Zero-initialize.
368
  // CHECK:             [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6
369
  // CHECK-NEXT:        store ptr null, ptr [[T0]], align 8
370

371
  // CHECK-NEXT:        [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6
372

373
  // The assignment.
374
  // CHECK-HEAP:   [[T1:%.*]] = call ptr @llvm.objc.retainBlock(ptr {{%.*}})
375
  // CHECK:        [[T3:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1
376
  // CHECK-NEXT:        [[T4:%.*]] = load ptr, ptr [[T3]]
377
  // CHECK-NEXT:        [[T5:%.*]] = getelementptr inbounds [[BYREF_T]], ptr [[T4]], i32 0, i32 6
378
  // CHECK-NEXT:        [[T6:%.*]] = load ptr, ptr [[T5]], align 8
379
  // CHECK-HEAP-NEXT:   store ptr {{%.*}}, ptr [[T5]], align 8
380
  // CHECK-NOHEAP-NEXT: store ptr [[BLOCK3]], ptr [[T5]], align 8
381
  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T6]])
382

383
  // Destroy at end of function.
384
  // CHECK-NEXT:        call void @_Block_object_dispose(ptr [[BYREF]], i32 8)
385
  // CHECK-NEXT:        [[T1:%.*]] = load ptr, ptr [[SLOT]]
386
  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T1]])
387
  // CHECK: ret void
388
}
389

390
void test11_helper(id);
391
void test11a(void) {
392
  int x;
393
  test11_helper(^{ (void) x; });
394

395
  // CHECK-LABEL:    define{{.*}} void @test11a()
396
  // CHECK:      [[X:%.*]] = alloca i32, align 4
397
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
398
  // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]])
399
  // CHECK-NEXT: call void @test11_helper(ptr noundef [[T2]])
400
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T2]])
401
  // CHECK: ret void
402
}
403
void test11b(void) {
404
  int x;
405
  id b = ^{ (void) x; };
406

407
  // CHECK-LABEL:    define{{.*}} void @test11b()
408
  // CHECK:      [[X:%.*]] = alloca i32, align 4
409
  // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8
410
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
411
  // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]])
412
  // CHECK-NEXT: store ptr [[T2]], ptr [[B]], align 8
413
  // CHECK-NEXT: [[T5:%.*]] = load ptr, ptr [[B]]
414
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T5]])
415
  // CHECK: ret void
416
}
417

418
@interface Test12
419
@property (strong) void(^ablock)(void);
420
@property (nonatomic, strong) void(^nblock)(void);
421
@end
422
@implementation Test12
423
@synthesize ablock, nblock;
424
// CHECK:    define internal ptr @"\01-[Test12 ablock]"(
425
// CHECK:    call ptr @objc_getProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef {{%.*}}, i1 noundef zeroext true)
426

427
// CHECK:    define internal void @"\01-[Test12 setAblock:]"(
428
// CHECK:    call void @objc_setProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef {{%.*}}, ptr noundef {{%.*}}, i1 noundef zeroext true, i1 noundef zeroext true)
429

430
// CHECK:    define internal ptr @"\01-[Test12 nblock]"(
431
// CHECK:    %add.ptr = getelementptr inbounds i8, ptr %0, i64 %ivar
432

433
// CHECK:    define internal void @"\01-[Test12 setNblock:]"(
434
// CHECK:    call void @objc_setProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef {{%.*}}, ptr noundef {{%.*}}, i1 noundef zeroext false, i1 noundef zeroext true)
435
@end
436

437
void test13(id x) {
438
  extern void test13_helper(id);
439
  extern void test13_use(void(^)(void));
440

441
  void (^b)(void) = (x ? ^{test13_helper(x);} : 0);
442
  test13_use(b);
443

444
  // CHECK-LABEL:    define{{.*}} void @test13(
445
  // CHECK:      [[X:%.*]] = alloca ptr, align 8
446
  // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8
447
  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
448
  // CHECK-NEXT: [[COND_CLEANUP_SAVE:%.*]] = alloca ptr,
449
  // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
450
  // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})
451
  // CHECK-NEXT: store ptr [[T0]], ptr [[X]], align 8
452
  // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[B]])
453
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]], align 8
454
  // CHECK-NEXT: [[T1:%.*]] = icmp ne ptr [[T0]], null
455
  // CHECK-NEXT: store i1 false, ptr [[CLEANUP_ACTIVE]]
456
  // CHECK-NEXT: br i1 [[T1]],
457

458
  // CHECK-NOT:  br
459
  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
460
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]], align 8
461
  // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])
462
  // CHECK-NEXT: store ptr [[T1]], ptr [[CAPTURE]], align 8
463
  // CHECK-NEXT: store ptr [[CAPTURE]], ptr [[COND_CLEANUP_SAVE]], align 8
464
  // CHECK-NEXT: store i1 true, ptr [[CLEANUP_ACTIVE]]
465
  // CHECK-NEXT: br label
466
  // CHECK:      br label
467
  // CHECK:      [[T0:%.*]] = phi ptr
468
  // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[T0]])
469
  // CHECK-NEXT: store ptr [[T2]], ptr [[B]], align 8
470
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]], align 8
471
  // CHECK-NEXT: call void @test13_use(ptr noundef [[T0]])
472
  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]]
473
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
474

475
  // CHECK-NEXT: [[T0:%.*]] = load i1, ptr [[CLEANUP_ACTIVE]]
476
  // CHECK-NEXT: br i1 [[T0]]
477
  // CHECK:      [[V12:%.*]] = load ptr, ptr [[COND_CLEANUP_SAVE]], align 8
478
  // CHECK:      [[T0:%.*]] = load ptr, ptr [[V12]]
479
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
480
  // CHECK-NEXT: br label
481

482
  // CHECK: call void @llvm.lifetime.end.p0(i64 8, ptr [[B]])
483
  // CHECK-NEXT:      [[T0:%.*]] = load ptr, ptr [[X]]
484
  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
485
  // CHECK-NEXT: ret void
486
}
487

488
void test14(void) {
489
  void (^const x[1])(void) = { ^{} };
490
}
491

492
// Don't make invalid ASTs and crash.
493
void test15_helper(void (^block)(void), int x);
494
void test15(int a) {
495
  test15_helper(^{ (void) a; }, ({ a; }));
496
}
497

498
void test16(void) {
499
  void (^BLKVAR)(void) = ^{ BLKVAR(); };
500

501
  // CHECK-LABEL: define{{.*}} void @test16(
502
  // CHECK: [[BLKVAR:%.*]]  = alloca ptr, align 8
503
  // CHECK-NEXT:  [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
504
  // CHECK-NEXT:  call void @llvm.lifetime.start.p0(i64 8, ptr [[BLKVAR]])
505
  // CHECK-NEXT:  store ptr null, ptr [[BLKVAR]], align 8
506
}
507

508
// This is an intentional exception to our conservative jump-scope
509
// checking for full-expressions containing block literals with
510
// non-trivial cleanups: if the block literal appears in the operand
511
// of a return statement, there's no need to extend its lifetime.
512
id (^test17(id self, int which))(void) {
513
  switch (which) {
514
  case 1: return ^{ return self; };
515
  case 0: return ^{ return self; };
516
  }
517
  return (void*) 0;
518
}
519
// CHECK-LABEL:    define{{.*}} ptr @test17(
520
// CHECK:      [[RET:%.*]] = alloca ptr, align
521
// CHECK-NEXT: [[SELF:%.*]] = alloca ptr,
522
// CHECK:      [[B0:%.*]] = alloca [[BLOCK:<.*>]], align
523
// CHECK:      [[B1:%.*]] = alloca [[BLOCK]], align
524
// CHECK:      [[T0:%.*]] = call ptr @llvm.objc.retain(ptr
525
// CHECK-NEXT: store ptr [[T0]], ptr [[SELF]], align
526
// CHECK-NOT:  objc_retain
527
// CHECK-NOT:  objc_release
528
// CHECK:      [[CAPTURED:%.*]] = getelementptr inbounds [[BLOCK]], ptr [[B0]], i32 0, i32 5
529
// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]], align
530
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]])
531
// CHECK-NEXT: store ptr [[T2]], ptr [[CAPTURED]],
532
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[B0]])
533
// CHECK-NEXT: store ptr [[T2]], ptr [[RET]]
534
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[CAPTURED]]
535
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
536
// CHECK-NEXT: store i32
537
// CHECK-NEXT: br label
538
// CHECK-NOT:  objc_retain
539
// CHECK-NOT:  objc_release
540
// CHECK:      [[CAPTURED:%.*]] = getelementptr inbounds [[BLOCK]], ptr [[B1]], i32 0, i32 5
541
// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]], align
542
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]])
543
// CHECK-NEXT: store ptr [[T2]], ptr [[CAPTURED]],
544
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[B1]])
545
// CHECK-NEXT: store ptr [[T2]], ptr [[RET]]
546
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[CAPTURED]]
547
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
548
// CHECK-NEXT: store i32
549
// CHECK-NEXT: br label
550

551
void test18(id x) {
552
// CHECK-UNOPT-LABEL:    define{{.*}} void @test18(
553
// CHECK-UNOPT:      [[X:%.*]] = alloca ptr,
554
// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
555
// CHECK-UNOPT-NEXT: store ptr null, ptr [[X]]
556
// CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(ptr [[X]], 
557
// CHECK-UNOPT: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 4
558
// CHECK-UNOPT: store ptr @[[BLOCK_DESCRIPTOR_TMP44]], ptr %[[BLOCK_DESCRIPTOR]], align 8
559
// CHECK-UNOPT:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
560
// CHECK-UNOPT-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],
561
// CHECK-UNOPT-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])
562
// CHECK-UNOPT-NEXT: store ptr [[T1]], ptr [[SLOT]],
563
// CHECK-UNOPT-NEXT: call void @test18_helper(
564
// CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(ptr [[SLOT]], ptr null) [[NUW:#[0-9]+]]
565
// CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(ptr [[X]], ptr null) [[NUW]]
566
// CHECK-UNOPT-NEXT: ret void
567
  extern void test18_helper(id (^)(void));
568
  test18_helper(^{ return x; });
569
}
570

571
// Ensure that we don't emit helper code in copy/dispose routines for variables
572
// that are const-captured.
573
void testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(id x, id y) {
574
  id __unsafe_unretained unsafeObject = x;
575
  (^ { testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(x, unsafeObject); })();
576
}
577

578
// CHECK-LABEL: define{{.*}} void @testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers
579
// %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4
580
// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP46]], ptr %[[BLOCK_DESCRIPTOR]], align 8
581

582
// CHECK-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
583
// CHECK-UNOPT-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
584

585
void test19_sink(void (^)(int));
586
void test19(void (^b)(void)) {
587
// CHECK-LABEL:    define{{.*}} void @test19(
588
//   Prologue.
589
// CHECK:      [[B:%.*]] = alloca ptr,
590
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
591
// CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})
592
// CHECK-NEXT: store ptr [[T1]], ptr [[B]]
593

594
//   Block setup.  We skip most of this.  Note the bare retain.
595
// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 4
596
// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP48]], ptr %[[BLOCK_DESCRIPTOR]], align 8
597
// CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5
598
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]],
599
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])
600
// CHECK-NEXT: store ptr [[T2]], ptr [[SLOT]],
601
//   Call.
602
// CHECK-NEXT: call void @test19_sink(ptr noundef [[BLOCK]])
603

604
  test19_sink(^(int x) { b(); });
605

606
//   Block teardown.
607
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]]
608
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
609

610
//   Local cleanup.
611
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]]
612
// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])
613

614
// CHECK-NEXT: ret void
615
}
616

617
// CHECK-LABEL: define{{.*}} void @test20(
618
// CHECK: [[XADDR:%.*]] = alloca ptr
619
// CHECK-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>
620
// CHECK-NEXT: [[RETAINEDX:%.*]] = call ptr @llvm.objc.retain(ptr %{{.*}})
621
// CHECK-NEXT: store ptr [[RETAINEDX]], ptr [[XADDR]]
622
// CHECK: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, ptr [[BLOCK]], i32 0, i32 5
623
// CHECK: [[CAPTURED:%.*]] = load ptr, ptr [[XADDR]]
624
// CHECK: store ptr [[CAPTURED]], ptr [[BLOCKCAPTURED]]
625
// CHECK: [[CAPTURE:%.*]] = load ptr, ptr [[BLOCKCAPTURED]]
626
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[CAPTURE]])
627
// CHECK-NEXT: [[X:%.*]] = load ptr, ptr [[XADDR]]
628
// CHECK-NEXT: call void @llvm.objc.release(ptr [[X]])
629
// CHECK-NEXT: ret void
630

631
// CHECK-UNOPT-LABEL: define{{.*}} void @test20(
632
// CHECK-UNOPT: [[XADDR:%.*]] = alloca ptr
633
// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>
634
// CHECK-UNOPT: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, ptr [[BLOCK]], i32 0, i32 5
635
// CHECK-UNOPT: [[CAPTURED:%.*]] = load ptr, ptr [[XADDR]]
636
// CHECK-UNOPT: [[RETAINED:%.*]] = call ptr @llvm.objc.retain(ptr [[CAPTURED]])
637
// CHECK-UNOPT: store ptr [[RETAINED]], ptr [[BLOCKCAPTURED]]
638
// CHECK-UNOPT: call void @llvm.objc.storeStrong(ptr [[BLOCKCAPTURED]], ptr null)
639

640
void test20_callee(void (^)(void));
641
void test20(const id x) {
642
  test20_callee(^{ (void)x; });
643
}
644

645
// CHECK-LABEL: define{{.*}} void @test21(
646
// CHECK: %[[V6:.*]] = call ptr @llvm.objc.retainBlock(
647
// CHECK: call void (i32, ...) @test21_callee(i32 noundef 1, ptr noundef %[[V6]]),
648

649
void test21_callee(int n, ...);
650
void test21(id x) {
651
  test21_callee(1, ^{ (void)x; });
652
}
653

654
// The lifetime of 'x', which is captured by the block in the statement
655
// expression, should be extended.
656

657
// CHECK-COMMON-LABEL: define{{.*}} ptr @test22(
658
// CHECK-COMMON: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 5
659
// CHECK-COMMON: %[[V3:.*]] = call ptr @llvm.objc.retain(ptr %{{.*}})
660
// CHECK-COMMON: store ptr %[[V3]], ptr %[[BLOCK_CAPTURED]], align 8
661
// CHECK-COMMON: call void @test22_1()
662
// CHECK-UNOPT: call void @llvm.objc.storeStrong(ptr %[[BLOCK_CAPTURED]], ptr null)
663
// CHECK: %[[V15:.*]] = load ptr, ptr %[[BLOCK_CAPTURED]], align 8
664
// CHECK: call void @llvm.objc.release(ptr %[[V15]])
665

666
id test22(int c, id x) {
667
  extern id test22_0(void);
668
  extern void test22_1(void);
669
  return c ? test22_0() : ({ id (^b)(void) = ^{ return x; }; test22_1(); b(); });
670
}
671

672
@interface Test23
673
-(void)m:(int)i, ...;
674
@end
675

676
// CHECK-COMMON-LABEL: define{{.*}} void @test23(
677
// CHECK-COMMON: %[[V9:.*]] = call ptr @llvm.objc.retainBlock(
678
// CHECK-COMMON: call void (ptr, ptr, i32, ...) @objc_msgSend(ptr noundef %{{.*}}, ptr noundef %{{.*}}, i32 noundef 123, ptr noundef %[[V9]])
679

680
void test23(id x, Test23 *t) {
681
  [t m:123, ^{ (void)x; }];
682
}
683

684
// CHECK-COMMON-LABEL: define internal void @"\01+[Test24 m]"(
685
// CHECK-COMMON: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4
686
// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP10]], ptr %[[BLOCK_DESCRIPTOR]],
687

688
@interface Test24
689
@property (class) void (^block)(void);
690
+(void)m;
691
@end
692

693
@implementation Test24
694
+(void)m {
695
  self.block = ^{ (void)self; };
696
}
697
@end
698

699
// CHECK: attributes [[NUW]] = { nounwind }
700
// CHECK-UNOPT: attributes [[NUW]] = { nounwind }
701

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.