[llvm] [VPlan] Verify and handle FOR legality during header phi creation (NFC). (PR #191298)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 08:25:29 PDT 2026


================
@@ -763,6 +919,50 @@ void VPlanTransforms::createHeaderPhiRecipes(
     PhiR->eraseFromParent();
   }
 
+  // Sink users of fixed-order recurrences past the recipe defining the
+  // previous value, introduce FirstOrderRecurrenceSplice VPInstructions, and
+  // replace FOR uses. At VPlan0, the VPlan mirrors the scalar IR, so the
+  // legality check (sink/hoist) is guaranteed to succeed by
+  // isFixedOrderRecurrence.
+  VPBuilder LoopBuilder;
+  for (VPRecipeBase &R : HeaderVPBB->phis()) {
+    auto *FOR = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&R);
+    if (!FOR)
+      continue;
+
+    // Follow through FOR phi chains to find the actual Previous recipe.
+    // Fixed-order recurrences do not contain cycles, so this loop is
+    // guaranteed to terminate.
+    SmallPtrSet<VPFirstOrderRecurrencePHIRecipe *, 4> SeenPhis;
+    VPRecipeBase *Previous = FOR->getBackedgeValue()->getDefiningRecipe();
+    while (auto *PrevPhi =
+               dyn_cast_or_null<VPFirstOrderRecurrencePHIRecipe>(Previous)) {
+      assert(PrevPhi->getParent() == FOR->getParent());
+      assert(SeenPhis.insert(PrevPhi).second);
+      Previous = PrevPhi->getBackedgeValue()->getDefiningRecipe();
+    }
+
+    // Sink FOR users after Previous or hoist Previous before FOR users.
+    if (!sinkRecurrenceUsersAfterPrevious(FOR, Previous, VPDT) &&
+        !hoistPreviousBeforeFORUsers(FOR, Previous, VPDT))
+      return false;
+
+    // Create FirstOrderRecurrenceSplice and replace FOR uses.
+    VPBasicBlock *InsertBlock =
+        Previous ? Previous->getParent() : FOR->getParent();
+    auto InsertPt = (!Previous || isa<VPHeaderPHIRecipe>(Previous))
+                        ? InsertBlock->getFirstNonPhi()
+                        : std::next(Previous->getIterator());
+    LoopBuilder.setInsertPoint(InsertBlock, InsertPt);
+
+    auto *RecurSplice =
+        LoopBuilder.createNaryOp(VPInstruction::FirstOrderRecurrenceSplice,
+                                 {FOR, FOR->getBackedgeValue()});
+    FOR->replaceUsesWithIf(RecurSplice, [RecurSplice](VPUser &U, unsigned) {
+      return &U != RecurSplice;
+    });
+  }
+
----------------
fhahn wrote:

Yep, moved thanks

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


More information about the llvm-commits mailing list