1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s 3; RUN: opt -S -codegenprepare %s -mtriple=x86_64-apple-darwin -o - | FileCheck %s --check-prefix OPT 4 5; Teach CGP to dup returns to enable tail call optimization. 6; rdar://9147433 7 8define i32 @foo(i32 %x) nounwind ssp { 9; CHECK-LABEL: foo: 10entry: 11 switch i32 %x, label %return [ 12 i32 1, label %sw.bb 13 i32 2, label %sw.bb1 14 i32 3, label %sw.bb3 15 i32 4, label %sw.bb5 16 i32 5, label %sw.bb7 17 i32 6, label %sw.bb9 18 ] 19 20sw.bb: ; preds = %entry 21; CHECK: jmp _f1 22 %call = tail call i32 @f1() nounwind 23 br label %return 24 25sw.bb1: ; preds = %entry 26; CHECK: jmp _f2 27 %call2 = tail call i32 @f2() nounwind 28 br label %return 29 30sw.bb3: ; preds = %entry 31; CHECK: jmp _f3 32 %call4 = tail call i32 @f3() nounwind 33 br label %return 34 35sw.bb5: ; preds = %entry 36; CHECK: jmp _f4 37 %call6 = tail call i32 @f4() nounwind 38 br label %return 39 40sw.bb7: ; preds = %entry 41; CHECK: jmp _f5 42 %call8 = tail call i32 @f5() nounwind 43 br label %return 44 45sw.bb9: ; preds = %entry 46; CHECK: jmp _f6 47 %call10 = tail call i32 @f6() nounwind 48 br label %return 49 50return: ; preds = %entry, %sw.bb9, %sw.bb7, %sw.bb5, %sw.bb3, %sw.bb1, %sw.bb 51 %retval.0 = phi i32 [ %call10, %sw.bb9 ], [ %call8, %sw.bb7 ], [ %call6, %sw.bb5 ], [ %call4, %sw.bb3 ], [ %call2, %sw.bb1 ], [ %call, %sw.bb ], [ 0, %entry ] 52 ret i32 %retval.0 53} 54 55declare i32 @f1() 56 57declare i32 @f2() 58 59declare i32 @f3() 60 61declare i32 @f4() 62 63declare i32 @f5() 64 65declare i32 @f6() 66 67; rdar://11958338 68%0 = type opaque 69 70declare i8* @bar(i8*) uwtable optsize noinline ssp 71 72define hidden %0* @thingWithValue(i8* %self) uwtable ssp { 73entry: 74; CHECK-LABEL: thingWithValue: 75; CHECK: jmp _bar 76 br i1 undef, label %if.then.i, label %if.else.i 77 78if.then.i: ; preds = %entry 79 br label %someThingWithValue.exit 80 81if.else.i: ; preds = %entry 82 %call4.i = tail call i8* @bar(i8* undef) optsize 83 br label %someThingWithValue.exit 84 85someThingWithValue.exit: ; preds = %if.else.i, %if.then.i 86 %retval.0.in.i = phi i8* [ undef, %if.then.i ], [ %call4.i, %if.else.i ] 87 %retval.0.i = bitcast i8* %retval.0.in.i to %0* 88 ret %0* %retval.0.i 89} 90 91 92; Correctly handle zext returns. 93declare zeroext i1 @foo_i1() 94 95; CHECK-LABEL: zext_i1 96; CHECK: jmp _foo_i1 97define zeroext i1 @zext_i1(i1 %k) { 98entry: 99 br i1 %k, label %land.end, label %land.rhs 100 101land.rhs: ; preds = %entry 102 %call1 = tail call zeroext i1 @foo_i1() 103 br label %land.end 104 105land.end: ; preds = %entry, %land.rhs 106 %0 = phi i1 [ false, %entry ], [ %call1, %land.rhs ] 107 ret i1 %0 108} 109 110; We need to look through bitcasts when looking for tail calls in phi incoming 111; values. 112declare i32* @g_ret32() 113define i8* @f_ret8(i8* %obj) nounwind { 114; OPT-LABEL: @f_ret8( 115; OPT-NEXT: entry: 116; OPT-NEXT: [[CMP:%.*]] = icmp eq i8* [[OBJ:%.*]], null 117; OPT-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[IF_THEN:%.*]] 118; OPT: if.then: 119; OPT-NEXT: [[PTR:%.*]] = tail call i32* @g_ret32() 120; OPT-NEXT: [[CASTED:%.*]] = bitcast i32* [[PTR]] to i8* 121; OPT-NEXT: ret i8* [[CASTED]] 122; OPT: return: 123; OPT-NEXT: ret i8* [[OBJ]] 124; 125; CHECK-LABEL: f_ret8: 126; CHECK: ## %bb.0: ## %entry 127; CHECK-NEXT: testq %rdi, %rdi 128; CHECK-NEXT: je LBB3_1 129; CHECK-NEXT: ## %bb.2: ## %if.then 130; CHECK-NEXT: jmp _g_ret32 ## TAILCALL 131; CHECK-NEXT: LBB3_1: ## %return 132; CHECK-NEXT: movq %rdi, %rax 133; CHECK-NEXT: retq 134entry: 135 %cmp = icmp eq i8* %obj, null 136 br i1 %cmp, label %return, label %if.then 137 138if.then: 139 %ptr = tail call i32* @g_ret32() 140 %casted = bitcast i32* %ptr to i8* 141 br label %return 142 143return: 144 %retval = phi i8* [ %casted, %if.then ], [ %obj, %entry ] 145 ret i8* %retval 146} 147