summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/JumpThreading
diff options
context:
space:
mode:
authorSanjoy Das <sanjoy@playingwithpointers.com>2017-02-17 04:21:14 +0000
committerSanjoy Das <sanjoy@playingwithpointers.com>2017-02-17 04:21:14 +0000
commit8b859c26eccc8e292356376a83f4bcfefe36a6c0 (patch)
tree5f58b355e6acb74a64e67ec5cb133290ce8069cf /llvm/test/Transforms/JumpThreading
parenta0921f68abafaff891ca3d5ee33a7f2d0fba41ee (diff)
downloadbcm5719-llvm-8b859c26eccc8e292356376a83f4bcfefe36a6c0.tar.gz
bcm5719-llvm-8b859c26eccc8e292356376a83f4bcfefe36a6c0.zip
[JumpThreading] Re-enable JumpThreading for guards
Summary: JumpThreading for guards feature has been reverted at https://reviews.llvm.org/rL295200 due to the following problem: the feature used the following algorithm for detection of diamond patters: 1. Find a block with 2 predecessors; 2. Check that these blocks have a common single parent; 3. Check that the parent's terminator is a branch instruction. The problem is that these checks are insufficient. They may pass for a non-diamond construction in case if those two predecessors are actually the same block. This may happen if parent's terminator is a br (either conditional or unconditional) to a block that ends with "switch" instruction with exactly two branches going to one block. This patch re-enables the JumpThreading for guards and fixes this issue by adding the check that those found predecessors are actually different blocks. This guarantees that parent's terminator is a conditional branch with exactly 2 different successors, which is now ensured by assertions. It also adds two more tests for this situation (with parent's terminator being a conditional and an unconditional branch). Patch by Max Kazantsev! Reviewers: anna, sanjoy, reames Reviewed By: sanjoy Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D30036 llvm-svn: 295410
Diffstat (limited to 'llvm/test/Transforms/JumpThreading')
-rw-r--r--llvm/test/Transforms/JumpThreading/guards.ll183
1 files changed, 183 insertions, 0 deletions
diff --git a/llvm/test/Transforms/JumpThreading/guards.ll b/llvm/test/Transforms/JumpThreading/guards.ll
new file mode 100644
index 00000000000..eac2b5dcd85
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/guards.ll
@@ -0,0 +1,183 @@
+; 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
+}
OpenPOWER on IntegriCloud