[llvm] [VPlan] Move IV predicate handling to VPlan. (PR #192876)

via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 19 14:41:12 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

Update induction SCEV predicate handling to track the SCEV predicates required for a induction in IVDescriptor directly. This allows moving the AllowedExit check to VPlan and tracking predicates per induction allows for more accurate decisions in follow-up patches.

For example, in some cases, the same phi could either be a fixed-order recurrence or an induction with predicates. This will allow more aggressively converting phis to fixed-order recurrences in VPlan, while still being able to gracefully handle the fall back when predicated inductions are needed.

Note that this also moves checking the SCEV predicate thresholds. This catches additional cases we missed before, because predicates were added after we performed the check in Legal.

---

Patch is 67.83 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/192876.diff


13 Files Affected:

- (modified) llvm/include/llvm/Analysis/IVDescriptors.h (+12-5) 
- (modified) llvm/include/llvm/Analysis/ScalarEvolution.h (+8-4) 
- (modified) llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h (+1-6) 
- (modified) llvm/lib/Analysis/IVDescriptors.cpp (+25-13) 
- (modified) llvm/lib/Analysis/ScalarEvolution.cpp (+15-8) 
- (modified) llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp (+7-92) 
- (modified) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp (+24) 
- (modified) llvm/lib/Transforms/Vectorize/VPlan.h (+6) 
- (modified) llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp (+67) 
- (modified) llvm/lib/Transforms/Vectorize/VPlanTransforms.h (+10) 
- (modified) llvm/test/Transforms/LoopVectorize/VPlan/vplan-print-after-all.ll (+1) 
- (modified) llvm/test/Transforms/LoopVectorize/induction.ll (+32-32) 
- (modified) llvm/test/Transforms/LoopVectorize/predicated-inductions.ll (+259-100) 


``````````diff
diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h
index 8383da0f9e879..5e3d34b815886 100644
--- a/llvm/include/llvm/Analysis/IVDescriptors.h
+++ b/llvm/include/llvm/Analysis/IVDescriptors.h
@@ -28,6 +28,7 @@ class Loop;
 class PredicatedScalarEvolution;
 class ScalarEvolution;
 class SCEV;
+class SCEVPredicate;
 class StoreInst;
 
 /// These are the kinds of recurrences that we support.
@@ -395,10 +396,10 @@ class InductionDescriptor {
   /// analysis, it can be passed through \p Expr. If the def-use chain
   /// associated with the phi includes casts (that we know we can ignore
   /// under proper runtime checks), they are passed through \p CastsToIgnore.
-  LLVM_ABI static bool
-  isInductionPHI(PHINode *Phi, const Loop *L, ScalarEvolution *SE,
-                 InductionDescriptor &D, const SCEV *Expr = nullptr,
-                 SmallVectorImpl<Instruction *> *CastsToIgnore = nullptr);
+  LLVM_ABI static bool isInductionPHI(
+      PHINode *Phi, const Loop *L, ScalarEvolution *SE, InductionDescriptor &D,
+      ArrayRef<const SCEVPredicate *> Preds = {}, const SCEV *Expr = nullptr,
+      SmallVectorImpl<Instruction *> *CastsToIgnore = nullptr);
 
   /// Returns true if \p Phi is a floating point induction in the loop \p L.
   /// If \p Phi is an induction, the induction descriptor \p D will contain
@@ -439,11 +440,15 @@ class InductionDescriptor {
   /// SCEV overflow check.
   ArrayRef<Instruction *> getCastInsts() const { return RedundantCasts; }
 
+  /// Returns the SCEV predicates associated with this induction.
+  ArrayRef<const SCEVPredicate *> getPredicates() const { return Predicates; }
+
 private:
   /// Private constructor - used by \c isInductionPHI.
   InductionDescriptor(Value *Start, InductionKind K, const SCEV *Step,
                       BinaryOperator *InductionBinOp = nullptr,
-                      SmallVectorImpl<Instruction *> *Casts = nullptr);
+                      SmallVectorImpl<Instruction *> *Casts = nullptr,
+                      ArrayRef<const SCEVPredicate *> Preds = {});
 
   /// Start value.
   TrackingVH<Value> StartValue;
@@ -456,6 +461,8 @@ class InductionDescriptor {
   // Instructions used for type-casts of the induction variable,
   // that are redundant when guarded with a runtime SCEV overflow check.
   SmallVector<Instruction *, 2> RedundantCasts;
+  // SCEV predicates (overflow checks) needed for this induction.
+  SmallVector<const SCEVPredicate *, 2> Predicates;
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 5c01da0855f66..c85d57aa270db 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -2631,8 +2631,11 @@ class PredicatedScalarEvolution {
   /// Attempts to produce an AddRecExpr for V by adding additional SCEV
   /// predicates. If we can't transform the expression into an AddRecExpr we
   /// return nullptr and not add additional SCEV predicates to the current
-  /// context.
-  LLVM_ABI const SCEVAddRecExpr *getAsAddRec(Value *V);
+  /// context. If \p ExtraPreds is non-null, the required predicates are
+  /// collected there instead of being added to this context.
+  LLVM_ABI const SCEVAddRecExpr *
+  getAsAddRec(Value *V,
+              SmallVectorImpl<const SCEVPredicate *> *ExtraPreds = nullptr);
 
   /// Proves that V doesn't overflow by adding SCEV predicate.
   LLVM_ABI void setNoOverflow(Value *V,
@@ -2655,8 +2658,9 @@ class PredicatedScalarEvolution {
 
   /// Check if \p AR1 and \p AR2 are equal, while taking into account
   /// Equal predicates in Preds.
-  LLVM_ABI bool areAddRecsEqualWithPreds(const SCEVAddRecExpr *AR1,
-                                         const SCEVAddRecExpr *AR2) const;
+  LLVM_ABI bool areAddRecsEqualWithPreds(
+      const SCEVAddRecExpr *AR1, const SCEVAddRecExpr *AR2,
+      ArrayRef<const SCEVPredicate *> ExtraPreds = {}) const;
 
 private:
   /// Increments the version number of the predicate.  This needs to be called
diff --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
index cff9162e39f60..e1543e2f39ddf 100644
--- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
+++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
@@ -644,8 +644,7 @@ class LoopVectorizationLegality {
   /// Updates the vectorization state by adding \p Phi to the inductions list.
   /// This can set \p Phi as the main induction of the loop if \p Phi is a
   /// better choice for the main induction than the existing one.
-  void addInductionPhi(PHINode *Phi, const InductionDescriptor &ID,
-                       SmallPtrSetImpl<Value *> &AllowedExit);
+  void addInductionPhi(PHINode *Phi, const InductionDescriptor &ID);
 
   /// The loop that we evaluate.
   Loop *TheLoop;
@@ -703,10 +702,6 @@ class LoopVectorizationLegality {
   /// Holds the widest induction type encountered.
   IntegerType *WidestIndTy = nullptr;
 
-  /// Allowed outside users. This holds the variables that can be accessed from
-  /// outside the loop.
-  SmallPtrSet<Value *, 4> AllowedExit;
-
   /// Vectorization requirements that will go through late-evaluation.
   LoopVectorizationRequirements *Requirements;
 
diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp
index 185943e0a9d2e..4762ad39aee88 100644
--- a/llvm/lib/Analysis/IVDescriptors.cpp
+++ b/llvm/lib/Analysis/IVDescriptors.cpp
@@ -1357,7 +1357,8 @@ RecurrenceDescriptor::getReductionOpChain(PHINode *Phi, Loop *L) const {
 
 InductionDescriptor::InductionDescriptor(Value *Start, InductionKind K,
                                          const SCEV *Step, BinaryOperator *BOp,
-                                         SmallVectorImpl<Instruction *> *Casts)
+                                         SmallVectorImpl<Instruction *> *Casts,
+                                         ArrayRef<const SCEVPredicate *> Preds)
     : StartValue(Start), IK(K), Step(Step), InductionBinOp(BOp) {
   assert(IK != IK_NoInduction && "Not an induction");
 
@@ -1386,6 +1387,7 @@ InductionDescriptor::InductionDescriptor(Value *Start, InductionKind K,
 
   if (Casts)
     llvm::append_range(RedundantCasts, *Casts);
+  llvm::append_range(Predicates, Preds);
 }
 
 ConstantInt *InductionDescriptor::getConstIntStepValue() const {
@@ -1482,11 +1484,11 @@ bool InductionDescriptor::isFPInductionPHI(PHINode *Phi, const Loop *TheLoop,
 static bool getCastsForInductionPHI(PredicatedScalarEvolution &PSE,
                                     const SCEVUnknown *PhiScev,
                                     const SCEVAddRecExpr *AR,
-                                    SmallVectorImpl<Instruction *> &CastInsts) {
+                                    SmallVectorImpl<Instruction *> &CastInsts,
+                                    ArrayRef<const SCEVPredicate *> Preds) {
 
   assert(CastInsts.empty() && "CastInsts is expected to be empty.");
   auto *PN = cast<PHINode>(PhiScev->getValue());
-  assert(PSE.getSCEV(PN) == AR && "Unexpected phi node SCEV expression");
   const Loop *L = AR->getLoop();
 
   // Find any cast instructions that participate in the def-use chain of
@@ -1520,6 +1522,11 @@ static bool getCastsForInductionPHI(PredicatedScalarEvolution &PSE,
   if (!Val)
     return false;
 
+  // Build a predicate to rewrite SCEVs of values in the cast chain using the
+  // predicates needed for this induction.
+  ScalarEvolution &SE = *PSE.getSE();
+  SCEVUnionPredicate Pred(Preds, SE);
+
   // Follow the def-use chain until the induction phi is reached.
   // If on the way we encounter a Value that has the same SCEV Expr as the
   // phi node, we can consider the instructions we visit from that point
@@ -1532,8 +1539,9 @@ static bool getCastsForInductionPHI(PredicatedScalarEvolution &PSE,
     if (!Inst || !L->contains(Inst)) {
       return false;
     }
-    auto *AddRec = dyn_cast<SCEVAddRecExpr>(PSE.getSCEV(Val));
-    if (AddRec && PSE.areAddRecsEqualWithPreds(AddRec, AR))
+    auto *AddRec = dyn_cast<SCEVAddRecExpr>(
+        SE.rewriteUsingPredicate(SE.getSCEV(Val), L, Pred));
+    if (AddRec && PSE.areAddRecsEqualWithPreds(AddRec, AR, Preds))
       InCastSequence = true;
     if (InCastSequence) {
       // Only the last instruction in the cast sequence is expected to have
@@ -1571,9 +1579,12 @@ bool InductionDescriptor::isInductionPHI(PHINode *Phi, const Loop *TheLoop,
   const SCEV *PhiScev = PSE.getSCEV(Phi);
   const auto *AR = dyn_cast<SCEVAddRecExpr>(PhiScev);
 
+  // Collect predicates needed to force the SCEV into an AddRecExpr.
+  SmallVector<const SCEVPredicate *, 2> Preds;
+
   // We need this expression to be an AddRecExpr.
   if (Assume && !AR)
-    AR = PSE.getAsAddRec(Phi);
+    AR = PSE.getAsAddRec(Phi, &Preds);
 
   if (!AR) {
     LLVM_DEBUG(dbgs() << "LV: PHI is not a poly recurrence.\n");
@@ -1589,17 +1600,17 @@ bool InductionDescriptor::isInductionPHI(PHINode *Phi, const Loop *TheLoop,
   // induction.
   if (PhiScev != AR && SymbolicPhi) {
     SmallVector<Instruction *, 2> Casts;
-    if (getCastsForInductionPHI(PSE, SymbolicPhi, AR, Casts))
-      return isInductionPHI(Phi, TheLoop, PSE.getSE(), D, AR, &Casts);
+    if (getCastsForInductionPHI(PSE, SymbolicPhi, AR, Casts, Preds))
+      return isInductionPHI(Phi, TheLoop, PSE.getSE(), D, Preds, AR, &Casts);
   }
 
-  return isInductionPHI(Phi, TheLoop, PSE.getSE(), D, AR);
+  return isInductionPHI(Phi, TheLoop, PSE.getSE(), D, Preds, AR);
 }
 
 bool InductionDescriptor::isInductionPHI(
     PHINode *Phi, const Loop *TheLoop, ScalarEvolution *SE,
-    InductionDescriptor &D, const SCEV *Expr,
-    SmallVectorImpl<Instruction *> *CastsToIgnore) {
+    InductionDescriptor &D, ArrayRef<const SCEVPredicate *> Preds,
+    const SCEV *Expr, SmallVectorImpl<Instruction *> *CastsToIgnore) {
   Type *PhiTy = Phi->getType();
   // isSCEVable returns true for integer and pointer types.
   if (!SE->isSCEVable(PhiTy))
@@ -1639,13 +1650,14 @@ bool InductionDescriptor::isInductionPHI(
     BinaryOperator *BOp =
         dyn_cast<BinaryOperator>(Phi->getIncomingValueForBlock(Latch));
     D = InductionDescriptor(StartValue, IK_IntInduction, Step, BOp,
-                            CastsToIgnore);
+                            CastsToIgnore, Preds);
     return true;
   }
 
   assert(PhiTy->isPointerTy() && "The PHI must be a pointer");
 
   // This allows induction variables w/non-constant steps.
-  D = InductionDescriptor(StartValue, IK_PtrInduction, Step);
+  D = InductionDescriptor(StartValue, IK_PtrInduction, Step,
+                          /*InductionBinOp=*/nullptr, /*Casts=*/nullptr, Preds);
   return true;
 }
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 9f362deb7cca9..535ebf6c1cc66 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -5863,16 +5863,17 @@ ScalarEvolution::createAddRecFromPHIWithCasts(const SCEVUnknown *SymbolicPHI) {
 // even when the following Equal predicate exists:
 // "%step == (sext ix (trunc iy to ix) to iy)".
 bool PredicatedScalarEvolution::areAddRecsEqualWithPreds(
-    const SCEVAddRecExpr *AR1, const SCEVAddRecExpr *AR2) const {
+    const SCEVAddRecExpr *AR1, const SCEVAddRecExpr *AR2,
+    ArrayRef<const SCEVPredicate *> ExtraPreds) const {
   if (AR1 == AR2)
     return true;
 
-  auto areExprsEqual = [&](const SCEV *Expr1, const SCEV *Expr2) -> bool {
-    if (Expr1 != Expr2 &&
-        !Preds->implies(SE.getEqualPredicate(Expr1, Expr2), SE) &&
-        !Preds->implies(SE.getEqualPredicate(Expr2, Expr1), SE))
-      return false;
-    return true;
+  SCEVUnionPredicate ExtraPred(ExtraPreds, SE);
+  SCEVUnionPredicate AllPreds = Preds->getUnionWith(&ExtraPred, SE);
+  auto areExprsEqual = [&](const SCEV *Expr1, const SCEV *Expr2) {
+    return Expr1 == Expr2 ||
+           AllPreds.implies(SE.getEqualPredicate(Expr1, Expr2), SE) ||
+           AllPreds.implies(SE.getEqualPredicate(Expr2, Expr1), SE);
   };
 
   if (!areExprsEqual(AR1->getStart(), AR2->getStart()) ||
@@ -15595,7 +15596,8 @@ bool PredicatedScalarEvolution::hasNoOverflow(
   return Flags == SCEVWrapPredicate::IncrementAnyWrap;
 }
 
-const SCEVAddRecExpr *PredicatedScalarEvolution::getAsAddRec(Value *V) {
+const SCEVAddRecExpr *PredicatedScalarEvolution::getAsAddRec(
+    Value *V, SmallVectorImpl<const SCEVPredicate *> *ExtraPreds) {
   const SCEV *Expr = this->getSCEV(V);
   SmallVector<const SCEVPredicate *, 4> NewPreds;
   auto *New = SE.convertSCEVToAddRecWithPredicates(Expr, &L, NewPreds);
@@ -15603,6 +15605,11 @@ const SCEVAddRecExpr *PredicatedScalarEvolution::getAsAddRec(Value *V) {
   if (!New)
     return nullptr;
 
+  if (ExtraPreds) {
+    ExtraPreds->append(NewPreds);
+    return New;
+  }
+
   for (const auto *P : NewPreds)
     addPredicate(*P);
 
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 07e6780d9e7ba..1ea08ad9e2892 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -51,17 +51,6 @@ static cl::opt<bool>
                          cl::desc("Allow enabling loop hints to reorder "
                                   "FP operations during vectorization."));
 
-// TODO: Move size-based thresholds out of legality checking, make cost based
-// decisions instead of hard thresholds.
-static cl::opt<unsigned> VectorizeSCEVCheckThreshold(
-    "vectorize-scev-check-threshold", cl::init(16), cl::Hidden,
-    cl::desc("The maximum number of SCEV checks allowed."));
-
-static cl::opt<unsigned> PragmaVectorizeSCEVCheckThreshold(
-    "pragma-vectorize-scev-check-threshold", cl::init(128), cl::Hidden,
-    cl::desc("The maximum number of SCEV checks allowed with a "
-             "vectorize(enable) pragma"));
-
 static cl::opt<LoopVectorizeHints::ScalableForceKind>
     ForceScalableVectorization(
         "scalable-vectorization", cl::init(LoopVectorizeHints::SK_Unspecified),
@@ -436,25 +425,6 @@ static IntegerType *getWiderInductionTy(const DataLayout &DL, Type *Ty0,
   return TyA->getScalarSizeInBits() > TyB->getScalarSizeInBits() ? TyA : TyB;
 }
 
-/// Check that the instruction has outside loop users and is not an
-/// identified reduction variable.
-static bool hasOutsideLoopUser(const Loop *TheLoop, Instruction *Inst,
-                               SmallPtrSetImpl<Value *> &AllowedExit) {
-  // Reductions, Inductions and non-header phis are allowed to have exit users. All
-  // other instructions must not have external users.
-  if (!AllowedExit.count(Inst))
-    // Check that all of the users of the loop are inside the BB.
-    for (User *U : Inst->users()) {
-      Instruction *UI = cast<Instruction>(U);
-      // This user may be a reduction exit value.
-      if (!TheLoop->contains(UI)) {
-        LLVM_DEBUG(dbgs() << "LV: Found an outside user for : " << *UI << '\n');
-        return true;
-      }
-    }
-  return false;
-}
-
 /// Returns true if A and B have same pointer operands or same SCEVs addresses
 static bool storeToSameAddress(ScalarEvolution *SE, StoreInst *A,
                                StoreInst *B) {
@@ -697,9 +667,8 @@ bool LoopVectorizationLegality::canVectorizeOuterLoop() {
   return Result;
 }
 
-void LoopVectorizationLegality::addInductionPhi(
-    PHINode *Phi, const InductionDescriptor &ID,
-    SmallPtrSetImpl<Value *> &AllowedExit) {
+void LoopVectorizationLegality::addInductionPhi(PHINode *Phi,
+                                                const InductionDescriptor &ID) {
   Inductions[Phi] = ID;
 
   // In case this induction also comes with casts that we know we can ignore
@@ -738,17 +707,6 @@ void LoopVectorizationLegality::addInductionPhi(
       PrimaryInduction = Phi;
   }
 
-  // Both the PHI node itself, and the "post-increment" value feeding
-  // back into the PHI node may have external users.
-  // We can allow those uses, except if the SCEVs we have for them rely
-  // on predicates that only hold within the loop, since allowing the exit
-  // currently means re-using this SCEV outside the loop (see PR33706 for more
-  // details).
-  if (PSE.getPredicate().isAlwaysTrue()) {
-    AllowedExit.insert(Phi);
-    AllowedExit.insert(Phi->getIncomingValueForBlock(TheLoop->getLoopLatch()));
-  }
-
   LLVM_DEBUG(dbgs() << "LV: Found an induction variable.\n");
 }
 
@@ -760,7 +718,7 @@ bool LoopVectorizationLegality::setupOuterLoopInductions() {
     InductionDescriptor ID;
     if (InductionDescriptor::isInductionPHI(&Phi, TheLoop, PSE, ID) &&
         ID.getKind() == InductionDescriptor::IK_IntInduction) {
-      addInductionPhi(&Phi, ID, AllowedExit);
+      addInductionPhi(&Phi, ID);
       return true;
     }
     // Bail out for any Phi in the outer loop header that is not a supported
@@ -868,7 +826,6 @@ bool LoopVectorizationLegality::canVectorizeInstr(Instruction &I) {
       // Unsafe cyclic dependencies with header phis are identified during
       // legalization for reduction, induction and fixed order
       // recurrences.
-      AllowedExit.insert(&I);
       return true;
     }
 
@@ -885,7 +842,6 @@ bool LoopVectorizationLegality::canVectorizeInstr(Instruction &I) {
     if (RecurrenceDescriptor::isReductionPHI(Phi, TheLoop, RedDes, DB, AC, DT,
                                              PSE.getSE())) {
       Requirements->addExactFPMathInst(RedDes.getExactFPMathInst());
-      AllowedExit.insert(RedDes.getLoopExitInstr());
       Reductions[Phi] = std::move(RedDes);
       assert((!RedDes.hasUsesOutsideReductionChain() ||
               RecurrenceDescriptor::isMinMaxRecurrenceKind(
@@ -907,30 +863,21 @@ bool LoopVectorizationLegality::canVectorizeInstr(Instruction &I) {
                  ID.getConstIntStepValue() == nullptr;
         };
 
-    // TODO: Instead of recording the AllowedExit, it would be good to
-    // record the complementary set: NotAllowedExit. These include (but may
-    // not be limited to):
     // 1. Reduction phis as they represent the one-before-last value, which
     // is not available when vectorized
     // 2. Induction phis and increment when SCEV predicates cannot be used
-    // outside the loop - see addInductionPhi
-    // 3. Non-Phis with outside uses when SCEV predicates cannot be used
-    // outside the loop - see call to hasOutsideLoopUser in the non-phi
-    // handling below
-    // 4. FixedOrderRecurrence phis that can possibly be handled by
+    // outside the loop - see finalizeSCEVPredicates
+    // 3. FixedOrderRecurrence phis that can possibly be handled by
     // extraction.
-    // By recording these, we can then reason about ways to vectorize each
-    // of these NotAllowedExit.
     InductionDescriptor ID;
     if (InductionDescriptor::isInductionPHI(Phi, TheLoop, PSE, ID) &&
         !IsDisallowedStridedPointerInduction(ID)) {
-      addInductionPhi(Phi, ID, AllowedExit);
+      addInductionPhi(Phi, ID);
       Requirements->addExactFPMathInst(ID.getExactFPMathInst());
       return true;
     }
 
     if (RecurrenceDescriptor::isFixedOrderRecurrence(Phi, TheLoop, DT)) {
-      AllowedExit.insert(Phi);
       FixedOrderRecurrences.insert(Phi);
       return true;
     }
@@ -939,7 +886,7 @@ bool LoopVectorizationLegality::canVectorizeInstr(Instruction &I) {
     // and re-try classifying it a an induction PHI.
     if (InductionDescriptor::isInductionPHI(Phi, TheLoop, PSE, ID, true) &&
         !IsDisallowedStridedPointerInduction(ID)) {
-      addInductionPhi(Phi, ID, AllowedExit);
+      addInductionPhi(Phi, ID);
       return true;
     }
 
@@ -1082,22 +1029,6 @@ bool LoopVectorizationLegality::canVectorizeInstr(Instruction &I) {
     Hints->setPotentiallyUnsafe();
   }
 
-  // Reduction instructions are allowed to have exit users.
-  // All other instructions must not have external users.
-  if (hasOutsideLoopUser(TheLoop, &I, AllowedExit)) {
-    // We can safely vectorize loops where instructions within the loop are
-    // used outside the loop only if the SCEV predicates within the loop is
-    // same as outside the loop. Allowing the exit means reusing the SCEV
-    // outside the loop.
-    if (PSE.getPredicate().isAlwaysTrue()) {
-      AllowedExit.insert(&I);
-      return true;
-  ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/192876


More information about the llvm-commits mailing list