[llvm] [VPlan] Extract reverse operation for reverse accesses (PR #146525)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 04:48:00 PST 2025


================
@@ -2866,28 +2867,42 @@ static void transformRecipestoEVLRecipes(VPlan &Plan, VPValue &EVL) {
         TypeInfo.inferScalarType(MaxEVL), DebugLoc::getUnknown());
 
     Builder.setInsertPoint(Header, Header->getFirstNonPhi());
-    VPValue *PrevEVL = Builder.createScalarPhi(
-        {MaxEVL, &EVL}, DebugLoc::getUnknown(), "prev.evl");
-
-    for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
-             vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) {
-      for (VPRecipeBase &R : *VPBB) {
-        VPValue *V1, *V2;
-        if (!match(&R,
-                   m_VPInstruction<VPInstruction::FirstOrderRecurrenceSplice>(
-                       m_VPValue(V1), m_VPValue(V2))))
-          continue;
+    PrevEVL = Builder.createScalarPhi({MaxEVL, &EVL}, DebugLoc::getUnknown(),
+                                      "prev.evl");
+  }
+
+  // Transform the recipes must be converted to vector predication intrinsics
+  // even if they do not use header mask.
+  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
+           vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) {
+    for (VPRecipeBase &R : *VPBB) {
+      VPWidenIntrinsicRecipe *NewRecipe = nullptr;
+      VPValue *V1, *V2;
+      if (match(&R, m_VPInstruction<VPInstruction::FirstOrderRecurrenceSplice>(
+                        m_VPValue(V1), m_VPValue(V2)))) {
         VPValue *Imm = Plan.getOrAddLiveIn(
             ConstantInt::getSigned(Type::getInt32Ty(Plan.getContext()), -1));
-        VPWidenIntrinsicRecipe *VPSplice = new VPWidenIntrinsicRecipe(
+        NewRecipe = new VPWidenIntrinsicRecipe(
             Intrinsic::experimental_vp_splice,
             {V1, V2, Imm, Plan.getTrue(), PrevEVL, &EVL},
             TypeInfo.inferScalarType(R.getVPSingleValue()), {}, {},
             R.getDebugLoc());
-        VPSplice->insertBefore(&R);
-        R.getVPSingleValue()->replaceAllUsesWith(VPSplice);
-        ToErase.push_back(&R);
       }
+
+      // TODO: Only convert reverse to vp.reverse if it uses the result of
+      // vp.load, or defines the stored value of vp.store.
----------------
fhahn wrote:

> Unconditionally replacing all the reverses to vp.reverses here means that optimizeMaskToEVL is no longer correct:

I think that's kind-of already the case, right? Until all recipes are converted, the intermediate VPlan may be partially incorrect.

For both approaches correctness boils down to whether the reverse is tied to the load/store currently. I would like to avoid correctness to depend on the exact position of the reverse. We could move the vp.reverse introduction after EVL load/store recipe creation, then asserting that the only operand/user are EVL load/store recipes. 

This makes me wonder if it would be easier to avoid adding them up front, but only 'materialize' the reverse operations after EVL recipes have been introduced (then we can convert `VPWidenLoadR ,reverse = true- > vp.reverse(VPWidenLoadEVLR...) ` atomically.

And then just separately materialize reverse() for plain VPWidenLoad/StoreR separately, possibly for now just in `convertToConcreteRecipes`.


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


More information about the llvm-commits mailing list