mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
01f52927e7
As a reminder, a "widenable branch" is the pattern "br i1 (and i1 X, WC()), label %taken, label %untaken" where "WC" is the widenable condition intrinsics. The semantics of such a branch (derived from the semantics of WC) is that a new condition can be added into the condition arbitrarily without violating legality. Broaden the definition in two ways: Allow swapped operands to the br (and X, WC()) form Allow widenable branch w/trivial condition (i.e. true) which takes form of br i1 WC() The former is just general robustness (e.g. for X = non-instruction this is what instcombine produces). The later is specifically important as partial unswitching of a widenable range check produces exactly this form above the loop. Differential Revision: https://reviews.llvm.org/D70502
1117 lines
48 KiB
LLVM
1117 lines
48 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -guard-widening-widen-branch-guards=true -guard-widening < %s | FileCheck %s
|
|
; RUN: opt -S -guard-widening-widen-branch-guards=true -passes=guard-widening < %s | FileCheck %s
|
|
|
|
; Basic test case: we wide the first check to check both the
|
|
; conditions.
|
|
define void @f_0(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_0(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
; Same as @f_0, but with using a more general notion of postdominance.
|
|
define void @f_1(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: right:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded
|
|
br label %merge
|
|
|
|
right: ; preds = %guarded
|
|
br label %merge
|
|
|
|
merge: ; preds = %right, %left
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %merge
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %merge
|
|
ret void
|
|
}
|
|
|
|
; Like @f_1, but we have some code we need to hoist before we can
|
|
; widen a dominanting check.
|
|
define void @f_2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @f_2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: br label [[MERGE:%.*]]
|
|
; CHECK: right:
|
|
; CHECK-NEXT: br label [[MERGE]]
|
|
; CHECK: merge:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ult i32 %a, 10
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded
|
|
br label %merge
|
|
|
|
right: ; preds = %guarded
|
|
br label %merge
|
|
|
|
merge: ; preds = %right, %left
|
|
%cond_1 = icmp ult i32 %b, 10
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %merge
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %merge
|
|
ret void
|
|
}
|
|
|
|
; Negative test: don't hoist stuff out of control flow
|
|
; indiscriminately, since that can make us do more work than needed.
|
|
define void @f_3(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @f_3(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: right:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ult i32 %a, 10
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded
|
|
%cond_1 = icmp ult i32 %b, 10
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %left
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %left
|
|
ret void
|
|
|
|
right: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
; But hoisting out of control flow is fine if it makes a loop computed
|
|
; condition loop invariant. This behavior may require some tuning in
|
|
; the future.
|
|
define void @f_4(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @f_4(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LOOP:%.*]], label [[LEAVE:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[LEAVE]]
|
|
; CHECK: leave:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ult i32 %a, 10
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %loop, label %leave
|
|
|
|
loop: ; preds = %guarded1, %guarded
|
|
%cond_1 = icmp ult i32 %b, 10
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %loop
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %loop
|
|
br i1 undef, label %loop, label %leave
|
|
|
|
leave: ; preds = %guarded1, %guarded
|
|
ret void
|
|
}
|
|
|
|
; Hoisting out of control flow is also fine if we can widen the
|
|
; dominating check without doing any extra work.
|
|
define void @f_5(i32 %a) {
|
|
; CHECK-LABEL: @f_5(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[A:%.*]], 7
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[A]], 11
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[A]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: right:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ugt i32 %a, 7
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded
|
|
%cond_1 = icmp ugt i32 %a, 10
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %left
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %left
|
|
ret void
|
|
|
|
right: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
; Negative test: the load from %a can be safely speculated to before
|
|
; the first guard, but there is no guarantee that it will produce the
|
|
; same value.
|
|
define void @f_6(i1* dereferenceable(32) %a, i1* %b, i1 %unknown) {
|
|
; CHECK-LABEL: @f_6(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = load i1, i1* [[A:%.*]]
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: store i1 [[UNKNOWN:%.*]], i1* [[B:%.*]]
|
|
; CHECK-NEXT: [[COND_1:%.*]] = load i1, i1* [[A]]
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = load i1, i1* %a
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
store i1 %unknown, i1* %b
|
|
%cond_1 = load i1, i1* %a
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
; All else equal, we try to widen the earliest guard we can. This
|
|
; heuristic can use some tuning.
|
|
define void @f_7(i32 %a, i1* %cond_buf) {
|
|
; CHECK-LABEL: @f_7(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_1:%.*]] = load volatile i1, i1* [[COND_BUF:%.*]]
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[COND_2:%.*]] = load volatile i1, i1* [[COND_BUF]]
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_2]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: [[WIDENABLE_COND7:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND8:%.*]] = and i1 [[COND_3]], [[WIDENABLE_COND7]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED5:%.*]], label [[DEOPT6:%.*]], !prof !0
|
|
; CHECK: deopt6:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded5:
|
|
; CHECK-NEXT: br label [[LEFT]]
|
|
; CHECK: right:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_1 = load volatile i1, i1* %cond_buf
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_1, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%cond_2 = load volatile i1, i1* %cond_buf
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_2, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded5, %guarded1
|
|
%cond_3 = icmp ult i32 %a, 7
|
|
%widenable_cond7 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond8 = and i1 %cond_3, %widenable_cond7
|
|
br i1 %exiplicit_guard_cond8, label %guarded5, label %deopt6, !prof !0
|
|
|
|
deopt6: ; preds = %left
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded5: ; preds = %left
|
|
br label %left
|
|
|
|
right: ; preds = %guarded1
|
|
ret void
|
|
}
|
|
|
|
; In this case the earliest dominating guard is in a loop, and we
|
|
; don't want to put extra work in there. This heuristic can use some
|
|
; tuning.
|
|
define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) {
|
|
; CHECK-LABEL: @f_8(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_1:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[LEAVE:%.*]]
|
|
; CHECK: leave:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: br i1 undef, label [[LOOP2:%.*]], label [[LEAVE2:%.*]]
|
|
; CHECK: loop2:
|
|
; CHECK-NEXT: [[WIDENABLE_COND7:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND8:%.*]] = and i1 [[COND_3]], [[WIDENABLE_COND7]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED5:%.*]], label [[DEOPT6:%.*]], !prof !0
|
|
; CHECK: deopt6:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded5:
|
|
; CHECK-NEXT: br label [[LOOP2]]
|
|
; CHECK: leave2:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop: ; preds = %guarded, %entry
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_1, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %loop
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %loop
|
|
br i1 undef, label %loop, label %leave
|
|
|
|
leave: ; preds = %guarded
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_2, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %leave
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %leave
|
|
br i1 undef, label %loop2, label %leave2
|
|
|
|
loop2: ; preds = %guarded5, %guarded1
|
|
%cond_3 = icmp ult i32 %a, 7
|
|
%widenable_cond7 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond8 = and i1 %cond_3, %widenable_cond7
|
|
br i1 %exiplicit_guard_cond8, label %guarded5, label %deopt6, !prof !0
|
|
|
|
deopt6: ; preds = %loop2
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded5: ; preds = %loop2
|
|
br label %loop2
|
|
|
|
leave2: ; preds = %guarded1
|
|
ret void
|
|
}
|
|
|
|
; In cases like these where there isn't any "obviously profitable"
|
|
; widening sites, we refuse to do anything.
|
|
define void @f_9(i32 %a, i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_9(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FIRST_LOOP:%.*]]
|
|
; CHECK: first_loop:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[FIRST_LOOP]], label [[SECOND_LOOP:%.*]]
|
|
; CHECK: second_loop:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1:%.*]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: br label [[SECOND_LOOP]]
|
|
;
|
|
entry:
|
|
br label %first_loop
|
|
|
|
first_loop: ; preds = %guarded, %entry
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %first_loop
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %first_loop
|
|
br i1 undef, label %first_loop, label %second_loop
|
|
|
|
second_loop: ; preds = %guarded1, %guarded
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %second_loop
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %second_loop
|
|
br label %second_loop
|
|
}
|
|
|
|
; Same situation as in @f_9: no "obviously profitable" widening sites,
|
|
; so we refuse to do anything.
|
|
define void @f_10(i32 %a, i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_10(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[NO_LOOP:%.*]]
|
|
; CHECK: no_loop:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1:%.*]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop: ; preds = %guarded, %entry
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %loop
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %loop
|
|
br i1 undef, label %loop, label %no_loop
|
|
|
|
no_loop: ; preds = %guarded
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %no_loop
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %no_loop
|
|
ret void
|
|
}
|
|
|
|
; With guards in loops, we're okay hoisting out the guard into the
|
|
; containing loop.
|
|
define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_11(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
|
|
; CHECK: outer_header:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br label [[INNER:%.*]]
|
|
; CHECK: inner:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: br i1 undef, label [[INNER]], label [[OUTER_LATCH:%.*]]
|
|
; CHECK: outer_latch:
|
|
; CHECK-NEXT: br i1 undef, label [[OUTER_HEADER]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %outer_header
|
|
|
|
outer_header: ; preds = %outer_latch, %entry
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %outer_header
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %outer_header
|
|
br label %inner
|
|
|
|
inner: ; preds = %guarded1, %guarded
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %inner
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %inner
|
|
br i1 undef, label %inner, label %outer_latch
|
|
|
|
outer_latch: ; preds = %guarded1
|
|
br i1 undef, label %outer_header, label %exit
|
|
|
|
exit: ; preds = %outer_latch
|
|
ret void
|
|
}
|
|
|
|
; Checks that we are adequately guarded against exponential-time
|
|
; behavior when hoisting code.
|
|
define void @f_12(i32 %a0) {
|
|
; CHECK-LABEL: @f_12(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[A1:%.*]] = mul i32 [[A0:%.*]], [[A0]]
|
|
; CHECK-NEXT: [[A2:%.*]] = mul i32 [[A1]], [[A1]]
|
|
; CHECK-NEXT: [[A3:%.*]] = mul i32 [[A2]], [[A2]]
|
|
; CHECK-NEXT: [[A4:%.*]] = mul i32 [[A3]], [[A3]]
|
|
; CHECK-NEXT: [[A5:%.*]] = mul i32 [[A4]], [[A4]]
|
|
; CHECK-NEXT: [[A6:%.*]] = mul i32 [[A5]], [[A5]]
|
|
; CHECK-NEXT: [[A7:%.*]] = mul i32 [[A6]], [[A6]]
|
|
; CHECK-NEXT: [[A8:%.*]] = mul i32 [[A7]], [[A7]]
|
|
; CHECK-NEXT: [[A9:%.*]] = mul i32 [[A8]], [[A8]]
|
|
; CHECK-NEXT: [[A10:%.*]] = mul i32 [[A9]], [[A9]]
|
|
; CHECK-NEXT: [[A11:%.*]] = mul i32 [[A10]], [[A10]]
|
|
; CHECK-NEXT: [[A12:%.*]] = mul i32 [[A11]], [[A11]]
|
|
; CHECK-NEXT: [[A13:%.*]] = mul i32 [[A12]], [[A12]]
|
|
; CHECK-NEXT: [[A14:%.*]] = mul i32 [[A13]], [[A13]]
|
|
; CHECK-NEXT: [[A15:%.*]] = mul i32 [[A14]], [[A14]]
|
|
; CHECK-NEXT: [[A16:%.*]] = mul i32 [[A15]], [[A15]]
|
|
; CHECK-NEXT: [[A17:%.*]] = mul i32 [[A16]], [[A16]]
|
|
; CHECK-NEXT: [[A18:%.*]] = mul i32 [[A17]], [[A17]]
|
|
; CHECK-NEXT: [[A19:%.*]] = mul i32 [[A18]], [[A18]]
|
|
; CHECK-NEXT: [[A20:%.*]] = mul i32 [[A19]], [[A19]]
|
|
; CHECK-NEXT: [[A21:%.*]] = mul i32 [[A20]], [[A20]]
|
|
; CHECK-NEXT: [[A22:%.*]] = mul i32 [[A21]], [[A21]]
|
|
; CHECK-NEXT: [[A23:%.*]] = mul i32 [[A22]], [[A22]]
|
|
; CHECK-NEXT: [[A24:%.*]] = mul i32 [[A23]], [[A23]]
|
|
; CHECK-NEXT: [[A25:%.*]] = mul i32 [[A24]], [[A24]]
|
|
; CHECK-NEXT: [[A26:%.*]] = mul i32 [[A25]], [[A25]]
|
|
; CHECK-NEXT: [[A27:%.*]] = mul i32 [[A26]], [[A26]]
|
|
; CHECK-NEXT: [[A28:%.*]] = mul i32 [[A27]], [[A27]]
|
|
; CHECK-NEXT: [[A29:%.*]] = mul i32 [[A28]], [[A28]]
|
|
; CHECK-NEXT: [[A30:%.*]] = mul i32 [[A29]], [[A29]]
|
|
; CHECK-NEXT: [[COND:%.*]] = trunc i32 [[A30]] to i1
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 true, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%a1 = mul i32 %a0, %a0
|
|
%a2 = mul i32 %a1, %a1
|
|
%a3 = mul i32 %a2, %a2
|
|
%a4 = mul i32 %a3, %a3
|
|
%a5 = mul i32 %a4, %a4
|
|
%a6 = mul i32 %a5, %a5
|
|
%a7 = mul i32 %a6, %a6
|
|
%a8 = mul i32 %a7, %a7
|
|
%a9 = mul i32 %a8, %a8
|
|
%a10 = mul i32 %a9, %a9
|
|
%a11 = mul i32 %a10, %a10
|
|
%a12 = mul i32 %a11, %a11
|
|
%a13 = mul i32 %a12, %a12
|
|
%a14 = mul i32 %a13, %a13
|
|
%a15 = mul i32 %a14, %a14
|
|
%a16 = mul i32 %a15, %a15
|
|
%a17 = mul i32 %a16, %a16
|
|
%a18 = mul i32 %a17, %a17
|
|
%a19 = mul i32 %a18, %a18
|
|
%a20 = mul i32 %a19, %a19
|
|
%a21 = mul i32 %a20, %a20
|
|
%a22 = mul i32 %a21, %a21
|
|
%a23 = mul i32 %a22, %a22
|
|
%a24 = mul i32 %a23, %a23
|
|
%a25 = mul i32 %a24, %a24
|
|
%a26 = mul i32 %a25, %a25
|
|
%a27 = mul i32 %a26, %a26
|
|
%a28 = mul i32 %a27, %a27
|
|
%a29 = mul i32 %a28, %a28
|
|
%a30 = mul i32 %a29, %a29
|
|
%cond = trunc i32 %a30 to i1
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
define void @f_13(i32 %a) {
|
|
; CHECK-LABEL: @f_13(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp ult i32 [[A]], 10
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp slt i32 [[A]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: right:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ult i32 %a, 14
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded
|
|
%cond_1 = icmp slt i32 %a, 10
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %left
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %left
|
|
ret void
|
|
|
|
right: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
define void @f_14(i32 %a) {
|
|
; CHECK-LABEL: @f_14(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
|
|
; CHECK: left:
|
|
; CHECK-NEXT: [[COND_1:%.*]] = icmp sgt i32 [[A]], 10
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: right:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cond_0 = icmp ult i32 %a, 14
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
br i1 undef, label %left, label %right
|
|
|
|
left: ; preds = %guarded
|
|
%cond_1 = icmp sgt i32 %a, 10
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %left
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %left
|
|
ret void
|
|
|
|
right: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
; Make sure we do not widen guard by trivial true conditions into something.
|
|
define void @f_15(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_15(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 true, [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 true, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
; Make sure we do not widen guard by trivial false conditions into something.
|
|
define void @f_16(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @f_16(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 false, [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 false, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
|
|
define void @swapped_wb(i1 %cond_0, i1 %cond_1) {
|
|
; CHECK-LABEL: @swapped_wb(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDENABLE_COND]], [[WIDE_CHK]]
|
|
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond = and i1 %widenable_cond, %cond_0
|
|
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
define void @trivial_wb(i1 %cond_0) {
|
|
; CHECK-LABEL: @trivial_wb(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND_0:%.*]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
|
; CHECK: deopt:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded:
|
|
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
|
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_0]], [[WIDENABLE_COND3]]
|
|
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
|
; CHECK: deopt2:
|
|
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: guarded1:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
|
br i1 %widenable_cond, label %guarded, label %deopt, !prof !0
|
|
|
|
deopt: ; preds = %entry
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded: ; preds = %entry
|
|
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
|
%exiplicit_guard_cond4 = and i1 %cond_0, %widenable_cond3
|
|
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
|
|
|
deopt2: ; preds = %guarded
|
|
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
|
ret void
|
|
|
|
guarded1: ; preds = %guarded
|
|
ret void
|
|
}
|
|
|
|
|
|
declare void @llvm.experimental.deoptimize.isVoid(...)
|
|
|
|
; Function Attrs: inaccessiblememonly nounwind
|
|
declare i1 @llvm.experimental.widenable.condition() #0
|
|
|
|
attributes #0 = { inaccessiblememonly nounwind }
|
|
|
|
!0 = !{!"branch_weights", i32 1048576, i32 1}
|