forked from OSchip/llvm-project
[SCEV] Prove condition invariance via context, try 2
Initial implementation had too weak requirements to positive/negative range crossings. Not crossing zero with nuw is not enough for two reasons: - If ArLHS has negative step, it may turn from positive to negative without crossing 0 boundary from left to right (and crossing right to left doesn't count for unsigned); - If ArLHS crosses SINT_MAX boundary, it still turns from positive to negative; In fact we require that ArLHS always stays non-negative or negative, which an be enforced by the following set of preconditions: - both nuw and nsw; - positive step (looks liftable); Because of positive step, boundary crossing is only possible from left part to the right part. And because of no-wrap flags, it is guaranteed to never happen.
This commit is contained in:
parent
5541e6bc05
commit
e587199a50
|
@ -1091,7 +1091,8 @@ public:
|
|||
/// invariants, available at L's entry. Otherwise, return None.
|
||||
Optional<LoopInvariantPredicate>
|
||||
getLoopInvariantPredicate(ICmpInst::Predicate Pred, const SCEV *LHS,
|
||||
const SCEV *RHS, const Loop *L);
|
||||
const SCEV *RHS, const Loop *L,
|
||||
const Instruction *CtxI = nullptr);
|
||||
|
||||
/// If the result of the predicate LHS `Pred` RHS is loop invariant with
|
||||
/// respect to L at given Context during at least first MaxIter iterations,
|
||||
|
|
|
@ -10756,8 +10756,8 @@ ScalarEvolution::getMonotonicPredicateTypeImpl(const SCEVAddRecExpr *LHS,
|
|||
Optional<ScalarEvolution::LoopInvariantPredicate>
|
||||
ScalarEvolution::getLoopInvariantPredicate(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS,
|
||||
const Loop *L) {
|
||||
|
||||
const Loop *L,
|
||||
const Instruction *CtxI) {
|
||||
// If there is a loop-invariant, force it into the RHS, otherwise bail out.
|
||||
if (!isLoopInvariant(RHS, L)) {
|
||||
if (!isLoopInvariant(LHS, L))
|
||||
|
@ -10794,10 +10794,49 @@ ScalarEvolution::getLoopInvariantPredicate(ICmpInst::Predicate Pred,
|
|||
bool Increasing = *MonotonicType == ScalarEvolution::MonotonicallyIncreasing;
|
||||
auto P = Increasing ? Pred : ICmpInst::getInversePredicate(Pred);
|
||||
|
||||
if (!isLoopBackedgeGuardedByCond(L, P, LHS, RHS))
|
||||
return None;
|
||||
if (isLoopBackedgeGuardedByCond(L, P, LHS, RHS))
|
||||
return ScalarEvolution::LoopInvariantPredicate(Pred, ArLHS->getStart(),
|
||||
RHS);
|
||||
|
||||
return ScalarEvolution::LoopInvariantPredicate(Pred, ArLHS->getStart(), RHS);
|
||||
if (!CtxI)
|
||||
return None;
|
||||
// Try to prove via context.
|
||||
// TODO: Support other cases.
|
||||
switch (Pred) {
|
||||
default:
|
||||
break;
|
||||
case ICmpInst::ICMP_ULE:
|
||||
case ICmpInst::ICMP_ULT: {
|
||||
assert(ArLHS->hasNoUnsignedWrap() && "Is a requirement of monotonicity!");
|
||||
// Given preconditions
|
||||
// (1) ArLHS does not cross the border of positive and negative parts of
|
||||
// range because of:
|
||||
// - Positive step; (TODO: lift this limitation)
|
||||
// - nuw - does not cross zero boundary;
|
||||
// - nsw - does not cross SINT_MAX boundary;
|
||||
// (2) ArLHS <s RHS
|
||||
// (3) RHS >=s 0
|
||||
// we can replace the loop variant ArLHS <u RHS condition with loop
|
||||
// invariant Start(ArLHS) <u RHS.
|
||||
//
|
||||
// Because of (1) there are two options:
|
||||
// - ArLHS is always negative. It means that ArLHS <u RHS is always false;
|
||||
// - ArLHS is always non-negative. Because of (3) RHS is also non-negative.
|
||||
// It means that ArLHS <s RHS <=> ArLHS <u RHS.
|
||||
// Because of (2) ArLHS <u RHS is trivially true.
|
||||
// All together it means that ArLHS <u RHS <=> Start(ArLHS) >=s 0.
|
||||
// We can strengthen this to Start(ArLHS) <u RHS.
|
||||
auto SignFlippedPred = ICmpInst::getFlippedSignednessPredicate(Pred);
|
||||
if (ArLHS->hasNoSignedWrap() && ArLHS->isAffine() &&
|
||||
isKnownPositive(ArLHS->getStepRecurrence(*this)) &&
|
||||
isKnownNonNegative(RHS) &&
|
||||
isKnownPredicateAt(SignFlippedPred, ArLHS, RHS, CtxI))
|
||||
return ScalarEvolution::LoopInvariantPredicate(Pred, ArLHS->getStart(),
|
||||
RHS);
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<ScalarEvolution::LoopInvariantPredicate>
|
||||
|
|
|
@ -213,7 +213,8 @@ bool SimplifyIndvar::makeIVComparisonInvariant(ICmpInst *ICmp,
|
|||
auto *PN = dyn_cast<PHINode>(IVOperand);
|
||||
if (!PN)
|
||||
return false;
|
||||
auto LIP = SE->getLoopInvariantPredicate(Pred, S, X, L);
|
||||
|
||||
auto LIP = SE->getLoopInvariantPredicate(Pred, S, X, L, ICmp);
|
||||
if (!LIP)
|
||||
return false;
|
||||
ICmpInst::Predicate InvariantPredicate = LIP->Pred;
|
||||
|
|
|
@ -320,6 +320,8 @@ done:
|
|||
|
||||
; Slightly more complex version of previous one (cycled phis).
|
||||
; TODO: remove unsigned comparison by proving non-negativity of iv.start.
|
||||
; TODO: When we check against IV_START, for some reason we then cannot infer nuw for IV.next.
|
||||
; It was possible while checking against IV. Missing inference logic somewhere.
|
||||
define i32 @start.from.sibling.iv.wide.cycled.phis(i32* %len.ptr, i32* %sibling.len.ptr) {
|
||||
; CHECK-LABEL: @start.from.sibling.iv.wide.cycled.phis(
|
||||
; CHECK-NEXT: entry:
|
||||
|
@ -349,10 +351,10 @@ define i32 @start.from.sibling.iv.wide.cycled.phis(i32* %len.ptr, i32* %sibling.
|
|||
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
||||
; CHECK: signed.passed:
|
||||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV_START]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_BACKEDGE]]
|
||||
; CHECK: outer.loop.backedge:
|
||||
|
@ -467,10 +469,10 @@ define i32 @start.from.sibling.iv.wide.cycled.phis.complex.phis(i32* %len.ptr, i
|
|||
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
||||
; CHECK: signed.passed:
|
||||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
||||
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV_START]], [[LEN]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
||||
; CHECK: backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
||||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_SELECTION:%.*]]
|
||||
; CHECK: outer.loop.selection:
|
||||
|
|
|
@ -412,7 +412,7 @@ define i32 @test_05(i32 %a, i32* %bp) {
|
|||
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
|
||||
; CHECK: inner.1:
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[OUTER_IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
|
||||
; CHECK: inner.backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
|
@ -974,7 +974,7 @@ define i32 @test_06(i32 %a, i32* %bp) {
|
|||
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
|
||||
; CHECK: inner.1:
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[OUTER_IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
|
||||
; CHECK: inner.backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
|
@ -1045,7 +1045,7 @@ define i32 @test_07(i32 %a, i32* %bp) {
|
|||
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
|
||||
; CHECK: inner.1:
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[OUTER_IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
|
||||
; CHECK: inner.backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
|
@ -1128,7 +1128,7 @@ define i32 @test_08(i32 %a, i32* %bp) {
|
|||
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
|
||||
; CHECK: inner.1:
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
|
||||
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[OUTER_IV]], [[B]]
|
||||
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
|
||||
; CHECK: inner.backedge:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
||||
|
|
Loading…
Reference in New Issue