1*67e74705SXin Li// 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*67e74705SXin Li 3*67e74705SXin Livoid test0(_Bool cond) { 4*67e74705SXin Li id test0_helper(void) __attribute__((ns_returns_retained)); 5*67e74705SXin Li 6*67e74705SXin Li // CHECK-LABEL: define void @test0( 7*67e74705SXin Li // CHECK: [[COND:%.*]] = alloca i8, 8*67e74705SXin Li // CHECK-NEXT: [[X:%.*]] = alloca i8*, 9*67e74705SXin Li // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8* 10*67e74705SXin Li // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1 11*67e74705SXin Li // CHECK-NEXT: zext 12*67e74705SXin Li // CHECK-NEXT: store 13*67e74705SXin Li // CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8* 14*67e74705SXin Li // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]]) 15*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = load i8, i8* [[COND]] 16*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1 17*67e74705SXin Li // CHECK-NEXT: store i1 false, i1* [[RELCOND]] 18*67e74705SXin Li // CHECK-NEXT: br i1 [[T1]], 19*67e74705SXin Li // CHECK: br label 20*67e74705SXin Li // CHECK: [[CALL:%.*]] = call i8* @test0_helper() 21*67e74705SXin Li // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]] 22*67e74705SXin Li // CHECK-NEXT: store i1 true, i1* [[RELCOND]] 23*67e74705SXin Li // CHECK-NEXT: br label 24*67e74705SXin Li // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ] 25*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW:#[0-9]+]] 26*67e74705SXin Li // CHECK-NEXT: store i8* [[T1]], i8** [[X]], 27*67e74705SXin Li // CHECK-NEXT: [[REL:%.*]] = load i1, i1* [[RELCOND]] 28*67e74705SXin Li // CHECK-NEXT: br i1 [[REL]], 29*67e74705SXin Li // CHECK: [[T0:%.*]] = load i8*, i8** [[RELVAL]] 30*67e74705SXin Li // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]] 31*67e74705SXin Li // CHECK-NEXT: br label 32*67e74705SXin Li // CHECK: [[T0:%.*]] = load i8*, i8** [[X]] 33*67e74705SXin Li // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]] 34*67e74705SXin Li // CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8* 35*67e74705SXin Li // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]]) 36*67e74705SXin Li // CHECK-NEXT: ret void 37*67e74705SXin Li id x = (cond ? 0 : test0_helper()); 38*67e74705SXin Li} 39*67e74705SXin Li 40*67e74705SXin Livoid test1(int cond) { 41*67e74705SXin Li __strong id strong; 42*67e74705SXin Li __weak id weak; 43*67e74705SXin Li extern void test1_sink(id *); 44*67e74705SXin Li test1_sink(cond ? &strong : 0); 45*67e74705SXin Li test1_sink(cond ? &weak : 0); 46*67e74705SXin Li 47*67e74705SXin Li // CHECK-LABEL: define void @test1( 48*67e74705SXin Li // CHECK: [[COND:%.*]] = alloca i32 49*67e74705SXin Li // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* 50*67e74705SXin Li // CHECK-NEXT: [[WEAK:%.*]] = alloca i8* 51*67e74705SXin Li // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8* 52*67e74705SXin Li // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8* 53*67e74705SXin Li // CHECK-NEXT: [[CONDCLEANUPSAVE:%.*]] = alloca i8* 54*67e74705SXin Li // CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1 55*67e74705SXin Li // CHECK-NEXT: store i32 56*67e74705SXin Li // CHECK-NEXT: [[STRONGPTR1:%.*]] = bitcast i8** [[STRONG]] to i8* 57*67e74705SXin Li // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[STRONGPTR1]]) 58*67e74705SXin Li // CHECK-NEXT: store i8* null, i8** [[STRONG]] 59*67e74705SXin Li // CHECK-NEXT: [[WEAKPTR1:%.*]] = bitcast i8** [[WEAK]] to i8* 60*67e74705SXin Li // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[WEAKPTR1]]) 61*67e74705SXin Li // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null) 62*67e74705SXin Li 63*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[COND]] 64*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 65*67e74705SXin Li // CHECK: [[ARG:%.*]] = phi i8** 66*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 67*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]] 68*67e74705SXin Li // CHECK-NEXT: br i1 [[T0]], 69*67e74705SXin Li // CHECK: [[T0:%.*]] = load i8*, i8** [[ARG]] 70*67e74705SXin Li // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]] 71*67e74705SXin Li // CHECK-NEXT: br label 72*67e74705SXin Li // CHECK: [[W:%.*]] = phi i8* [ [[T0]], {{%.*}} ], [ undef, {{%.*}} ] 73*67e74705SXin Li // CHECK-NEXT: call void @test1_sink(i8** [[T1]]) 74*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 75*67e74705SXin Li // CHECK-NEXT: br i1 [[T0]], 76*67e74705SXin Li // CHECK: [[T0:%.*]] = load i8*, i8** [[TEMP1]] 77*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 78*67e74705SXin Li // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[W]]) [[NUW]] 79*67e74705SXin Li // CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[ARG]] 80*67e74705SXin Li // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]] 81*67e74705SXin Li // CHECK-NEXT: call void @objc_release(i8* [[T2]]) 82*67e74705SXin Li // CHECK-NEXT: br label 83*67e74705SXin Li 84*67e74705SXin Li // CHECK: [[T0:%.*]] = load i32, i32* [[COND]] 85*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 86*67e74705SXin Li // CHECK: [[ARG:%.*]] = phi i8** 87*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 88*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]] 89*67e74705SXin Li // CHECK-NEXT: store i1 false, i1* [[CONDCLEANUP]] 90*67e74705SXin Li // CHECK-NEXT: br i1 [[T0]], 91*67e74705SXin Li // CHECK: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[ARG]]) 92*67e74705SXin Li // CHECK-NEXT: store i8* [[T0]], i8** [[CONDCLEANUPSAVE]] 93*67e74705SXin Li // CHECK-NEXT: store i1 true, i1* [[CONDCLEANUP]] 94*67e74705SXin Li // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]] 95*67e74705SXin Li // CHECK-NEXT: br label 96*67e74705SXin Li // CHECK: call void @test1_sink(i8** [[T1]]) 97*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 98*67e74705SXin Li // CHECK-NEXT: br i1 [[T0]], 99*67e74705SXin Li // CHECK: [[T0:%.*]] = load i8*, i8** [[TEMP2]] 100*67e74705SXin Li // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]]) 101*67e74705SXin Li // CHECK-NEXT: br label 102*67e74705SXin Li 103*67e74705SXin Li // CHECK: call void @objc_destroyWeak(i8** [[WEAK]]) 104*67e74705SXin Li // CHECK: [[WEAKPTR2:%.*]] = bitcast i8** [[WEAK]] to i8* 105*67e74705SXin Li // CHECK: call void @llvm.lifetime.end(i64 8, i8* [[WEAKPTR2]]) 106*67e74705SXin Li // CHECK: [[STRONGPTR2:%.*]] = bitcast i8** [[STRONG]] to i8* 107*67e74705SXin Li // CHECK: call void @llvm.lifetime.end(i64 8, i8* [[STRONGPTR2]]) 108*67e74705SXin Li // CHECK: ret void 109*67e74705SXin Li} 110*67e74705SXin Li 111*67e74705SXin Li// rdar://13113981 112*67e74705SXin Li// Test that, when emitting an expression at +1 that we can't peephole, 113*67e74705SXin Li// we emit the retain inside the full-expression. If we ever peephole 114*67e74705SXin Li// +1s of conditional expressions (which we probably ought to), we'll 115*67e74705SXin Li// need to find another example of something we need to do this for. 116*67e74705SXin Livoid test2(int cond) { 117*67e74705SXin Li extern id test2_producer(void); 118*67e74705SXin Li for (id obj in cond ? test2_producer() : (void*) 0) { 119*67e74705SXin Li } 120*67e74705SXin Li 121*67e74705SXin Li // CHECK-LABEL: define void @test2( 122*67e74705SXin Li // CHECK: [[COND:%.*]] = alloca i32, 123*67e74705SXin Li // CHECK: alloca i8* 124*67e74705SXin Li // CHECK: [[CLEANUP_SAVE:%.*]] = alloca i8* 125*67e74705SXin Li // CHECK: [[RUN_CLEANUP:%.*]] = alloca i1 126*67e74705SXin Li // Evaluate condition; cleanup disabled by default. 127*67e74705SXin Li // CHECK: [[T0:%.*]] = load i32, i32* [[COND]], 128*67e74705SXin Li // CHECK-NEXT: icmp ne i32 [[T0]], 0 129*67e74705SXin Li // CHECK-NEXT: store i1 false, i1* [[RUN_CLEANUP]] 130*67e74705SXin Li // CHECK-NEXT: br i1 131*67e74705SXin Li // Within true branch, cleanup enabled. 132*67e74705SXin Li // CHECK: [[T0:%.*]] = call i8* @test2_producer() 133*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 134*67e74705SXin Li // CHECK-NEXT: store i8* [[T1]], i8** [[CLEANUP_SAVE]] 135*67e74705SXin Li // CHECK-NEXT: store i1 true, i1* [[RUN_CLEANUP]] 136*67e74705SXin Li // CHECK-NEXT: br label 137*67e74705SXin Li // Join point for conditional operator; retain immediately. 138*67e74705SXin Li // CHECK: [[T0:%.*]] = phi i8* [ [[T1]], {{%.*}} ], [ null, {{%.*}} ] 139*67e74705SXin Li // CHECK-NEXT: [[RESULT:%.*]] = call i8* @objc_retain(i8* [[T0]]) 140*67e74705SXin Li // Leaving full-expression; run conditional cleanup. 141*67e74705SXin Li // CHECK-NEXT: [[T0:%.*]] = load i1, i1* [[RUN_CLEANUP]] 142*67e74705SXin Li // CHECK-NEXT: br i1 [[T0]] 143*67e74705SXin Li // CHECK: [[T0:%.*]] = load i8*, i8** [[CLEANUP_SAVE]] 144*67e74705SXin Li // CHECK-NEXT: call void @objc_release(i8* [[T0]]) 145*67e74705SXin Li // CHECK-NEXT: br label 146*67e74705SXin Li // And way down at the end of the loop: 147*67e74705SXin Li // CHECK: call void @objc_release(i8* [[RESULT]]) 148*67e74705SXin Li} 149*67e74705SXin Li 150*67e74705SXin Li// CHECK: attributes [[NUW]] = { nounwind } 151