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. 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 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 nuw [[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 nuw [[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 66void 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 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 2 112 // 0x02000000 - has copy/dispose helpers strong 113 // CHECK-NEXT: store i32 838860800, ptr [[T0]] 114 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6 130 // CHECK-NEXT: load ptr, ptr 131 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw {{.*}}, 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 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 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 nuw [[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 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(i64 48, ptr [[VAR]]) 189 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw [[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 nuw <{ 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 nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6 211 // CHECK-NEXT: load ptr, ptr 212 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw {{.*}}, i32 0, i32 6 221 // CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr [[SLOT]], ptr null) 222 // CHECK-NEXT: ret void 223} 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_LAYOUT 240 // CHECK: store i32 -1040187392, 241 // CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw [[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 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 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. 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 8 313 314 // Zero-initialization before running the initializer. 315 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[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 nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1 321 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T3]] 322 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw [[BYREF_T]], ptr [[D0]], i32 0, i32 6 343// CHECK-NEXT: [[S0:%.*]] = load ptr, ptr {{%.*}} 344// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds nuw [[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 nuw [[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. 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 8 366 367 // Zero-initialize. 368 // CHECK: [[T0:%.*]] = getelementptr inbounds nuw [[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 nuw [[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 nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1 376 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T3]] 377 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds nuw [[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 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 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} 403void 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 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 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 nuw [[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 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 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. 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, 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 nuw [[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 nuw [[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 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 4 558// CHECK-UNOPT: store ptr @[[BLOCK_DESCRIPTOR_TMP44]], ptr %[[BLOCK_DESCRIPTOR]], align 8 559// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds nuw [[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. 573void 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 nuw <{ 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 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 4 596// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP48]], ptr %[[BLOCK_DESCRIPTOR]], align 8 597// CHECK: [[SLOT:%.*]] = getelementptr inbounds nuw [[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 nuw <[[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 nuw <[[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 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 statement 655// 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 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 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 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 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 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