[llvm] 0a45515 - [VPlan][NFC] Simplify reverse access pattern detection in EVL vectorization (#199510)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 01:56:46 PDT 2026
Author: Mel Chen
Date: 2026-06-10T08:56:41Z
New Revision: 0a45515e9e386233970b56b34a65d7442ac37e5f
URL: https://github.com/llvm/llvm-project/commit/0a45515e9e386233970b56b34a65d7442ac37e5f
DIFF: https://github.com/llvm/llvm-project/commit/0a45515e9e386233970b56b34a65d7442ac37e5f.diff
LOG: [VPlan][NFC] Simplify reverse access pattern detection in EVL vectorization (#199510)
This PR demonstrates how to decouple the transformation of reverse
accesses during `VPlanTransforms::optimizeEVLMasks` from the reverse
operations of load results or stored values. First, `optimizeEVLMask`
transforms:
```
vptr = vec_end_ptr (ptr, VF)
res = masked.load(vptr, vector.reverse(mask))
-->
vptr = vec_end_ptr (ptr, evl)
load = vp.load(vptr, vp.reverse(mask_w/o_header_mask), evl)
res = splice.left(poison, load, evl)
```
```
vptr = vec_end_ptr (ptr, VF)
masked.store(stored_val, vptr, vector.reverse(mask))
-->
vptr = vec_end_ptr (ptr, evl)
splice = splice.right(store_val, poison, evl)
vp.store(splice, vp.reverse(mask_w/o_header_mask), evl)
```
To maintain cost model consistency, `optimizeEVLMasks` introduces the
following simplification rules to fold splice and vector.reverse to
vp.reverse.
```
vector.reverse(splice.left(poison, v, evl))
-->
vp.reverse(v, true, evl)
splice.right(vector.reverse(v), poison, evl)
-->
vp.reverse(v, true, evl)
```
As a result, the permutations elimination can now take place directly
before the EVL lowering. However, a side effect is that we might
subsequently need to clean up redundant splices after EVL lowering.
Added:
Modified:
llvm/lib/Analysis/VectorUtils.cpp
llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 0929f55ae68b2..ecded79e990f3 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -164,6 +164,8 @@ bool llvm::isVectorIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,
case Intrinsic::smul_fix_sat:
case Intrinsic::umul_fix:
case Intrinsic::umul_fix_sat:
+ case Intrinsic::vector_splice_left:
+ case Intrinsic::vector_splice_right:
return (ScalarOpdIdx == 2);
case Intrinsic::experimental_vp_splice:
return ScalarOpdIdx == 2 || ScalarOpdIdx == 4;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index cc19c1c1faa2d..532fe65b8ae31 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -2997,19 +2997,19 @@ static VPRecipeBase *optimizeMaskToEVL(VPValue *HeaderMask,
return new VPWidenLoadEVLRecipe(cast<VPWidenLoadRecipe>(CurRecipe), Addr,
EVL, Mask);
- VPValue *ReversedVal;
- if (match(&CurRecipe, m_Reverse(m_VPValue(ReversedVal))) &&
- match(ReversedVal,
+ if (match(&CurRecipe,
m_MaskedLoad(m_VPValue(EndPtr),
m_Reverse(m_RemoveMask(HeaderMask, Mask)))) &&
match(EndPtr, m_VecEndPtr(m_VPValue(), m_Specific(&Plan->getVF())))) {
Mask = GetVPReverse(Mask);
Addr = AdjustEndPtr(EndPtr);
- auto *LoadR = new VPWidenLoadEVLRecipe(
- *cast<VPWidenLoadRecipe>(ReversedVal), Addr, EVL, Mask);
+ auto *LoadR = new VPWidenLoadEVLRecipe(cast<VPWidenLoadRecipe>(CurRecipe),
+ Addr, EVL, Mask);
LoadR->insertBefore(&CurRecipe);
- return new VPWidenIntrinsicRecipe(Intrinsic::experimental_vp_reverse,
- {LoadR, Plan->getTrue(), &EVL},
+ VPValue *Poison =
+ Plan->getOrAddLiveIn(PoisonValue::get(LoadR->getScalarType()));
+ return new VPWidenIntrinsicRecipe(Intrinsic::vector_splice_left,
+ {Poison, LoadR, &EVL},
LoadR->getScalarType(), {}, {}, DL);
}
@@ -3033,14 +3033,19 @@ static VPRecipeBase *optimizeMaskToEVL(VPValue *HeaderMask,
StoredVal, EVL, Mask);
if (match(&CurRecipe,
- m_MaskedStore(m_VPValue(EndPtr), m_Reverse(m_VPValue(ReversedVal)),
+ m_MaskedStore(m_VPValue(EndPtr), m_VPValue(StoredVal),
m_Reverse(m_RemoveMask(HeaderMask, Mask)))) &&
match(EndPtr, m_VecEndPtr(m_VPValue(), m_Specific(&Plan->getVF())))) {
Mask = GetVPReverse(Mask);
Addr = AdjustEndPtr(EndPtr);
- StoredVal = GetVPReverse(ReversedVal);
+ VPValue *Poison =
+ Plan->getOrAddLiveIn(PoisonValue::get(StoredVal->getScalarType()));
+ auto *SpliceR = new VPWidenIntrinsicRecipe(
+ Intrinsic::vector_splice_right, {StoredVal, Poison, &EVL},
+ StoredVal->getScalarType(), {}, {}, DL);
+ SpliceR->insertBefore(&CurRecipe);
return new VPWidenStoreEVLRecipe(cast<VPWidenStoreRecipe>(CurRecipe), Addr,
- StoredVal, EVL, Mask);
+ SpliceR, EVL, Mask);
}
if (auto *Rdx = dyn_cast<VPReductionRecipe>(&CurRecipe))
@@ -3133,6 +3138,28 @@ void VPlanTransforms::optimizeEVLMasks(VPlan &Plan) {
}
}
+ // Fold the following splice patterns into vp.reverse for reverse accesses:
+ // vector.reverse(splice.left(poison, x, evl)) -> vp.reverse(x, true, evl)
+ // splice.right(vector.reverse(x), poison, evl) -> vp.reverse(x, true, evl)
+ for (VPUser *U : collectUsersRecursively(EVL)) {
+ VPValue *X;
+ if (!match(U,
+ m_CombineOr(
+ m_Reverse(m_Intrinsic<Intrinsic::vector_splice_left>(
+ m_Poison(), m_VPValue(X), m_Specific(EVL))),
+ m_Intrinsic<Intrinsic::vector_splice_right>(
+ m_Reverse(m_VPValue(X)), m_Poison(), m_Specific(EVL)))))
+ continue;
+
+ auto *Def = cast<VPSingleDefRecipe>(U);
+ auto *VPReverse = new VPWidenIntrinsicRecipe(
+ Intrinsic::experimental_vp_reverse, {X, Plan.getTrue(), EVL},
+ X->getScalarType(), {}, {}, Def->getDebugLoc());
+ VPReverse->insertBefore(Def);
+ Def->replaceAllUsesWith(VPReverse);
+ OldRecipes.push_back(Def);
+ }
+
for (VPRecipeBase *R : reverse(OldRecipes)) {
SmallVector<VPValue *> PossiblyDead(R->operands());
R->eraseFromParent();
More information about the llvm-commits
mailing list