| ; RUN: opt < %s -jump-threading -dce -S | FileCheck %s |
| |
| declare void @llvm.experimental.guard(i1, ...) |
| |
| declare i32 @f1() |
| declare i32 @f2() |
| |
| define i32 @branch_implies_guard(i32 %a) { |
| ; CHECK-LABEL: @branch_implies_guard( |
| %cond = icmp slt i32 %a, 10 |
| br i1 %cond, label %T1, label %F1 |
| |
| T1: |
| ; CHECK: T1.split |
| ; CHECK: %v1 = call i32 @f1() |
| ; CHECK-NEXT: %retVal |
| ; CHECK-NEXT: br label %Merge |
| %v1 = call i32 @f1() |
| br label %Merge |
| |
| F1: |
| ; CHECK: F1.split |
| ; CHECK: %v2 = call i32 @f2() |
| ; CHECK-NEXT: %retVal |
| ; CHECK-NEXT: %condGuard |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard |
| ; CHECK-NEXT: br label %Merge |
| %v2 = call i32 @f2() |
| br label %Merge |
| |
| Merge: |
| ; CHECK: Merge |
| ; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard( |
| %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] |
| %retVal = add i32 %retPhi, 10 |
| %condGuard = icmp slt i32 %a, 20 |
| call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] |
| ret i32 %retVal |
| } |
| |
| define i32 @not_branch_implies_guard(i32 %a) { |
| ; CHECK-LABEL: @not_branch_implies_guard( |
| %cond = icmp slt i32 %a, 20 |
| br i1 %cond, label %T1, label %F1 |
| |
| T1: |
| ; CHECK: T1.split: |
| ; CHECK-NEXT: %v1 = call i32 @f1() |
| ; CHECK-NEXT: %retVal |
| ; CHECK-NEXT: %condGuard |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard |
| ; CHECK-NEXT: br label %Merge |
| %v1 = call i32 @f1() |
| br label %Merge |
| |
| F1: |
| ; CHECK: F1.split: |
| ; CHECK-NEXT: %v2 = call i32 @f2() |
| ; CHECK-NEXT: %retVal |
| ; CHECK-NEXT: br label %Merge |
| %v2 = call i32 @f2() |
| br label %Merge |
| |
| Merge: |
| ; CHECK: Merge |
| ; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard( |
| %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] |
| %retVal = add i32 %retPhi, 10 |
| %condGuard = icmp sgt i32 %a, 10 |
| call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] |
| ret i32 %retVal |
| } |
| |
| define i32 @branch_overlaps_guard(i32 %a) { |
| ; CHECK-LABEL: @branch_overlaps_guard( |
| %cond = icmp slt i32 %a, 20 |
| br i1 %cond, label %T1, label %F1 |
| |
| T1: |
| ; CHECK: T1: |
| ; CHECK-NEXT: %v1 = call i32 @f1() |
| ; CHECK-NEXT: br label %Merge |
| %v1 = call i32 @f1() |
| br label %Merge |
| |
| F1: |
| ; CHECK: F1: |
| ; CHECK-NEXT: %v2 = call i32 @f2() |
| ; CHECK-NEXT: br label %Merge |
| %v2 = call i32 @f2() |
| br label %Merge |
| |
| Merge: |
| ; CHECK: Merge |
| ; CHECK: %condGuard = icmp slt i32 %a, 10 |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] |
| %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] |
| %retVal = add i32 %retPhi, 10 |
| %condGuard = icmp slt i32 %a, 10 |
| call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] |
| ret i32 %retVal |
| } |
| |
| define i32 @branch_doesnt_overlap_guard(i32 %a) { |
| ; CHECK-LABEL: @branch_doesnt_overlap_guard( |
| %cond = icmp slt i32 %a, 10 |
| br i1 %cond, label %T1, label %F1 |
| |
| T1: |
| ; CHECK: T1: |
| ; CHECK-NEXT: %v1 = call i32 @f1() |
| ; CHECK-NEXT: br label %Merge |
| %v1 = call i32 @f1() |
| br label %Merge |
| |
| F1: |
| ; CHECK: F1: |
| ; CHECK-NEXT: %v2 = call i32 @f2() |
| ; CHECK-NEXT: br label %Merge |
| %v2 = call i32 @f2() |
| br label %Merge |
| |
| Merge: |
| ; CHECK: Merge |
| ; CHECK: %condGuard = icmp sgt i32 %a, 20 |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] |
| %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] |
| %retVal = add i32 %retPhi, 10 |
| %condGuard = icmp sgt i32 %a, 20 |
| call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] |
| ret i32 %retVal |
| } |
| |
| define i32 @not_a_diamond1(i32 %a, i1 %cond1) { |
| ; CHECK-LABEL: @not_a_diamond1( |
| br i1 %cond1, label %Pred, label %Exit |
| |
| Pred: |
| ; CHECK: Pred: |
| ; CHECK-NEXT: switch i32 %a, label %Exit |
| switch i32 %a, label %Exit [ |
| i32 10, label %Merge |
| i32 20, label %Merge |
| ] |
| |
| Merge: |
| ; CHECK: Merge: |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] |
| ; CHECK-NEXT: br label %Exit |
| call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] |
| br label %Exit |
| |
| Exit: |
| ; CHECK: Exit: |
| ; CHECK-NEXT: ret i32 %a |
| ret i32 %a |
| } |
| |
| define void @not_a_diamond2(i32 %a, i1 %cond1) { |
| ; CHECK-LABEL: @not_a_diamond2( |
| br label %Parent |
| |
| Merge: |
| call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ] |
| ret void |
| |
| Pred: |
| ; CHECK-NEXT: Pred: |
| ; CHECK-NEXT: switch i32 %a, label %Exit |
| switch i32 %a, label %Exit [ |
| i32 10, label %Merge |
| i32 20, label %Merge |
| ] |
| |
| Parent: |
| br label %Pred |
| |
| Exit: |
| ; CHECK: Merge: |
| ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] |
| ; CHECK-NEXT: ret void |
| ret void |
| } |