mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-23 22:52:48 +00:00

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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295410 91177308-0d34-0410-b5e6-96231b3b80d8
184 lines
4.6 KiB
LLVM
184 lines
4.6 KiB
LLVM
; 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
|
|
}
|