[llvm] [SLP] Split blocking build-vector stores in scalar chains (PR #194970)
Yaxun Liu via llvm-commits
llvm-commits at lists.llvm.org
Mon May 4 07:46:21 PDT 2026
================
@@ -26634,6 +26499,53 @@ SLPVectorizerPass::vectorizeStoreChain(ArrayRef<Value *> Chain, BoUpSLP &R,
}
namespace {
+/// A store-chain element after breaking stores into scalar lanes.
+///
+/// A scalar store contributes one lane. A simple build-vector store contributes
+/// one lane per inserted element, so a store of <a, b, c, d> to p[3] is modeled
+/// as lanes p[3] = a, p[4] = b, p[5] = c, p[6] = d.
+struct StoreLane {
+ StoreInst *Store = nullptr;
+ Value *ScalarValue = nullptr;
+ int64_t Offset = 0;
+ unsigned Lane = 0;
+ bool IsVectorLane = false;
+
+ Align getAlignment(TypeSize EltSize) const {
+ uint64_t StoreOffset = IsVectorLane ? Lane : 0;
+ return commonAlignment(Store->getAlign(),
+ StoreOffset * EltSize.getFixedValue());
+ }
+};
+
+static bool collectBuildVector(Value *V, SmallVectorImpl<Value *> &Elts,
+ SmallVectorImpl<Instruction *> &Insts) {
+ auto *VecTy = dyn_cast<FixedVectorType>(V->getType());
+ if (!VecTy)
+ return false;
+ Elts.assign(VecTy->getNumElements(), nullptr);
+ Value *Cur = V;
+ while (auto *IE = dyn_cast<InsertElementInst>(Cur)) {
+ auto *Idx = dyn_cast<ConstantInt>(IE->getOperand(2));
+ if (!Idx || Idx->getValue().uge(Elts.size()))
+ return false;
+ Elts[Idx->getZExtValue()] = IE->getOperand(1);
+ Insts.push_back(IE);
+ Cur = IE->getOperand(0);
----------------
yxsamliu wrote:
Fixed. The walk now goes from the stored value back toward the undef/poison root, so the latest insertelement on a given lane is visited before any earlier one. The first insertelement we see for a lane is the one we keep, and any later visit to that same lane index is a no-op. That matches IR semantics, where the most recent insertelement is the visible value at the store.
https://github.com/llvm/llvm-project/pull/194970
More information about the llvm-commits
mailing list