[llvm] Vectorize ld st nop (PR #223412)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 02:02:45 PDT 2026
================
@@ -3996,6 +3996,177 @@ void VPlanTransforms::sinkPredicatedStores(VPlan &Plan,
}
}
+/// Return the recipe defining \p V if it is an unpredicated GEP with an
+/// underlying GetElementPtrInst, i.e. a VPWidenGEPRecipe or a replicating GEP.
+static VPRecipeWithIRFlags *getGEPRecipe(VPValue *V) {
+ auto *R = dyn_cast_or_null<VPRecipeWithIRFlags>(V->getDefiningRecipe());
+ if (!R)
+ return nullptr;
+ if (isa<VPWidenGEPRecipe>(R))
+ return R;
+ auto *RepR = dyn_cast<VPReplicateRecipe>(R);
+ if (RepR && RepR->getOpcode() == Instruction::GetElementPtr &&
+ !RepR->isPredicated())
+ return RepR;
+ return nullptr;
+}
+
+/// Return true if \p A and \p B are GEPs with loop-invariant base pointers
+/// that only differ in their base pointer, i.e. they compute addresses with the
+/// same stride.
+static bool areGEPsWithSameIndices(VPRecipeWithIRFlags *A,
+ VPRecipeWithIRFlags *B) {
+ auto *GEPA = cast<GetElementPtrInst>(A->getUnderlyingInstr());
+ auto *GEPB = cast<GetElementPtrInst>(B->getUnderlyingInstr());
+ if (GEPA->getSourceElementType() != GEPB->getSourceElementType() ||
+ A->getNumOperands() != B->getNumOperands())
+ return false;
+ if (!A->getOperand(0)->isDefinedOutsideLoopRegions() ||
+ !B->getOperand(0)->isDefinedOutsideLoopRegions())
+ return false;
+ return std::equal(std::next(A->op_begin()), A->op_end(),
+ std::next(B->op_begin()));
+}
+
+void VPlanTransforms::convertSelectPtrLoadStoreToMasked(VPlan &Plan) {
+ if (Plan.hasScalarVFOnly())
+ return;
+
+ // Look for
+ // %v = load (select %c, %p, %q)
+ // store %v, %q
+ // where %p and %q are consecutive addresses with the same stride. For lanes
+ // with %c == false, the store writes back the value just loaded from %q,
+ // which is a no-op. Hence, the pair is equivalent to a masked load from %p
+ // and a masked store to %q, both using %c as mask.
+
+ VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
+ for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
+ vp_depth_first_shallow(LoopRegion->getEntry()))) {
+ for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
+ auto *StoreR = dyn_cast<VPWidenStoreRecipe>(&R);
+ if (!StoreR || !StoreR->isConsecutive()) // Should also check if reversed?
----------------
dnsampaio wrote:
I believe it should be required to test that both load and store pointers iterate on the same direction, but I'm not exactly sure how.
https://github.com/llvm/llvm-project/pull/223412
More information about the llvm-commits
mailing list