701 lines · plain
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 %s2// 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 %s3// 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 %s4 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 86// 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 87// 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 88// 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 89 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 813 14// This shouldn't crash.15void test0(id (^maker)(void)) {16 maker();17}18 19int (^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 30void 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 nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 537// 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_release43// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]44// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release45// CHECK-NEXT: ret void46 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, ptr51// CHECK-NEXT: [[DST:%.*]] = load ptr, ptr52// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[SRC]], i32 0, i32 553// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]54// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]]) [[NUW]]55// CHECK-NEXT: ret void56 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, ptr60// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[T0]], i32 0, i32 561// CHECK-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]62// CHECK-NEXT: call void @llvm.objc.release(ptr [[T3]])63// CHECK-NEXT: ret void64}65 66void test3(void (^sink)(id*)) {67 __strong id strong;68 sink(&strong);69 70 // CHECK-LABEL: define{{.*}} void @test3(71 // CHECK: [[SINK:%.*]] = alloca ptr72 // CHECK-NEXT: [[STRONG:%.*]] = alloca ptr73 // CHECK-NEXT: [[TEMP:%.*]] = alloca ptr74 // CHECK-NEXT: call ptr @llvm.objc.retain(75 // CHECK-NEXT: store ptr {{%.*}}, ptr [[SINK]]76 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[STRONG]])77 // CHECK-NEXT: store ptr null, ptr [[STRONG]]78 79 // CHECK-NEXT: [[BLOCK:%.*]] = load ptr, ptr [[SINK]]80 // CHECK-NEXT: getelementptr81 // CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[STRONG]]82 // CHECK-NEXT: store ptr [[V]], ptr [[TEMP]]83 // CHECK-NEXT: [[F0:%.*]] = load ptr, ptr84 // 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(ptr [[STRONG]])95 96 // CHECK-NEXT: load ptr, ptr [[SINK]]97 // CHECK-NEXT: call void @llvm.objc.release98 // CHECK-NEXT: ret void99 100}101 102void 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 nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 2112 // 0x02000000 - has copy/dispose helpers strong113 // CHECK-NEXT: store i32 838860800, ptr [[T0]]114 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6115 // 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 nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6119 // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT120 // CHECK: store i32 -1040187392,121 // CHECK: store ptr [[VAR]], ptr122 // 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 void127 128 // CHECK-LABEL: define internal void @__Block_byref_object_copy_(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {129 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6130 // CHECK-NEXT: load ptr, ptr131 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6132 // 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 nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6138 // 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_invoke142 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw {{.*}}, i32 0, i32 6143 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align 8144 // CHECK-NEXT: store ptr null, ptr [[SLOT]],145 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])146 // CHECK-NEXT: ret void147 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 155void 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 ptr163 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],164 // CHECK-NEXT: call void @llvm.lifetime.start.p0(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_LAYOUT170 // CHECK: store i32 -1073741824, ptr171 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5172 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[VAR]]173 // CHECK-NEXT: store ptr [[T0]], ptr [[CAPTURE]]174 // CHECK: call void @test5_helper175 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VAR]])176 // CHECK-NEXT: ret void177}178 179void 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(ptr [[VAR]])189 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 2190 // 0x02000000 - has copy/dispose helpers weak191 // CHECK-NEXT: store i32 1107296256, ptr [[T0]]192 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6193 // 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 nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6198 // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT199 // CHECK: store i32 -1040187392,200 // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4201// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP9]], ptr %[[BLOCK_DESCRIPTOR]], align 8202 // CHECK: store ptr [[VAR]], ptr203 // 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(ptr [[VAR]])207 // CHECK-NEXT: ret void208 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 nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6211 // CHECK-NEXT: load ptr, ptr212 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6213 // 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 nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6217 // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[T0]])218 219 // CHECK-LABEL: define internal void @__test6_block_invoke220 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw {{.*}}, i32 0, i32 6221 // CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr [[SLOT]], ptr null)222 // CHECK-NEXT: ret void223}224 225void 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_LAYOUT240 // CHECK: store i32 -1040187392,241 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5242 // 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 void247 248 // CHECK-LABEL: define internal void @__test7_block_invoke249 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr {{%.*}}, i32 0, i32 5250 // 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 void254 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: getelementptr257 // CHECK-NEXT: getelementptr258 // 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: getelementptr262 // CHECK-NEXT: call void @llvm.objc.destroyWeak(263}264 265@interface Test8 @end266@implementation Test8267- (void) test {268// CHECK: define internal void @"\01-[Test8 test]"269// CHECK: [[SELF:%.*]] = alloca ptr,270// CHECK-NEXT: alloca ptr271// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],272// CHECK: store273// CHECK-NEXT: store274// CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5275// 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 void281 282 extern void test8_helper(void (^)(void));283 test8_helper(^{ (void) self; });284}285@end286 287id 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 getelementptr297// CHECK-NEXT: call ptr298// CHECK-NEXT: tail call ptr @llvm.objc.autoreleaseReturnValue299// CHECK-NEXT: ret ptr300 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 ptr304}305 306// Test that we correctly initialize __block variables307// when the initialization captures the variable.308void 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 8313 314 // Zero-initialization before running the initializer.315 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6316 // CHECK-NEXT: store ptr null, ptr [[T0]], align 8317 318 // Run the initializer as an assignment.319 // CHECK-HEAP: [[T1:%.*]] = call ptr @llvm.objc.retainBlock(ptr {{%.*}})320 // CHECK: [[T3:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1321 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T3]]322 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[T4]], i32 0, i32 6323 // CHECK-NEXT: [[T6:%.*]] = load ptr, ptr [[T5]], align 8324 // CHECK-HEAP-NEXT: store ptr {{%.*}}, ptr [[T5]], align 8325 // CHECK-NOHEAP-NEXT: store ptr [[BLOCK1]], ptr [[T5]], align 8326 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T6]])327 328 // Destroy at end of function.329 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6330 // 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 void334}335 336// do this copy and dispose with objc_retainBlock/release instead of337// _Block_object_assign/destroy. We can also use _Block_object_assign/destroy338// 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 nuw [[BYREF_T]], ptr [[D0]], i32 0, i32 6343// CHECK-NEXT: [[S0:%.*]] = load ptr, ptr {{%.*}}344// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[S0]], i32 0, i32 6345// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[S2]], align 8346// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[T0]])347// CHECK-NEXT: store ptr [[T2]], ptr [[D2]], align 8348// CHECK: ret void349 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 nuw [[BYREF_T]], ptr [[T0]], i32 0, i32 6353// CHECK-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]354// CHECK-NEXT: call void @llvm.objc.release(ptr [[T3]])355// CHECK-NEXT: ret void356 357// Test that we correctly assign to __block variables when the358// assignment captures the variable.359void 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 8366 367 // Zero-initialize.368 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6369 // CHECK-NEXT: store ptr null, ptr [[T0]], align 8370 371 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6372 373 // The assignment.374 // CHECK-HEAP: [[T1:%.*]] = call ptr @llvm.objc.retainBlock(ptr {{%.*}})375 // CHECK: [[T3:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1376 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T3]]377 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[T4]], i32 0, i32 6378 // CHECK-NEXT: [[T6:%.*]] = load ptr, ptr [[T5]], align 8379 // CHECK-HEAP-NEXT: store ptr {{%.*}}, ptr [[T5]], align 8380 // CHECK-NOHEAP-NEXT: store ptr [[BLOCK3]], ptr [[T5]], align 8381 // 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 void388}389 390void test11_helper(id);391void test11a(void) {392 int x;393 test11_helper(^{ (void) x; });394 395 // CHECK-LABEL: define{{.*}} void @test11a()396 // CHECK: [[X:%.*]] = alloca i32, align 4397 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8398 // 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 void402}403void test11b(void) {404 int x;405 id b = ^{ (void) x; };406 407 // CHECK-LABEL: define{{.*}} void @test11b()408 // CHECK: [[X:%.*]] = alloca i32, align 4409 // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8410 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8411 // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]])412 // CHECK-NEXT: store ptr [[T2]], ptr [[B]], align 8413 // CHECK-NEXT: [[T5:%.*]] = load ptr, ptr [[B]]414 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T5]])415 // CHECK: ret void416}417 418@interface Test12419@property (strong) void(^ablock)(void);420@property (nonatomic, strong) void(^nblock)(void);421@end422@implementation Test12423@synthesize ablock, nblock;424// CHECK: define internal ptr @"\01-[Test12 ablock]"(425// CHECK: call ptr @objc_getProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef 0, 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 0, 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 8432 433// CHECK: define internal void @"\01-[Test12 setNblock:]"(434// CHECK: call void @objc_setProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef 8, ptr noundef {{%.*}}, i1 noundef zeroext false, i1 noundef zeroext true)435@end436 437void 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 8446 // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8447 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8448 // CHECK-NEXT: [[COND_CLEANUP_SAVE:%.*]] = alloca ptr,449 // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1450 // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})451 // CHECK-NEXT: store ptr [[T0]], ptr [[X]], align 8452 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B]])453 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]], align 8454 // CHECK-NEXT: [[T1:%.*]] = icmp ne ptr [[T0]], null455 // CHECK-NEXT: store i1 false, ptr [[CLEANUP_ACTIVE]]456 // CHECK-NEXT: br i1 [[T1]],457 458 // CHECK-NOT: br459 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5460 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]], align 8461 // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])462 // CHECK-NEXT: store ptr [[T1]], ptr [[CAPTURE]], align 8463 // CHECK-NEXT: store ptr [[CAPTURE]], ptr [[COND_CLEANUP_SAVE]], align 8464 // CHECK-NEXT: store i1 true, ptr [[CLEANUP_ACTIVE]]465 // CHECK-NEXT: br label466 // CHECK: br label467 // CHECK: [[T0:%.*]] = phi ptr468 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[T0]])469 // CHECK-NEXT: store ptr [[T2]], ptr [[B]], align 8470 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]], align 8471 // 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 8478 // CHECK: [[T0:%.*]] = load ptr, ptr [[V12]]479 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])480 // CHECK-NEXT: br label481 482 // CHECK: call void @llvm.lifetime.end.p0(ptr [[B]])483 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]484 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])485 // CHECK-NEXT: ret void486}487 488void test14(void) {489 void (^const x[1])(void) = { ^{} };490}491 492// Don't make invalid ASTs and crash.493void test15_helper(void (^block)(void), int x);494void test15(int a) {495 test15_helper(^{ (void) a; }, ({ a; }));496}497 498void test16(void) {499 void (^BLKVAR)(void) = ^{ BLKVAR(); };500 501 // CHECK-LABEL: define{{.*}} void @test16(502 // CHECK: [[BLKVAR:%.*]] = alloca ptr, align 8503 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],504 // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[BLKVAR]])505 // CHECK-NEXT: store ptr null, ptr [[BLKVAR]], align 8506}507 508// This is an intentional exception to our conservative jump-scope509// checking for full-expressions containing block literals with510// non-trivial cleanups: if the block literal appears in the operand511// of a return statement, there's no need to extend its lifetime.512id (^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, align521// CHECK-NEXT: [[SELF:%.*]] = alloca ptr,522// CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align523// CHECK: [[B1:%.*]] = alloca [[BLOCK]], align524// CHECK: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr525// CHECK-NEXT: store ptr [[T0]], ptr [[SELF]], align526// CHECK-NOT: objc_retain527// CHECK-NOT: objc_release528// CHECK: [[CAPTURED:%.*]] = getelementptr inbounds nuw [[BLOCK]], ptr [[B0]], i32 0, i32 5529// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]], align530// 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 i32537// CHECK-NEXT: br label538// CHECK-NOT: objc_retain539// CHECK-NOT: objc_release540// CHECK: [[CAPTURED:%.*]] = getelementptr inbounds nuw [[BLOCK]], ptr [[B1]], i32 0, i32 5541// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]], align542// 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 i32549// CHECK-NEXT: br label550 551void 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 nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 4558// CHECK-UNOPT: store ptr @[[BLOCK_DESCRIPTOR_TMP44]], ptr %[[BLOCK_DESCRIPTOR]], align 8559// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5560// 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 void567 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 variables572// that are const-captured.573void testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(id x, id y) {574 id __unsafe_unretained unsafeObject = x;575 (^ { testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(x, unsafeObject); })();576}577 578// CHECK-LABEL: define{{.*}} void @testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers579// %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4580// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP46]], ptr %[[BLOCK_DESCRIPTOR]], align 8581 582// CHECK-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke583// CHECK-UNOPT-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke584 585void test19_sink(void (^)(int));586void 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 nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 4596// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP48]], ptr %[[BLOCK_DESCRIPTOR]], align 8597// CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5598// 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 void615}616 617// CHECK-LABEL: define{{.*}} void @test20(618// CHECK: [[XADDR:%.*]] = alloca ptr619// 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 nuw <[[BLOCKTY]]>, ptr [[BLOCK]], i32 0, i32 5623// 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 void630 631// CHECK-UNOPT-LABEL: define{{.*}} void @test20(632// CHECK-UNOPT: [[XADDR:%.*]] = alloca ptr633// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>634// CHECK-UNOPT: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds nuw <[[BLOCKTY]]>, ptr [[BLOCK]], i32 0, i32 5635// 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 640void test20_callee(void (^)(void));641void 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 649void test21_callee(int n, ...);650void test21(id x) {651 test21_callee(1, ^{ (void)x; });652}653 654// The lifetime of 'x', which is captured by the block in the statement655// expression, should be extended.656 657// CHECK-COMMON-LABEL: define{{.*}} ptr @test22(658// CHECK-COMMON: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 5659// CHECK-COMMON: %[[V3:.*]] = call ptr @llvm.objc.retain(ptr %{{.*}})660// CHECK-COMMON: store ptr %[[V3]], ptr %[[BLOCK_CAPTURED]], align 8661// 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 8664// CHECK: call void @llvm.objc.release(ptr %[[V15]])665 666id 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 Test23673-(void)m:(int)i, ...;674@end675 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 680void 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 nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4686// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP10]], ptr %[[BLOCK_DESCRIPTOR]],687 688@interface Test24689@property (class) void (^block)(void);690+(void)m;691@end692 693@implementation Test24694+(void)m {695 self.block = ^{ (void)self; };696}697@end698 699// CHECK: attributes [[NUW]] = { nounwind }700// CHECK-UNOPT: attributes [[NUW]] = { nounwind }701