[llvm] [VPlan] Wrap SCEVAddRecExprs in VPExpandSCEVRecipe in VPSCEVExpander. (PR #210013)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 06:09:29 PDT 2026


================
@@ -873,22 +876,37 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
       llvm_unreachable("Unexpected min/max SCEV type");
     }
     // Chain operands in reverse order matching SCEVExpander's expansion of
-    // min/max expressions.
-    SmallVector<VPValue *, 2> Ops;
-    for (const SCEVUse &Op : reverse(MinMax->operands())) {
-      VPValue *OpV = tryToExpand(Op);
-      if (!OpV)
-        return nullptr;
-      Ops.push_back(OpV);
-    }
+    // min/max expressions. In SafeUDivMode freeze expansion results of operands
+    // other than the first for sequential UMins, to avoid short-circuiting
+    // divide-by-0/poison.
+    bool IsSequential = S->getSCEVType() == scSequentialUMinExpr;
     Type *ResultTy = MinMax->getType();
-    VPValue *Result = Ops.front();
-    for (VPValue *Op : drop_begin(Ops))
-      Result = Builder.createScalarIntrinsic(IntrinsicID, {Result, Op},
-                                             ResultTy, DL);
+    bool PrevSafeMode = SafeUDivMode;
+    VPValue *Result = nullptr;
+    for (const auto &[I, SCEVOp] : enumerate(reverse(MinMax->operands()))) {
+      bool MayShortCircuit = IsSequential && I != MinMax->getNumOperands() - 1;
+      SafeUDivMode = MayShortCircuit || PrevSafeMode;
+      VPValue *Op = expand(SCEVOp);
+      SafeUDivMode = PrevSafeMode;
+      if (MayShortCircuit)
+        Op = Builder.createScalarFreeze(Op, ResultTy, DL);
+      Result = Result ? Builder.createScalarIntrinsic(IntrinsicID, {Result, Op},
+                                                      ResultTy, DL)
+                      : Op;
+    }
     return Result;
   }
-  default:
-    return nullptr;
+  case scAddRecExpr: {
+    [[maybe_unused]] BasicBlock *PH =
+        cast<VPIRBasicBlock>(Builder.getPlan().getEntry())->getIRBasicBlock();
+    assert(
+        SE.DT.dominates(cast<SCEVAddRecExpr>(S)->getLoop()->getHeader(), PH) &&
+        "can only expand AddRecs for loops outside VPlan's scope");
+    // AddRecs outside VPlan's scope must be expanded via VPExpandSCEV.
----------------
artagnon wrote:

In fact, if the AR's loop header refers to a BasicBlock that's completely absent in the Plan, there would be no point expanding it, as the expansion would target a BasicBlock that we don't emit (we only ever execute the Plan?).

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


More information about the llvm-commits mailing list