summaryrefslogtreecommitdiff
path: root/lib/Analysis/ScalarEvolution.cpp
diff options
context:
space:
mode:
authorDaniel Neilson <dneilson@azul.com>2017-09-05 19:54:03 +0000
committerDaniel Neilson <dneilson@azul.com>2017-09-05 19:54:03 +0000
commitf7dd8e2ac0a427d290964362c408eb9e9a1c950c (patch)
tree98b35d610e91530d81ced79fae23c849f704ac43 /lib/Analysis/ScalarEvolution.cpp
parenta3886c11ee55aa4cb683cbb34d9bf33e4de6fc63 (diff)
[SCEV] Ensure ScalarEvolution::createAddRecFromPHIWithCastsImpl properly handles out of range truncations of the start and accum values
Summary: When constructing the predicate P1 in ScalarEvolution::createAddRecFromPHIWithCastsImpl() it is possible for the PHISCEV from which the predicate is constructed to be a SCEVConstant instead of a SCEVAddRec. If this happens, then the cast<SCEVAddRec>(PHISCEV) in the code will assert. Such a PHISCEV is possible if either the start value or the accumulator value is a constant value that not equal to its truncated value, and if the truncated value is zero. This patch adds tests that demonstrate the cast<> assertion, and fixes this problem by checking whether the PHISCEV is a constant before constructing the P1 predicate; if it is, then P1 is equivalent to one of P2 or P3. Additionally, if we know that the start value or accumulator value are constants then we check whether the P2 and/or P3 predicates are known false at compile time; if either is, then we bail out of constructing the AddRec. Reviewers: sanjoy, mkazantsev, silviu.baranga Reviewed By: mkazantsev Subscribers: mkazantsev, llvm-commits Differential Revision: https://reviews.llvm.org/D37265 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312568 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/ScalarEvolution.cpp')
-rw-r--r--lib/Analysis/ScalarEvolution.cpp74
1 files changed, 59 insertions, 15 deletions
diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp
index e3bd30a9e3c..73ce83e9dbc 100644
--- a/lib/Analysis/ScalarEvolution.cpp
+++ b/lib/Analysis/ScalarEvolution.cpp
@@ -4443,7 +4443,7 @@ ScalarEvolution::createAddRecFromPHIWithCastsImpl(const SCEVUnknown *SymbolicPHI
// varying inside the loop.
if (!isLoopInvariant(Accum, L))
return None;
-
+
// *** Part2: Create the predicates
// Analysis was successful: we have a phi-with-cast pattern for which we
@@ -4493,27 +4493,71 @@ ScalarEvolution::createAddRecFromPHIWithCastsImpl(const SCEVUnknown *SymbolicPHI
//
// By induction, the same applies to all iterations 1<=i<n:
//
-
+
// Create a truncated addrec for which we will add a no overflow check (P1).
const SCEV *StartVal = getSCEV(StartValueV);
- const SCEV *PHISCEV =
+ const SCEV *PHISCEV =
getAddRecExpr(getTruncateExpr(StartVal, TruncTy),
- getTruncateExpr(Accum, TruncTy), L, SCEV::FlagAnyWrap);
- const auto *AR = cast<SCEVAddRecExpr>(PHISCEV);
+ getTruncateExpr(Accum, TruncTy), L, SCEV::FlagAnyWrap);
- SCEVWrapPredicate::IncrementWrapFlags AddedFlags =
- Signed ? SCEVWrapPredicate::IncrementNSSW
- : SCEVWrapPredicate::IncrementNUSW;
- const SCEVPredicate *AddRecPred = getWrapPredicate(AR, AddedFlags);
- Predicates.push_back(AddRecPred);
+ // PHISCEV can be either a SCEVConstant or a SCEVAddRecExpr.
+ // ex: If truncated Accum is 0 and StartVal is a constant, then PHISCEV
+ // will be constant.
+ //
+ // If PHISCEV is a constant, then P1 degenerates into P2 or P3, so we don't
+ // add P1.
+ if (const auto *AR = dyn_cast<SCEVAddRecExpr>(PHISCEV)) {
+ SCEVWrapPredicate::IncrementWrapFlags AddedFlags =
+ Signed ? SCEVWrapPredicate::IncrementNSSW
+ : SCEVWrapPredicate::IncrementNUSW;
+ const SCEVPredicate *AddRecPred = getWrapPredicate(AR, AddedFlags);
+ Predicates.push_back(AddRecPred);
+ } else
+ assert(isa<SCEVConstant>(PHISCEV) && "Expected constant SCEV");
// Create the Equal Predicates P2,P3:
- auto AppendPredicate = [&](const SCEV *Expr) -> void {
+
+ // It is possible that the predicates P2 and/or P3 are computable at
+ // compile time due to StartVal and/or Accum being constants.
+ // If either one is, then we can check that now and escape if either P2
+ // or P3 is false.
+
+ // Construct the extended SCEV: (Ext ix (Trunc iy (Expr) to ix) to iy)
+ // for each of StartVal and Accum
+ auto GetExtendedExpr = [&](const SCEV *Expr) -> const SCEV * {
assert(isLoopInvariant(Expr, L) && "Expr is expected to be invariant");
const SCEV *TruncatedExpr = getTruncateExpr(Expr, TruncTy);
const SCEV *ExtendedExpr =
Signed ? getSignExtendExpr(TruncatedExpr, Expr->getType())
: getZeroExtendExpr(TruncatedExpr, Expr->getType());
+ return ExtendedExpr;
+ };
+
+ // Given:
+ // ExtendedExpr = (Ext ix (Trunc iy (Expr) to ix) to iy
+ // = GetExtendedExpr(Expr)
+ // Determine whether the predicate P: Expr == ExtendedExpr
+ // is known to be false at compile time
+ auto PredIsKnownFalse = [&](const SCEV *Expr,
+ const SCEV *ExtendedExpr) -> bool {
+ return Expr != ExtendedExpr &&
+ isKnownPredicate(ICmpInst::ICMP_NE, Expr, ExtendedExpr);
+ };
+
+ const SCEV *StartExtended = GetExtendedExpr(StartVal);
+ if (PredIsKnownFalse(StartVal, StartExtended)) {
+ DEBUG(dbgs() << "P2 is compile-time false\n";);
+ return None;
+ }
+
+ const SCEV *AccumExtended = GetExtendedExpr(Accum);
+ if (PredIsKnownFalse(Accum, AccumExtended)) {
+ DEBUG(dbgs() << "P3 is compile-time false\n";);
+ return None;
+ }
+
+ auto AppendPredicate = [&](const SCEV *Expr,
+ const SCEV *ExtendedExpr) -> void {
if (Expr != ExtendedExpr &&
!isKnownPredicate(ICmpInst::ICMP_EQ, Expr, ExtendedExpr)) {
const SCEVPredicate *Pred = getEqualPredicate(Expr, ExtendedExpr);
@@ -4521,10 +4565,10 @@ ScalarEvolution::createAddRecFromPHIWithCastsImpl(const SCEVUnknown *SymbolicPHI
Predicates.push_back(Pred);
}
};
-
- AppendPredicate(StartVal);
- AppendPredicate(Accum);
-
+
+ AppendPredicate(StartVal, StartExtended);
+ AppendPredicate(Accum, AccumExtended);
+
// *** Part3: Predicates are ready. Now go ahead and create the new addrec in
// which the casts had been folded away. The caller can rewrite SymbolicPHI
// into NewAR if it will also add the runtime overflow checks specified in