1*f4a2713aSLionel Sambuc// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s 2*f4a2713aSLionel Sambuc// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT %s 3*f4a2713aSLionel Sambuc 4*f4a2713aSLionel Sambuc// This shouldn't crash. 5*f4a2713aSLionel Sambucvoid test0(id (^maker)(void)) { 6*f4a2713aSLionel Sambuc maker(); 7*f4a2713aSLionel Sambuc} 8*f4a2713aSLionel Sambuc 9*f4a2713aSLionel Sambucint (^test1(int x))(void) { 10*f4a2713aSLionel Sambuc // CHECK-LABEL: define i32 ()* @test1( 11*f4a2713aSLionel Sambuc // CHECK: [[X:%.*]] = alloca i32, 12*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 13*f4a2713aSLionel Sambuc // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]] 14*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()* 15*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8* 16*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) [[NUW:#[0-9]+]] 17*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()* 18*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8* 19*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T5:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) [[NUW]] 20*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()* 21*f4a2713aSLionel Sambuc // CHECK-NEXT: ret i32 ()* [[T6]] 22*f4a2713aSLionel Sambuc return ^{ return x; }; 23*f4a2713aSLionel Sambuc} 24*f4a2713aSLionel Sambuc 25*f4a2713aSLionel Sambucvoid test2(id x) { 26*f4a2713aSLionel Sambuc// CHECK-LABEL: define void @test2( 27*f4a2713aSLionel Sambuc// CHECK: [[X:%.*]] = alloca i8*, 28*f4a2713aSLionel Sambuc// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 29*f4a2713aSLionel Sambuc// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) 30*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* [[PARM]], i8** [[X]] 31*f4a2713aSLionel Sambuc// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 32*f4a2713aSLionel Sambuc// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 33*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], 34*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 35*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]], 36*f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast 37*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @test2_helper( 38*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]] 39*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release 40*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]] 41*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release 42*f4a2713aSLionel Sambuc// CHECK-NEXT: ret void 43*f4a2713aSLionel Sambuc extern void test2_helper(id (^)(void)); 44*f4a2713aSLionel Sambuc test2_helper(^{ return x; }); 45*f4a2713aSLionel Sambuc 46*f4a2713aSLionel Sambuc// CHECK-LABEL: define internal void @__copy_helper_block_ 47*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = load i8** 48*f4a2713aSLionel Sambuc// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* 49*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** 50*f4a2713aSLionel Sambuc// CHECK-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* 51*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5 52*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]] 53*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]] 54*f4a2713aSLionel Sambuc// CHECK-NEXT: ret void 55*f4a2713aSLionel Sambuc 56*f4a2713aSLionel Sambuc// CHECK-LABEL: define internal void @__destroy_helper_block_ 57*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = load i8** 58*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* 59*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5 60*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = load i8** [[T2]] 61*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T3]]) 62*f4a2713aSLionel Sambuc// CHECK-NEXT: ret void 63*f4a2713aSLionel Sambuc} 64*f4a2713aSLionel Sambuc 65*f4a2713aSLionel Sambucvoid test3(void (^sink)(id*)) { 66*f4a2713aSLionel Sambuc __strong id strong; 67*f4a2713aSLionel Sambuc sink(&strong); 68*f4a2713aSLionel Sambuc 69*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test3( 70*f4a2713aSLionel Sambuc // CHECK: [[SINK:%.*]] = alloca void (i8**)* 71*f4a2713aSLionel Sambuc // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* 72*f4a2713aSLionel Sambuc // CHECK-NEXT: [[TEMP:%.*]] = alloca i8* 73*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8* 74*f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_retain( 75*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast i8* 76*f4a2713aSLionel Sambuc // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]] 77*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* null, i8** [[STRONG]] 78*f4a2713aSLionel Sambuc 79*f4a2713aSLionel Sambuc // CHECK-NEXT: load void (i8**)** [[SINK]] 80*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast 81*f4a2713aSLionel Sambuc // CHECK-NEXT: getelementptr 82*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = bitcast 83*f4a2713aSLionel Sambuc // CHECK-NEXT: [[V:%.*]] = load i8** [[STRONG]] 84*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[V]], i8** [[TEMP]] 85*f4a2713aSLionel Sambuc // CHECK-NEXT: [[F0:%.*]] = load i8** 86*f4a2713aSLionel Sambuc // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)* 87*f4a2713aSLionel Sambuc // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]]) 88*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]] 89*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 90*f4a2713aSLionel Sambuc // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V]]) [[NUW]] 91*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]] 92*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]] 93*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T2]]) 94*f4a2713aSLionel Sambuc 95*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]] 96*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 97*f4a2713aSLionel Sambuc 98*f4a2713aSLionel Sambuc // CHECK-NEXT: load void (i8**)** [[SINK]] 99*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast 100*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release 101*f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 102*f4a2713aSLionel Sambuc 103*f4a2713aSLionel Sambuc} 104*f4a2713aSLionel Sambuc 105*f4a2713aSLionel Sambucvoid test4(void) { 106*f4a2713aSLionel Sambuc id test4_source(void); 107*f4a2713aSLionel Sambuc void test4_helper(void (^)(void)); 108*f4a2713aSLionel Sambuc __block id var = test4_source(); 109*f4a2713aSLionel Sambuc test4_helper(^{ var = 0; }); 110*f4a2713aSLionel Sambuc 111*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test4() 112*f4a2713aSLionel Sambuc // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], 113*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 114*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2 115*f4a2713aSLionel Sambuc // 0x02000000 - has copy/dispose helpers strong 116*f4a2713aSLionel Sambuc // CHECK-NEXT: store i32 838860800, i32* [[T0]] 117*f4a2713aSLionel Sambuc // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 118*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source() 119*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 120*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]] 121*f4a2713aSLionel Sambuc // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 122*f4a2713aSLionel Sambuc // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT 123*f4a2713aSLionel Sambuc // CHECK: store i32 -1040187392, 124*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* 125*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** 126*f4a2713aSLionel Sambuc // CHECK: call void @test4_helper( 127*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* 128*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) 129*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]] 130*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 131*f4a2713aSLionel Sambuc // CHECK: ret void 132*f4a2713aSLionel Sambuc 133*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__Block_byref_object_copy_ 134*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 135*f4a2713aSLionel Sambuc // CHECK-NEXT: load i8** 136*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* 137*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 138*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]] 139*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T2]], i8** [[T0]] 140*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* null, i8** [[T1]] 141*f4a2713aSLionel Sambuc 142*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__Block_byref_object_dispose_ 143*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 144*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]] 145*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 146*f4a2713aSLionel Sambuc 147*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__test4_block_invoke 148*f4a2713aSLionel Sambuc // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 149*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8 150*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* null, i8** [[SLOT]], 151*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 152*f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 153*f4a2713aSLionel Sambuc 154*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__copy_helper_block_ 155*f4a2713aSLionel Sambuc // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) 156*f4a2713aSLionel Sambuc 157*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__destroy_helper_block_ 158*f4a2713aSLionel Sambuc // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) 159*f4a2713aSLionel Sambuc} 160*f4a2713aSLionel Sambuc 161*f4a2713aSLionel Sambucvoid test5(void) { 162*f4a2713aSLionel Sambuc extern id test5_source(void); 163*f4a2713aSLionel Sambuc void test5_helper(void (^)(void)); 164*f4a2713aSLionel Sambuc __unsafe_unretained id var = test5_source(); 165*f4a2713aSLionel Sambuc test5_helper(^{ (void) var; }); 166*f4a2713aSLionel Sambuc 167*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test5() 168*f4a2713aSLionel Sambuc // CHECK: [[VAR:%.*]] = alloca i8* 169*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 170*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = call i8* @test5_source() 171*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 172*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]], 173*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 174*f4a2713aSLionel Sambuc // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT 175*f4a2713aSLionel Sambuc // CHECK: store i32 -1073741824, i32* 176*f4a2713aSLionel Sambuc // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 177*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]] 178*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]] 179*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to 180*f4a2713aSLionel Sambuc // CHECK: call void @test5_helper 181*f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 182*f4a2713aSLionel Sambuc} 183*f4a2713aSLionel Sambuc 184*f4a2713aSLionel Sambucvoid test6(void) { 185*f4a2713aSLionel Sambuc id test6_source(void); 186*f4a2713aSLionel Sambuc void test6_helper(void (^)(void)); 187*f4a2713aSLionel Sambuc __block __weak id var = test6_source(); 188*f4a2713aSLionel Sambuc test6_helper(^{ var = 0; }); 189*f4a2713aSLionel Sambuc 190*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test6() 191*f4a2713aSLionel Sambuc // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], 192*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 193*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2 194*f4a2713aSLionel Sambuc // 0x02000000 - has copy/dispose helpers weak 195*f4a2713aSLionel Sambuc // CHECK-NEXT: store i32 1107296256, i32* [[T0]] 196*f4a2713aSLionel Sambuc // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 197*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source() 198*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 199*f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]]) 200*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 201*f4a2713aSLionel Sambuc // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 202*f4a2713aSLionel Sambuc // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT 203*f4a2713aSLionel Sambuc // CHECK: store i32 -1040187392, 204*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* 205*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** 206*f4a2713aSLionel Sambuc // CHECK: call void @test6_helper( 207*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* 208*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) 209*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]]) 210*f4a2713aSLionel Sambuc // CHECK: ret void 211*f4a2713aSLionel Sambuc 212*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__Block_byref_object_copy_ 213*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 214*f4a2713aSLionel Sambuc // CHECK-NEXT: load i8** 215*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* 216*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 217*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]]) 218*f4a2713aSLionel Sambuc 219*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__Block_byref_object_dispose_ 220*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 221*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) 222*f4a2713aSLionel Sambuc 223*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__test6_block_invoke 224*f4a2713aSLionel Sambuc // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 225*f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null) 226*f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 227*f4a2713aSLionel Sambuc 228*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__copy_helper_block_ 229*f4a2713aSLionel Sambuc // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control) 230*f4a2713aSLionel Sambuc // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) 231*f4a2713aSLionel Sambuc 232*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__destroy_helper_block_ 233*f4a2713aSLionel Sambuc // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control) 234*f4a2713aSLionel Sambuc // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) 235*f4a2713aSLionel Sambuc} 236*f4a2713aSLionel Sambuc 237*f4a2713aSLionel Sambucvoid test7(void) { 238*f4a2713aSLionel Sambuc id test7_source(void); 239*f4a2713aSLionel Sambuc void test7_helper(void (^)(void)); 240*f4a2713aSLionel Sambuc void test7_consume(id); 241*f4a2713aSLionel Sambuc __weak id var = test7_source(); 242*f4a2713aSLionel Sambuc test7_helper(^{ test7_consume(var); }); 243*f4a2713aSLionel Sambuc 244*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test7() 245*f4a2713aSLionel Sambuc // CHECK: [[VAR:%.*]] = alloca i8*, 246*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 247*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = call i8* @test7_source() 248*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 249*f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]]) 250*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 251*f4a2713aSLionel Sambuc // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT 252*f4a2713aSLionel Sambuc // CHECK: store i32 -1040187392, 253*f4a2713aSLionel Sambuc // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 254*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[VAR]]) 255*f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]]) 256*f4a2713aSLionel Sambuc // CHECK: call void @test7_helper( 257*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}}) 258*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]]) 259*f4a2713aSLionel Sambuc // CHECK: ret void 260*f4a2713aSLionel Sambuc 261*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__test7_block_invoke 262*f4a2713aSLionel Sambuc // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5 263*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[SLOT]]) 264*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @test7_consume(i8* [[T0]]) 265*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 266*f4a2713aSLionel Sambuc // CHECK: ret void 267*f4a2713aSLionel Sambuc 268*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__copy_helper_block_ 269*f4a2713aSLionel Sambuc // CHECK: getelementptr 270*f4a2713aSLionel Sambuc // CHECK-NEXT: getelementptr 271*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_copyWeak( 272*f4a2713aSLionel Sambuc 273*f4a2713aSLionel Sambuc // CHECK-LABEL: define internal void @__destroy_helper_block_ 274*f4a2713aSLionel Sambuc // CHECK: getelementptr 275*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_destroyWeak( 276*f4a2713aSLionel Sambuc} 277*f4a2713aSLionel Sambuc 278*f4a2713aSLionel Sambuc@interface Test8 @end 279*f4a2713aSLionel Sambuc@implementation Test8 280*f4a2713aSLionel Sambuc- (void) test { 281*f4a2713aSLionel Sambuc// CHECK: define internal void @"\01-[Test8 test]" 282*f4a2713aSLionel Sambuc// CHECK: [[SELF:%.*]] = alloca [[TEST8:%.*]]*, 283*f4a2713aSLionel Sambuc// CHECK-NEXT: alloca i8* 284*f4a2713aSLionel Sambuc// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 285*f4a2713aSLionel Sambuc// CHECK: store 286*f4a2713aSLionel Sambuc// CHECK-NEXT: store 287*f4a2713aSLionel Sambuc// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 288*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 289*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[SELF]], 290*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* 291*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) 292*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]* 293*f4a2713aSLionel Sambuc// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]] 294*f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to 295*f4a2713aSLionel Sambuc// CHECK: call void @test8_helper( 296*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]] 297*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* 298*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T2]]) 299*f4a2713aSLionel Sambuc// CHECK: ret void 300*f4a2713aSLionel Sambuc 301*f4a2713aSLionel Sambuc extern void test8_helper(void (^)(void)); 302*f4a2713aSLionel Sambuc test8_helper(^{ (void) self; }); 303*f4a2713aSLionel Sambuc} 304*f4a2713aSLionel Sambuc@end 305*f4a2713aSLionel Sambuc 306*f4a2713aSLionel Sambucid test9(void) { 307*f4a2713aSLionel Sambuc typedef id __attribute__((ns_returns_retained)) blocktype(void); 308*f4a2713aSLionel Sambuc extern void test9_consume_block(blocktype^); 309*f4a2713aSLionel Sambuc return ^blocktype { 310*f4a2713aSLionel Sambuc extern id test9_produce(void); 311*f4a2713aSLionel Sambuc return test9_produce(); 312*f4a2713aSLionel Sambuc }(); 313*f4a2713aSLionel Sambuc 314*f4a2713aSLionel Sambuc// CHECK-LABEL: define i8* @test9( 315*f4a2713aSLionel Sambuc// CHECK: load i8** getelementptr 316*f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast i8* 317*f4a2713aSLionel Sambuc// CHECK-NEXT: call i8* 318*f4a2713aSLionel Sambuc// CHECK-NEXT: tail call i8* @objc_autoreleaseReturnValue 319*f4a2713aSLionel Sambuc// CHECK-NEXT: ret i8* 320*f4a2713aSLionel Sambuc 321*f4a2713aSLionel Sambuc// CHECK: call i8* @test9_produce() 322*f4a2713aSLionel Sambuc// CHECK-NEXT: call i8* @objc_retain 323*f4a2713aSLionel Sambuc// CHECK-NEXT: ret i8* 324*f4a2713aSLionel Sambuc} 325*f4a2713aSLionel Sambuc 326*f4a2713aSLionel Sambuc// rdar://problem/9814099 327*f4a2713aSLionel Sambuc// Test that we correctly initialize __block variables 328*f4a2713aSLionel Sambuc// when the initialization captures the variable. 329*f4a2713aSLionel Sambucvoid test10a(void) { 330*f4a2713aSLionel Sambuc __block void (^block)(void) = ^{ block(); }; 331*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test10a() 332*f4a2713aSLionel Sambuc // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], 333*f4a2713aSLionel Sambuc 334*f4a2713aSLionel Sambuc // Zero-initialization before running the initializer. 335*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 336*f4a2713aSLionel Sambuc // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 337*f4a2713aSLionel Sambuc 338*f4a2713aSLionel Sambuc // Run the initializer as an assignment. 339*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* 340*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]]) 341*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* 342*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1 343*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]] 344*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6 345*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8 346*f4a2713aSLionel Sambuc // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 347*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* 348*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T7]]) 349*f4a2713aSLionel Sambuc 350*f4a2713aSLionel Sambuc // Destroy at end of function. 351*f4a2713aSLionel Sambuc // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 352*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* 353*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) 354*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]] 355*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* 356*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T2]]) 357*f4a2713aSLionel Sambuc // CHECK: ret void 358*f4a2713aSLionel Sambuc} 359*f4a2713aSLionel Sambuc 360*f4a2713aSLionel Sambuc// <rdar://problem/10402698>: do this copy and dispose with 361*f4a2713aSLionel Sambuc// objc_retainBlock/release instead of _Block_object_assign/destroy. 362*f4a2713aSLionel Sambuc// We can also use _Block_object_assign/destroy with 363*f4a2713aSLionel Sambuc// BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER. 364*f4a2713aSLionel Sambuc 365*f4a2713aSLionel Sambuc// CHECK-LABEL: define internal void @__Block_byref_object_copy 366*f4a2713aSLionel Sambuc// CHECK: [[D0:%.*]] = load i8** {{%.*}} 367*f4a2713aSLionel Sambuc// CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]* 368*f4a2713aSLionel Sambuc// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[D1]], i32 0, i32 6 369*f4a2713aSLionel Sambuc// CHECK-NEXT: [[S0:%.*]] = load i8** {{%.*}} 370*f4a2713aSLionel Sambuc// CHECK-NEXT: [[S1:%.*]] = bitcast i8* [[S0]] to [[BYREF_T]]* 371*f4a2713aSLionel Sambuc// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[S1]], i32 0, i32 6 372*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load void ()** [[S2]], align 8 373*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 374*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) 375*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* 376*f4a2713aSLionel Sambuc// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8 377*f4a2713aSLionel Sambuc// CHECK: ret void 378*f4a2713aSLionel Sambuc 379*f4a2713aSLionel Sambuc// CHECK-LABEL: define internal void @__Block_byref_object_dispose 380*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = load i8** {{%.*}} 381*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]* 382*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6 383*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]] 384*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* 385*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T4]]) 386*f4a2713aSLionel Sambuc// CHECK-NEXT: ret void 387*f4a2713aSLionel Sambuc 388*f4a2713aSLionel Sambuc// Test that we correctly assign to __block variables when the 389*f4a2713aSLionel Sambuc// assignment captures the variable. 390*f4a2713aSLionel Sambucvoid test10b(void) { 391*f4a2713aSLionel Sambuc __block void (^block)(void); 392*f4a2713aSLionel Sambuc block = ^{ block(); }; 393*f4a2713aSLionel Sambuc 394*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test10b() 395*f4a2713aSLionel Sambuc // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], 396*f4a2713aSLionel Sambuc 397*f4a2713aSLionel Sambuc // Zero-initialize. 398*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 399*f4a2713aSLionel Sambuc // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 400*f4a2713aSLionel Sambuc 401*f4a2713aSLionel Sambuc // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 402*f4a2713aSLionel Sambuc 403*f4a2713aSLionel Sambuc // The assignment. 404*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* 405*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]]) 406*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* 407*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1 408*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]] 409*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6 410*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8 411*f4a2713aSLionel Sambuc // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 412*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* 413*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T7]]) 414*f4a2713aSLionel Sambuc 415*f4a2713aSLionel Sambuc // Destroy at end of function. 416*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* 417*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) 418*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]] 419*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* 420*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T2]]) 421*f4a2713aSLionel Sambuc // CHECK: ret void 422*f4a2713aSLionel Sambuc} 423*f4a2713aSLionel Sambuc 424*f4a2713aSLionel Sambuc// rdar://problem/10088932 425*f4a2713aSLionel Sambucvoid test11_helper(id); 426*f4a2713aSLionel Sambucvoid test11a(void) { 427*f4a2713aSLionel Sambuc int x; 428*f4a2713aSLionel Sambuc test11_helper(^{ (void) x; }); 429*f4a2713aSLionel Sambuc 430*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test11a() 431*f4a2713aSLionel Sambuc // CHECK: [[X:%.*]] = alloca i32, align 4 432*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 433*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* 434*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 435*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) 436*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* 437*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* 438*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @test11_helper(i8* [[T4]]) 439*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8* 440*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T5]]) 441*f4a2713aSLionel Sambuc // CHECK: ret void 442*f4a2713aSLionel Sambuc} 443*f4a2713aSLionel Sambucvoid test11b(void) { 444*f4a2713aSLionel Sambuc int x; 445*f4a2713aSLionel Sambuc id b = ^{ (void) x; }; 446*f4a2713aSLionel Sambuc 447*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test11b() 448*f4a2713aSLionel Sambuc // CHECK: [[X:%.*]] = alloca i32, align 4 449*f4a2713aSLionel Sambuc // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8 450*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 451*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* 452*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 453*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) 454*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* 455*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* 456*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8 457*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]] 458*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T5]]) 459*f4a2713aSLionel Sambuc // CHECK: ret void 460*f4a2713aSLionel Sambuc} 461*f4a2713aSLionel Sambuc 462*f4a2713aSLionel Sambuc// rdar://problem/9979150 463*f4a2713aSLionel Sambuc@interface Test12 464*f4a2713aSLionel Sambuc@property (strong) void(^ablock)(void); 465*f4a2713aSLionel Sambuc@property (nonatomic, strong) void(^nblock)(void); 466*f4a2713aSLionel Sambuc@end 467*f4a2713aSLionel Sambuc@implementation Test12 468*f4a2713aSLionel Sambuc@synthesize ablock, nblock; 469*f4a2713aSLionel Sambuc// CHECK: define internal void ()* @"\01-[Test12 ablock]"( 470*f4a2713aSLionel Sambuc// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true) 471*f4a2713aSLionel Sambuc 472*f4a2713aSLionel Sambuc// CHECK: define internal void @"\01-[Test12 setAblock:]"( 473*f4a2713aSLionel Sambuc// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true) 474*f4a2713aSLionel Sambuc 475*f4a2713aSLionel Sambuc// CHECK: define internal void ()* @"\01-[Test12 nblock]"( 476*f4a2713aSLionel Sambuc// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false) 477*f4a2713aSLionel Sambuc 478*f4a2713aSLionel Sambuc// CHECK: define internal void @"\01-[Test12 setNblock:]"( 479*f4a2713aSLionel Sambuc// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true) 480*f4a2713aSLionel Sambuc@end 481*f4a2713aSLionel Sambuc 482*f4a2713aSLionel Sambuc// rdar://problem/10131784 483*f4a2713aSLionel Sambucvoid test13(id x) { 484*f4a2713aSLionel Sambuc extern void test13_helper(id); 485*f4a2713aSLionel Sambuc extern void test13_use(void(^)(void)); 486*f4a2713aSLionel Sambuc 487*f4a2713aSLionel Sambuc void (^b)(void) = (x ? ^{test13_helper(x);} : 0); 488*f4a2713aSLionel Sambuc test13_use(b); 489*f4a2713aSLionel Sambuc 490*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test13( 491*f4a2713aSLionel Sambuc // CHECK: [[X:%.*]] = alloca i8*, align 8 492*f4a2713aSLionel Sambuc // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 493*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8 494*f4a2713aSLionel Sambuc // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1 495*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) 496*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8 497*f4a2713aSLionel Sambuc // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 498*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8 499*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null 500*f4a2713aSLionel Sambuc // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]] 501*f4a2713aSLionel Sambuc // CHECK-NEXT: br i1 [[T1]], 502*f4a2713aSLionel Sambuc 503*f4a2713aSLionel Sambuc // CHECK-NOT: br 504*f4a2713aSLionel Sambuc // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 505*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8 506*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 507*f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T1]], i8** [[CAPTURE]], align 8 508*f4a2713aSLionel Sambuc // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]] 509*f4a2713aSLionel Sambuc // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* 510*f4a2713aSLionel Sambuc // CHECK-NEXT: br label 511*f4a2713aSLionel Sambuc // CHECK: br label 512*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = phi void ()* 513*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 514*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) 515*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* 516*f4a2713aSLionel Sambuc // CHECK-NEXT: store void ()* [[T3]], void ()** [[B]], align 8 517*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]], align 8 518*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @test13_use(void ()* [[T0]]) 519*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]] 520*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 521*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 522*f4a2713aSLionel Sambuc 523*f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]] 524*f4a2713aSLionel Sambuc // CHECK-NEXT: br i1 [[T0]] 525*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_ADDR]] 526*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 527*f4a2713aSLionel Sambuc // CHECK-NEXT: br label 528*f4a2713aSLionel Sambuc 529*f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = load i8** [[X]] 530*f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 531*f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 532*f4a2713aSLionel Sambuc} 533*f4a2713aSLionel Sambuc 534*f4a2713aSLionel Sambuc// <rdar://problem/10907510> 535*f4a2713aSLionel Sambucvoid test14() { 536*f4a2713aSLionel Sambuc void (^const x[1])(void) = { ^{} }; 537*f4a2713aSLionel Sambuc} 538*f4a2713aSLionel Sambuc 539*f4a2713aSLionel Sambuc// rdar://11149025 540*f4a2713aSLionel Sambuc// Don't make invalid ASTs and crash. 541*f4a2713aSLionel Sambucvoid test15_helper(void (^block)(void), int x); 542*f4a2713aSLionel Sambucvoid test15(int a) { 543*f4a2713aSLionel Sambuc test15_helper(^{ (void) a; }, ({ a; })); 544*f4a2713aSLionel Sambuc} 545*f4a2713aSLionel Sambuc 546*f4a2713aSLionel Sambuc// rdar://11016025 547*f4a2713aSLionel Sambucvoid test16() { 548*f4a2713aSLionel Sambuc void (^BLKVAR)(void) = ^{ BLKVAR(); }; 549*f4a2713aSLionel Sambuc 550*f4a2713aSLionel Sambuc // CHECK-LABEL: define void @test16( 551*f4a2713aSLionel Sambuc // CHECK: [[BLKVAR:%.*]] = alloca void ()*, align 8 552*f4a2713aSLionel Sambuc // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 553*f4a2713aSLionel Sambuc // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 554*f4a2713aSLionel Sambuc // CHECK-NEXT: store void ()* null, void ()** [[BLKVAR]], align 8 555*f4a2713aSLionel Sambuc} 556*f4a2713aSLionel Sambuc 557*f4a2713aSLionel Sambuc// rdar://12151005 558*f4a2713aSLionel Sambuc// 559*f4a2713aSLionel Sambuc// This is an intentional exception to our conservative jump-scope 560*f4a2713aSLionel Sambuc// checking for full-expressions containing block literals with 561*f4a2713aSLionel Sambuc// non-trivial cleanups: if the block literal appears in the operand 562*f4a2713aSLionel Sambuc// of a return statement, there's no need to extend its lifetime. 563*f4a2713aSLionel Sambucid (^test17(id self, int which))(void) { 564*f4a2713aSLionel Sambuc switch (which) { 565*f4a2713aSLionel Sambuc case 1: return ^{ return self; }; 566*f4a2713aSLionel Sambuc case 0: return ^{ return self; }; 567*f4a2713aSLionel Sambuc } 568*f4a2713aSLionel Sambuc return (void*) 0; 569*f4a2713aSLionel Sambuc} 570*f4a2713aSLionel Sambuc// CHECK-LABEL: define i8* ()* @test17( 571*f4a2713aSLionel Sambuc// CHECK: [[RET:%.*]] = alloca i8* ()*, align 572*f4a2713aSLionel Sambuc// CHECK-NEXT: [[SELF:%.*]] = alloca i8*, 573*f4a2713aSLionel Sambuc// CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align 574*f4a2713aSLionel Sambuc// CHECK: [[B1:%.*]] = alloca [[BLOCK]], align 575*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = call i8* @objc_retain(i8* 576*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* [[T0]], i8** [[SELF]], align 577*f4a2713aSLionel Sambuc// CHECK-NOT: objc_retain 578*f4a2713aSLionel Sambuc// CHECK-NOT: objc_release 579*f4a2713aSLionel Sambuc// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5 580*f4a2713aSLionel Sambuc// CHECK-NOT: objc_retain 581*f4a2713aSLionel Sambuc// CHECK-NOT: objc_release 582*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5 583*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align 584*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) 585*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* [[T2]], i8** [[T0]], 586*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B0]] to i8* ()* 587*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8* 588*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) 589*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()* 590*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]] 591*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]] 592*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T0]]) 593*f4a2713aSLionel Sambuc// CHECK-NEXT: store i32 594*f4a2713aSLionel Sambuc// CHECK-NEXT: br label 595*f4a2713aSLionel Sambuc// CHECK-NOT: objc_retain 596*f4a2713aSLionel Sambuc// CHECK-NOT: objc_release 597*f4a2713aSLionel Sambuc// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5 598*f4a2713aSLionel Sambuc// CHECK-NOT: objc_retain 599*f4a2713aSLionel Sambuc// CHECK-NOT: objc_release 600*f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5 601*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align 602*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) 603*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* [[T2]], i8** [[T0]], 604*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B1]] to i8* ()* 605*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8* 606*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) 607*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()* 608*f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]] 609*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]] 610*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T0]]) 611*f4a2713aSLionel Sambuc// CHECK-NEXT: store i32 612*f4a2713aSLionel Sambuc// CHECK-NEXT: br label 613*f4a2713aSLionel Sambuc 614*f4a2713aSLionel Sambucvoid test18(id x) { 615*f4a2713aSLionel Sambuc// CHECK-UNOPT-LABEL: define void @test18( 616*f4a2713aSLionel Sambuc// CHECK-UNOPT: [[X:%.*]] = alloca i8*, 617*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 618*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: store i8* null, i8** [[X]] 619*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], 620*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 621*f4a2713aSLionel Sambuc// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 622*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** [[X]], 623*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 624*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: store i8* [[T1]], i8** [[SLOT]], 625*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: bitcast 626*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: call void @test18_helper( 627*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[SLOTREL]], i8* null) [[NUW:#[0-9]+]] 628*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) [[NUW]] 629*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: ret void 630*f4a2713aSLionel Sambuc extern void test18_helper(id (^)(void)); 631*f4a2713aSLionel Sambuc test18_helper(^{ return x; }); 632*f4a2713aSLionel Sambuc 633*f4a2713aSLionel Sambuc// CHECK-UNOPT-LABEL: define internal void @__copy_helper_block_ 634*f4a2713aSLionel Sambuc// CHECK-UNOPT: [[T0:%.*]] = load i8** 635*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* 636*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** 637*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* 638*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5 639*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T1:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[DST]], i32 0, i32 5 640*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T2:%.*]] = load i8** [[T0]] 641*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: store i8* null, i8** [[T1]] 642*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) [[NUW]] 643*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: ret void 644*f4a2713aSLionel Sambuc 645*f4a2713aSLionel Sambuc// CHECK-UNOPT-LABEL: define internal void @__destroy_helper_block_ 646*f4a2713aSLionel Sambuc// CHECK-UNOPT: [[T0:%.*]] = load i8** 647*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* 648*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5 649*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) 650*f4a2713aSLionel Sambuc// CHECK-UNOPT-NEXT: ret void 651*f4a2713aSLionel Sambuc} 652*f4a2713aSLionel Sambuc 653*f4a2713aSLionel Sambuc// rdar://13588325 654*f4a2713aSLionel Sambucvoid test19_sink(void (^)(int)); 655*f4a2713aSLionel Sambucvoid test19(void (^b)(void)) { 656*f4a2713aSLionel Sambuc// CHECK-LABEL: define void @test19( 657*f4a2713aSLionel Sambuc// Prologue. 658*f4a2713aSLionel Sambuc// CHECK: [[B:%.*]] = alloca void ()*, 659*f4a2713aSLionel Sambuc// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], 660*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* 661*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 662*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* 663*f4a2713aSLionel Sambuc// CHECK-NEXT: store void ()* [[T2]], void ()** [[B]] 664*f4a2713aSLionel Sambuc 665*f4a2713aSLionel Sambuc// Block setup. We skip most of this. Note the bare retain. 666*f4a2713aSLionel Sambuc// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 667*f4a2713aSLionel Sambuc// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 668*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]], 669*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 670*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) 671*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* 672*f4a2713aSLionel Sambuc// CHECK-NEXT: store void ()* [[T3]], void ()** [[SLOT]], 673*f4a2713aSLionel Sambuc// Call. 674*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void (i32)* 675*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @test19_sink(void (i32)* [[T0]]) 676*f4a2713aSLionel Sambuc 677*f4a2713aSLionel Sambuc test19_sink(^(int x) { b(); }); 678*f4a2713aSLionel Sambuc 679*f4a2713aSLionel Sambuc// Block teardown. 680*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load void ()** [[SLOTREL]] 681*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 682*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T1]]) 683*f4a2713aSLionel Sambuc 684*f4a2713aSLionel Sambuc// Local cleanup. 685*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]] 686*f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* 687*f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T1]]) 688*f4a2713aSLionel Sambuc 689*f4a2713aSLionel Sambuc// CHECK-NEXT: ret void 690*f4a2713aSLionel Sambuc} 691*f4a2713aSLionel Sambuc 692*f4a2713aSLionel Sambuc// CHECK: attributes [[NUW]] = { nounwind } 693*f4a2713aSLionel Sambuc// CHECK-UNOPT: attributes [[NUW]] = { nounwind } 694