1; RUN: opt < %s -jump-threading -dce -S | FileCheck %s 2 3declare void @llvm.experimental.guard(i1, ...) 4 5declare i32 @f1() 6declare i32 @f2() 7 8define i32 @branch_implies_guard(i32 %a) { 9; CHECK-LABEL: @branch_implies_guard( 10 %cond = icmp slt i32 %a, 10 11 br i1 %cond, label %T1, label %F1 12 13T1: 14; CHECK: T1.split 15; CHECK: %v1 = call i32 @f1() 16; CHECK-NEXT: %retVal 17; CHECK-NEXT: br label %Merge 18 %v1 = call i32 @f1() 19 br label %Merge 20 21F1: 22; CHECK: F1.split 23; CHECK: %v2 = call i32 @f2() 24; CHECK-NEXT: %retVal 25; CHECK-NEXT: %condGuard 26; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard 27; CHECK-NEXT: br label %Merge 28 %v2 = call i32 @f2() 29 br label %Merge 30 31Merge: 32; CHECK: Merge 33; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard( 34 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 35 %retVal = add i32 %retPhi, 10 36 %condGuard = icmp slt i32 %a, 20 37 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 38 ret i32 %retVal 39} 40 41define i32 @not_branch_implies_guard(i32 %a) { 42; CHECK-LABEL: @not_branch_implies_guard( 43 %cond = icmp slt i32 %a, 20 44 br i1 %cond, label %T1, label %F1 45 46T1: 47; CHECK: T1.split: 48; CHECK-NEXT: %v1 = call i32 @f1() 49; CHECK-NEXT: %retVal 50; CHECK-NEXT: %condGuard 51; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard 52; CHECK-NEXT: br label %Merge 53 %v1 = call i32 @f1() 54 br label %Merge 55 56F1: 57; CHECK: F1.split: 58; CHECK-NEXT: %v2 = call i32 @f2() 59; CHECK-NEXT: %retVal 60; CHECK-NEXT: br label %Merge 61 %v2 = call i32 @f2() 62 br label %Merge 63 64Merge: 65; CHECK: Merge 66; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard( 67 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 68 %retVal = add i32 %retPhi, 10 69 %condGuard = icmp sgt i32 %a, 10 70 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 71 ret i32 %retVal 72} 73 74define i32 @branch_overlaps_guard(i32 %a) { 75; CHECK-LABEL: @branch_overlaps_guard( 76 %cond = icmp slt i32 %a, 20 77 br i1 %cond, label %T1, label %F1 78 79T1: 80; CHECK: T1: 81; CHECK-NEXT: %v1 = call i32 @f1() 82; CHECK-NEXT: br label %Merge 83 %v1 = call i32 @f1() 84 br label %Merge 85 86F1: 87; CHECK: F1: 88; CHECK-NEXT: %v2 = call i32 @f2() 89; CHECK-NEXT: br label %Merge 90 %v2 = call i32 @f2() 91 br label %Merge 92 93Merge: 94; CHECK: Merge 95; CHECK: %condGuard = icmp slt i32 %a, 10 96; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 97 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 98 %retVal = add i32 %retPhi, 10 99 %condGuard = icmp slt i32 %a, 10 100 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 101 ret i32 %retVal 102} 103 104define i32 @branch_doesnt_overlap_guard(i32 %a) { 105; CHECK-LABEL: @branch_doesnt_overlap_guard( 106 %cond = icmp slt i32 %a, 10 107 br i1 %cond, label %T1, label %F1 108 109T1: 110; CHECK: T1: 111; CHECK-NEXT: %v1 = call i32 @f1() 112; CHECK-NEXT: br label %Merge 113 %v1 = call i32 @f1() 114 br label %Merge 115 116F1: 117; CHECK: F1: 118; CHECK-NEXT: %v2 = call i32 @f2() 119; CHECK-NEXT: br label %Merge 120 %v2 = call i32 @f2() 121 br label %Merge 122 123Merge: 124; CHECK: Merge 125; CHECK: %condGuard = icmp sgt i32 %a, 20 126; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 127 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 128 %retVal = add i32 %retPhi, 10 129 %condGuard = icmp sgt i32 %a, 20 130 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 131 ret i32 %retVal 132} 133 134define i32 @not_a_diamond1(i32 %a, i1 %cond1) { 135; CHECK-LABEL: @not_a_diamond1( 136 br i1 %cond1, label %Pred, label %Exit 137 138Pred: 139; CHECK: Pred: 140; CHECK-NEXT: switch i32 %a, label %Exit 141 switch i32 %a, label %Exit [ 142 i32 10, label %Merge 143 i32 20, label %Merge 144 ] 145 146Merge: 147; CHECK: Merge: 148; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 149; CHECK-NEXT: br label %Exit 150 call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 151 br label %Exit 152 153Exit: 154; CHECK: Exit: 155; CHECK-NEXT: ret i32 %a 156 ret i32 %a 157} 158 159define void @not_a_diamond2(i32 %a, i1 %cond1) { 160; CHECK-LABEL: @not_a_diamond2( 161 br label %Parent 162 163Merge: 164 call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ] 165 ret void 166 167Pred: 168; CHECK-NEXT: Pred: 169; CHECK-NEXT: switch i32 %a, label %Exit 170 switch i32 %a, label %Exit [ 171 i32 10, label %Merge 172 i32 20, label %Merge 173 ] 174 175Parent: 176 br label %Pred 177 178Exit: 179; CHECK: Merge: 180; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 181; CHECK-NEXT: ret void 182 ret void 183} 184