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