mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[SCEV] recognize logical and/or pattern
This patch makes SCEV recognize 'select A, B, false' and 'select A, true, B'. This is a performance improvement that will be helpful after unsound select -> and/or transformation is removed, as discussed in D93065. SCEV's answers for the select form should be a bit more conservative than the equivalent `and A, B` / `or A, B`. Take this example: https://alive2.llvm.org/ce/z/NsP9ue . To check whether it is valid for SCEV's computeExitLimit to return min(n, m) as ExactNotTaken value, I put llvm.assume at tgt. It fails because the exit limit becomes poison if n is zero and m is poison. This is problematic if e.g. the exit value of i is replaced with min(n, m). If either n or m is constant, we can revive the analysis again. I added relevant tests and put alive2 links there. If and is used instead, this is okay: https://alive2.llvm.org/ce/z/K9rbJk . Hence the existing analysis is sound. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D93882
This commit is contained in:
parent
0c19daeb5f
commit
38364a4c2c
@ -1676,10 +1676,7 @@ private:
|
||||
computeExitLimitFromCondFromBinOp(ExitLimitCacheTy &Cache, const Loop *L,
|
||||
Value *ExitCond, bool ExitIfTrue,
|
||||
bool ControlsExit, bool AllowPredicates);
|
||||
ExitLimit computeExitLimitFromCondFromBinOpHelper(
|
||||
ExitLimitCacheTy &Cache, const Loop *L, BinaryOperator *BO,
|
||||
bool EitherMayExit, bool ExitIfTrue, bool ControlsExit,
|
||||
bool AllowPredicates, const Constant *NeutralElement);
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will
|
||||
/// execute if its exit condition were a conditional branch of the ICmpInst
|
||||
/// ExitCond and ExitIfTrue. If AllowPredicates is set, this call will try
|
||||
|
@ -135,6 +135,7 @@
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace PatternMatch;
|
||||
|
||||
#define DEBUG_TYPE "scalar-evolution"
|
||||
|
||||
@ -7578,47 +7579,64 @@ ScalarEvolution::computeExitLimitFromCondFromBinOp(
|
||||
ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, bool ExitIfTrue,
|
||||
bool ControlsExit, bool AllowPredicates) {
|
||||
// Check if the controlling expression for this loop is an And or Or.
|
||||
if (auto *BO = dyn_cast<BinaryOperator>(ExitCond)) {
|
||||
if (BO->getOpcode() == Instruction::And)
|
||||
return computeExitLimitFromCondFromBinOpHelper(
|
||||
Cache, L, BO, !ExitIfTrue, ExitIfTrue, ControlsExit, AllowPredicates,
|
||||
ConstantInt::get(BO->getType(), 1));
|
||||
if (BO->getOpcode() == Instruction::Or)
|
||||
return computeExitLimitFromCondFromBinOpHelper(
|
||||
Cache, L, BO, ExitIfTrue, ExitIfTrue, ControlsExit, AllowPredicates,
|
||||
ConstantInt::get(BO->getType(), 0));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
Value *Op0, *Op1;
|
||||
bool IsAnd = false;
|
||||
if (match(ExitCond, m_LogicalAnd(m_Value(Op0), m_Value(Op1))))
|
||||
IsAnd = true;
|
||||
else if (match(ExitCond, m_LogicalOr(m_Value(Op0), m_Value(Op1))))
|
||||
IsAnd = false;
|
||||
else
|
||||
return None;
|
||||
|
||||
// EitherMayExit is true in these two cases:
|
||||
// br (and Op0 Op1), loop, exit
|
||||
// br (or Op0 Op1), exit, loop
|
||||
bool EitherMayExit = IsAnd ^ ExitIfTrue;
|
||||
ExitLimit EL0 = computeExitLimitFromCondCached(Cache, L, Op0, ExitIfTrue,
|
||||
ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL1 = computeExitLimitFromCondCached(Cache, L, Op1, ExitIfTrue,
|
||||
ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
|
||||
// Be robust against unsimplified IR for the form "op i1 X, NeutralElement"
|
||||
const Constant *NeutralElement = ConstantInt::get(ExitCond->getType(), IsAnd);
|
||||
if (isa<ConstantInt>(Op1))
|
||||
return Op1 == NeutralElement ? EL0 : EL1;
|
||||
if (isa<ConstantInt>(Op0))
|
||||
return Op0 == NeutralElement ? EL1 : EL0;
|
||||
|
||||
ScalarEvolution::ExitLimit
|
||||
ScalarEvolution::computeExitLimitFromCondFromBinOpHelper(
|
||||
ExitLimitCacheTy &Cache, const Loop *L, BinaryOperator *BO,
|
||||
bool EitherMayExit, bool ExitIfTrue, bool ControlsExit,
|
||||
bool AllowPredicates, const Constant *NeutralElement) {
|
||||
ExitLimit EL0 = computeExitLimitFromCondCached(
|
||||
Cache, L, BO->getOperand(0), ExitIfTrue, ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL1 = computeExitLimitFromCondCached(
|
||||
Cache, L, BO->getOperand(1), ExitIfTrue, ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
// Be robust against unsimplified IR for the form "op i1 X,
|
||||
// NeutralElement"
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->getOperand(1)))
|
||||
return CI == NeutralElement ? EL0 : EL1;
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->getOperand(0)))
|
||||
return CI == NeutralElement ? EL1 : EL0;
|
||||
const SCEV *BECount = getCouldNotCompute();
|
||||
const SCEV *MaxBECount = getCouldNotCompute();
|
||||
if (EitherMayExit) {
|
||||
// Both conditions must be same for the loop to continue executing.
|
||||
// Choose the less conservative count.
|
||||
if (EL0.ExactNotTaken == getCouldNotCompute() ||
|
||||
EL1.ExactNotTaken == getCouldNotCompute())
|
||||
BECount = getCouldNotCompute();
|
||||
else
|
||||
// If ExitCond is a short-circuit form (select), using
|
||||
// umin(EL0.ExactNotTaken, EL1.ExactNotTaken) is unsafe in general.
|
||||
// To see the detailed examples, please see
|
||||
// test/Analysis/ScalarEvolution/exit-count-select.ll
|
||||
bool PoisonSafe = isa<BinaryOperator>(ExitCond);
|
||||
if (!PoisonSafe)
|
||||
// Even if ExitCond is select, we can safely derive BECount using both
|
||||
// EL0 and EL1 in these cases:
|
||||
// (1) EL0.ExactNotTaken is non-zero
|
||||
// (2) EL1.ExactNotTaken is non-poison
|
||||
// (3) EL0.ExactNotTaken is zero (BECount should be simply zero and
|
||||
// it cannot be umin(0, ..))
|
||||
// The PoisonSafe assignment below is simplified and the assertion after
|
||||
// BECount calculation fully guarantees the condition (3).
|
||||
PoisonSafe = isa<SCEVConstant>(EL0.ExactNotTaken) ||
|
||||
isa<SCEVConstant>(EL1.ExactNotTaken);
|
||||
if (EL0.ExactNotTaken != getCouldNotCompute() &&
|
||||
EL1.ExactNotTaken != getCouldNotCompute() && PoisonSafe) {
|
||||
BECount =
|
||||
getUMinFromMismatchedTypes(EL0.ExactNotTaken, EL1.ExactNotTaken);
|
||||
|
||||
// If EL0.ExactNotTaken was zero and ExitCond was a short-circuit form,
|
||||
// it should have been simplified to zero (see the condition (3) above)
|
||||
assert(!isa<BinaryOperator>(ExitCond) || !EL0.ExactNotTaken->isZero() ||
|
||||
BECount->isZero());
|
||||
}
|
||||
if (EL0.MaxNotTaken == getCouldNotCompute())
|
||||
MaxBECount = EL1.MaxNotTaken;
|
||||
else if (EL1.MaxNotTaken == getCouldNotCompute())
|
||||
|
312
test/Analysis/ScalarEvolution/exit-count-select.ll
Normal file
312
test/Analysis/ScalarEvolution/exit-count-select.ll
Normal file
@ -0,0 +1,312 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
|
||||
; RUN: opt -analyze -enable-new-pm=0 -scalar-evolution %s | FileCheck %s
|
||||
; RUN: opt -disable-output "-passes=print<scalar-evolution>" %s 2>&1 | FileCheck %s
|
||||
|
||||
|
||||
; exact-not-taken cannot be umin(n, m) because it is possible for (n, m) to be (0, poison)
|
||||
; https://alive2.llvm.org/ce/z/NsP9ue
|
||||
define void @logical_and(i32 %n, i32 %m) {
|
||||
; CHECK-LABEL: 'logical_and'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_and
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_and
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp ult i32 %i, %n
|
||||
%cond_i2 = icmp ult i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
br i1 %cond, label %loop, label %exit
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; If m is constant, exact-not-taken is umin(n, m)
|
||||
; https://alive2.llvm.org/ce/z/ZTNXgY
|
||||
define void @logical_and_m_const(i32 %n) {
|
||||
; CHECK-LABEL: 'logical_and_m_const'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_and_m_const
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,3) S: [0,3) Exits: (2 umin %n) LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,4) S: [1,4) Exits: (1 + (2 umin %n))<nuw><nsw> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_and_m_const
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is (2 umin %n)
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is 2
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (2 umin %n)
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp ult i32 %i, %n
|
||||
%cond_i2 = icmp ult i32 %i, 2
|
||||
%cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
br i1 %cond, label %loop, label %exit
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken is umin(2, m) because m participates in the exit branch condition.
|
||||
; https://alive2.llvm.org/ce/z/rCVMmp
|
||||
define void @logical_and_nonzero(i32 %m) {
|
||||
; CHECK-LABEL: 'logical_and_nonzero'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_and_nonzero
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,3) S: [0,3) Exits: (2 umin %m) LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,4) S: [1,4) Exits: (1 + (2 umin %m))<nuw><nsw> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_and_nonzero
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is (2 umin %m)
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is 2
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (2 umin %m)
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp ult i32 %i, 2
|
||||
%cond_i2 = icmp ult i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
br i1 %cond, label %loop, label %exit
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken cannot be umin(0, m) because m never participates in the exit branch condition.
|
||||
; https://alive2.llvm.org/ce/z/rlaN4a
|
||||
; Instead, it should be just 0.
|
||||
define void @logical_and_zero(i32 %m) {
|
||||
; CHECK-LABEL: 'logical_and_zero'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_and_zero
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,1) S: [0,1) Exits: 0 LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_and_zero
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is 0
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is 0
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is 0
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp ult i32 %i, 0
|
||||
%cond_i2 = icmp ult i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
br i1 %cond, label %loop, label %exit
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken is umax(n, m) because both conditions (cond_i, cond_i2) participate in branching,
|
||||
; preventing them from being poison.
|
||||
; https://alive2.llvm.org/ce/z/8_p-zu
|
||||
; Currently SCEV is conservative in this case and simply returns unknown.
|
||||
define void @logical_and_inversed(i32 %n, i32 %m) {
|
||||
; CHECK-LABEL: 'logical_and_inversed'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_and_inversed
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_and_inversed
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp uge i32 %i, %n
|
||||
%cond_i2 = icmp uge i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 %cond_i2, i1 false
|
||||
br i1 %cond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken cannot be umin(n, m) because it is possible for (n, m) to be (0, poison)
|
||||
; https://alive2.llvm.org/ce/z/ApRitq
|
||||
define void @logical_or(i32 %n, i32 %m) {
|
||||
; CHECK-LABEL: 'logical_or'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_or
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_or
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp uge i32 %i, %n
|
||||
%cond_i2 = icmp uge i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
br i1 %cond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; If m is constant, exact-not-taken is umin(n, m)
|
||||
; https://alive2.llvm.org/ce/z/RQmJiq
|
||||
define void @logical_or_m_const(i32 %n) {
|
||||
; CHECK-LABEL: 'logical_or_m_const'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_or_m_const
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,3) S: [0,3) Exits: (2 umin %n) LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,4) S: [1,4) Exits: (1 + (2 umin %n))<nuw><nsw> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_or_m_const
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is (2 umin %n)
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is 2
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (2 umin %n)
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp uge i32 %i, %n
|
||||
%cond_i2 = icmp uge i32 %i, 2
|
||||
%cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
br i1 %cond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken is umin(2, m) because m participates in exit branch condition.
|
||||
; https://alive2.llvm.org/ce/z/zcHS_d
|
||||
define void @logical_or_nonzero(i32 %m) {
|
||||
; CHECK-LABEL: 'logical_or_nonzero'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_or_nonzero
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,3) S: [0,3) Exits: (2 umin %m) LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,4) S: [1,4) Exits: (1 + (2 umin %m))<nuw><nsw> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_or_nonzero
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is (2 umin %m)
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is 2
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (2 umin %m)
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp uge i32 %i, 2
|
||||
%cond_i2 = icmp uge i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
br i1 %cond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken cannot be umin(0, m) because m does not participate in exit branch condition.
|
||||
; https://alive2.llvm.org/ce/z/-dUmmc
|
||||
; Instead, exact-not-taken should be just 0.
|
||||
define void @logical_or_zero(i32 %m) {
|
||||
; CHECK-LABEL: 'logical_or_zero'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_or_zero
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,1) S: [0,1) Exits: 0 LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_or_zero
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is 0
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is 0
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is 0
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp uge i32 %i, 0
|
||||
%cond_i2 = icmp uge i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
br i1 %cond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; exact-not-taken is umax(n, m) because both conditions (cond_i, cond_i2) participate in branching,
|
||||
; preventing them from being poison.
|
||||
; https://alive2.llvm.org/ce/z/VaCu9C
|
||||
; Currently SCEV is conservative in this case and simply returns unknown.
|
||||
define void @logical_or_inversed(i32 %n, i32 %m) {
|
||||
; CHECK-LABEL: 'logical_or_inversed'
|
||||
; CHECK-NEXT: Classifying expressions for: @logical_or_inversed
|
||||
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
|
||||
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %i.next = add i32 %i, 1
|
||||
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
|
||||
; CHECK-NEXT: %cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
|
||||
; CHECK-NEXT: Determining loop execution counts for: @logical_or_inversed
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [0, %entry], [%i.next, %loop]
|
||||
%i.next = add i32 %i, 1
|
||||
%cond_i = icmp ult i32 %i, %n
|
||||
%cond_i2 = icmp ult i32 %i, %m
|
||||
%cond = select i1 %cond_i, i1 true, i1 %cond_i2
|
||||
br i1 %cond, label %loop, label %exit
|
||||
exit:
|
||||
ret void
|
||||
}
|
366
test/Analysis/ScalarEvolution/trip-count-andor-selectform.ll
Normal file
366
test/Analysis/ScalarEvolution/trip-count-andor-selectform.ll
Normal file
@ -0,0 +1,366 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
|
||||
; RUN: opt < %s -analyze -enable-new-pm=0 -scalar-evolution -scalar-evolution-classify-expressions=0 2>&1 | FileCheck %s
|
||||
; RUN: opt < %s -disable-output "-passes=print<scalar-evolution>" -scalar-evolution-classify-expressions=0 2>&1 2>&1 | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define void @unsimplified_and1(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_and1'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_and1
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%and = select i1 %becond, i1 true, i1 false
|
||||
br i1 %and, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_and2(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_and2'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_and2
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%and = select i1 true, i1 %becond, i1 false
|
||||
br i1 %and, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_and3(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_and3'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_and3
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is false
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%and = select i1 false, i1 %becond, i1 false
|
||||
br i1 %and, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_and4(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_and4'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_and4
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is false
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%and = select i1 %becond, i1 false, i1 false
|
||||
br i1 %and, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_or1(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_or1'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_or1
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%or = select i1 %becond, i1 true, i1 true
|
||||
br i1 %or, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_or2(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_or2'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_or2
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%or = select i1 true, i1 true, i1 %becond
|
||||
br i1 %or, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_or3(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_or3'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_or3
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%or = select i1 false, i1 true, i1 %becond
|
||||
br i1 %or, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @unsimplified_or4(i32 %n) {
|
||||
; CHECK-LABEL: 'unsimplified_or4'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @unsimplified_or4
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ule i32 %iv.inc, %n
|
||||
%or = select i1 %becond, i1 true, i1 false
|
||||
br i1 %or, label %loop, label %leave
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_and1(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_and1'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_and1
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%and = select i1 %becond, i1 true, i1 false
|
||||
br i1 %and, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_and2(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_and2'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_and2
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%and = select i1 true, i1 %becond, i1 false
|
||||
br i1 %and, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_and3(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_and3'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_and3
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%and = select i1 false, i1 %becond, i1 false
|
||||
br i1 %and, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_and4(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_and4'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_and4
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count.
|
||||
; CHECK-NEXT: Loop %loop: Unpredictable predicated backedge-taken count.
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%and = select i1 %becond, i1 false, i1 false
|
||||
br i1 %and, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_or1(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_or1'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_or1
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is false
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%or = select i1 %becond, i1 true, i1 true
|
||||
br i1 %or, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_or2(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_or2'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_or2
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is false
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is false
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%or = select i1 true, i1 true, i1 %becond
|
||||
br i1 %or, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_or3(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_or3'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_or3
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%or = select i1 false, i1 true, i1 %becond
|
||||
br i1 %or, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @reversed_or4(i32 %n) {
|
||||
; CHECK-LABEL: 'reversed_or4'
|
||||
; CHECK-NEXT: Determining loop execution counts for: @reversed_or4
|
||||
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
|
||||
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
|
||||
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is %n
|
||||
; CHECK-NEXT: Predicates:
|
||||
; CHECK: Loop %loop: Trip multiple is 1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
|
||||
%iv.inc = add nsw i32 %iv, 1
|
||||
%becond = icmp ugt i32 %iv.inc, %n
|
||||
%or = select i1 %becond, i1 true, i1 false
|
||||
br i1 %or, label %leave, label %loop
|
||||
|
||||
leave:
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user