[SCEV] Use trivial bound on defining scope of all SCEVs when computing flags
authorPhilip Reames <listmail@philipreames.com>
Sun, 3 Oct 2021 23:01:30 +0000 (16:01 -0700)
committerPhilip Reames <listmail@philipreames.com>
Sun, 3 Oct 2021 23:01:30 +0000 (16:01 -0700)
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.

llvm/include/llvm/Analysis/ScalarEvolution.h
llvm/lib/Analysis/ScalarEvolution.cpp
llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll

index b9b5450..c3ee802 100644 (file)
@@ -1920,10 +1920,10 @@ private:
   /// 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.
index 70bf9ae..f9d7ff2 100644 (file)
@@ -2804,10 +2804,8 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
       // 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);
@@ -6586,17 +6584,14 @@ SCEV::NoWrapFlags ScalarEvolution::getNoWrapFlagsFromUB(const Value *V) {
   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
@@ -6657,9 +6652,9 @@ bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) {
     // 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;
 }
index 5ab2415..4319475 100644 (file)
@@ -1328,7 +1328,7 @@ define void @test-sub-no-nsw(float* %input, i32 %start, i32 %sub, i32 %numIterat
 ; 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
@@ -1369,7 +1369,7 @@ define void @test-sub-nsw(float* %input, i32 %start, i32 %sub, i32 %numIteration
 ; 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