This addresses a comment from review on D109845. Even for SCEVs which we can't find true bounds without recursing through operands, entry to the function forms a trivial upper bound. In some cases, this trivial bound is enough to prove safety of flag inference.
/// would trigger undefined behavior on overflow.
SCEV::NoWrapFlags getNoWrapFlagsFromUB(const Value *V);
- /// If S trivially defines a scope (without needing to recurse through
- /// operands), return the first instruction in it. Else, return nullptr.
+ /// Return a scope which provides an upper bound on the defining scope of
+ /// 'S'. Specifically, return the first instruction in said bounding scope.
/// (See scope definition rules associated with flag discussion above)
- const Instruction *getDefinedScopeRoot(const SCEV *S);
+ const Instruction *getDefiningScopeBound(const SCEV *S);
/// Given two instructions in the same function, return true if we can
/// prove B must execute given A executes.
// in the outer scope.
const bool CanPropagateFlags = llvm::any_of(LIOps, [&](const SCEV *S) {
auto *ReachI = &*AddRecLoop->getHeader()->begin();
- if (auto *DefI = getDefinedScopeRoot(S))
- if (isGuaranteedToTransferExecutionTo(DefI, ReachI))
- return true;
- return false;
+ auto *DefI = getDefiningScopeBound(S);
+ return isGuaranteedToTransferExecutionTo(DefI, ReachI);
});
auto AddFlags = CanPropagateFlags ? Flags : SCEV::FlagAnyWrap;
AddRecOps[0] = getAddExpr(LIOps, AddFlags, Depth + 1);
return isSCEVExprNeverPoison(BinOp) ? Flags : SCEV::FlagAnyWrap;
}
-const Instruction *ScalarEvolution::getDefinedScopeRoot(const SCEV *S) {
+const Instruction *ScalarEvolution::getDefiningScopeBound(const SCEV *S) {
if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(S))
return &*AddRec->getLoop()->getHeader()->begin();
- if (isa<SCEVConstant>(S))
- return &*F.getEntryBlock().begin();
- if (auto *U = dyn_cast<SCEVUnknown>(S)) {
+ if (auto *U = dyn_cast<SCEVUnknown>(S))
if (auto *I = dyn_cast<Instruction>(U->getValue()))
return I;
- return &*F.getEntryBlock().begin();
- }
- return nullptr;
+ // All SCEVs are bound by the entry to F
+ return &*F.getEntryBlock().begin();
}
static bool
// TODO: We can do better here in some cases.
if (!isSCEVable(Op->getType()))
return false;
- if (auto *DefI = getDefinedScopeRoot(getSCEV(Op)))
- if (isGuaranteedToTransferExecutionTo(DefI, I))
- return true;
+ auto *DefI = getDefiningScopeBound(getSCEV(Op));
+ if (isGuaranteedToTransferExecutionTo(DefI, I))
+ return true;
}
return false;
}
; CHECK-NEXT: %index32 = sub nsw i32 %i, %sub
; CHECK-NEXT: --> {((-1 * %sub) + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: (-1 + (-1 * %sub) + %numIterations) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %index64 = sext i32 %index32 to i64
-; CHECK-NEXT: --> {((sext i32 %start to i64) + (-1 * (sext i32 %sub to i64))<nsw>),+,1}<nsw><%loop> U: [-4294967295,8589934591) S: [-4294967295,8589934591) Exits: ((zext i32 (-1 + (-1 * %start) + %numIterations) to i64) + (sext i32 %start to i64) + (-1 * (sext i32 %sub to i64))<nsw>) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {((sext i32 %start to i64) + (-1 * (sext i32 %sub to i64))<nsw>)<nsw>,+,1}<nsw><%loop> U: [-4294967295,8589934591) S: [-4294967295,8589934591) Exits: ((zext i32 (-1 + (-1 * %start) + %numIterations) to i64) + (sext i32 %start to i64) + (-1 * (sext i32 %sub to i64))<nsw>) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %ptr = getelementptr inbounds float, float* %input, i64 %index64
; CHECK-NEXT: --> {((4 * (sext i32 %start to i64))<nsw> + (-4 * (sext i32 %sub to i64))<nsw> + %input),+,4}<nw><%loop> U: full-set S: full-set Exits: ((4 * (zext i32 (-1 + (-1 * %start) + %numIterations) to i64))<nuw><nsw> + (4 * (sext i32 %start to i64))<nsw> + (-4 * (sext i32 %sub to i64))<nsw> + %input) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %nexti = add nsw i32 %i, 1
; CHECK-NEXT: %index32 = sub nsw i32 %i, %halfsub
; CHECK-NEXT: --> {((-1 * %halfsub)<nsw> + %start)<nsw>,+,1}<nsw><%loop> U: full-set S: full-set Exits: (-1 + (-1 * %halfsub)<nsw> + %numIterations) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %index64 = sext i32 %index32 to i64
-; CHECK-NEXT: --> {((sext i32 %start to i64) + (-1 * (sext i32 %halfsub to i64))<nsw>),+,1}<nsw><%loop> U: [-3221225471,7516192767) S: [-3221225471,7516192767) Exits: ((zext i32 (-1 + (-1 * %start) + %numIterations) to i64) + (sext i32 %start to i64) + (-1 * (sext i32 %halfsub to i64))<nsw>) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {((sext i32 %start to i64) + (-1 * (sext i32 %halfsub to i64))<nsw>)<nsw>,+,1}<nsw><%loop> U: [-3221225471,7516192767) S: [-3221225471,7516192767) Exits: ((zext i32 (-1 + (-1 * %start) + %numIterations) to i64) + (sext i32 %start to i64) + (-1 * (sext i32 %halfsub to i64))<nsw>) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %ptr = getelementptr inbounds float, float* %input, i64 %index64
; CHECK-NEXT: --> {((4 * (sext i32 %start to i64))<nsw> + (-4 * (sext i32 %halfsub to i64))<nsw> + %input),+,4}<nw><%loop> U: full-set S: full-set Exits: ((4 * (zext i32 (-1 + (-1 * %start) + %numIterations) to i64))<nuw><nsw> + (4 * (sext i32 %start to i64))<nsw> + (-4 * (sext i32 %halfsub to i64))<nsw> + %input) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %nexti = add nsw i32 %i, 1