[llvm] [SandboxVec][LoadStoreVec] Vectorize load seed chains (PR #215944)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 16 08:00:42 PDT 2026
================
@@ -128,91 +156,111 @@ bool LoadStoreVec::vectorizeStores(ArrayRef<Instruction *> Bndl, Region &Rgn,
// Vectorizing mixed floats and integers with external uses may not be
// profitable on some targets, so save state here.
saveIR(Rgn);
-
Value *VecOp = nullptr;
if (AllLoads) {
// TODO: Try to avoid the extra copy to an instruction vector.
SmallVector<Instruction *, 8> Loads;
Loads.reserve(Operands.size());
for (Value *Op : Operands)
Loads.push_back(cast<Instruction>(Op));
-
- bool Consecutive = VecUtils::areConsecutive<LoadInst, Instruction>(
- Loads, A.getScalarEvolution(), *DL);
- if (!Consecutive) {
- Ctx.accept();
+ VecOp = createVectorLoad(Loads);
+ if (VecOp == nullptr) {
+ Ctx->accept();
return false;
}
- if (!canVectorize(Loads, Sched)) {
- Ctx.accept();
- return false;
- }
-
- // Generate vector load.
- Type *Ty = VecUtils::getCombinedVectorTypeFor(Bndl, *DL);
- Value *LdPtr = cast<LoadInst>(Loads[0])->getPointerOperand();
- // TODO: Compute alignment.
- Align LdAlign(1);
- auto LdWhereIt = std::next(VecUtils::getLowest(Loads)->getIterator());
- VecOp = LoadInst::create(Ty, LdPtr, LdAlign, LdWhereIt, Ctx, "VecIinitL");
} else if (AllConstants) {
- SmallVector<Constant *, 8> Constants;
- Constants.reserve(Operands.size());
- for (Value *Op : Operands) {
- auto *COp = cast<Constant>(Op);
- if (auto *AggrCOp = dyn_cast<ConstantAggregate>(COp)) {
- // If the operand is a constant aggregate, then append all its elements.
- for (Value *Elm : AggrCOp->operands())
- Constants.push_back(cast<Constant>(Elm));
- } else if (auto *SeqCOp = dyn_cast<ConstantDataSequential>(COp)) {
- for (auto ElmIdx : seq<unsigned>(SeqCOp->getNumElements()))
- Constants.push_back(SeqCOp->getElementAsConstant(ElmIdx));
- } else if (auto *Zero = dyn_cast<ConstantAggregateZero>(COp)) {
- auto *ZeroElm = Zero->getSequentialElement();
- for ([[maybe_unused]] auto Cnt :
- seq<unsigned>(Zero->getElementCount().getFixedValue()))
- Constants.push_back(ZeroElm);
- } else if (isa<ConstantInt>(COp) && isa<VectorType>(COp->getType())) {
- auto *Elm = ConstantInt::get(Ctx, cast<ConstantInt>(COp)->getValue());
- for ([[maybe_unused]] auto Cnt :
- seq<unsigned>(cast<VectorType>(COp->getType())
- ->getElementCount()
- .getFixedValue()))
- Constants.push_back(Elm);
- } else if (isa<ConstantFP>(COp) && isa<VectorType>(COp->getType())) {
- auto *Elm = ConstantFP::get(cast<ConstantFP>(COp)->getValue(), Ctx);
- for ([[maybe_unused]] auto Cnt :
- seq<unsigned>(cast<VectorType>(COp->getType())
- ->getElementCount()
- .getFixedValue()))
- Constants.push_back(Elm);
- } else {
- Constants.push_back(COp);
- }
- }
- VecOp = ConstantVector::get(Constants);
+ VecOp = createConstantVector(Operands);
}
// Generate vector store.
- Value *StPtr = cast<StoreInst>(Bndl[0])->getPointerOperand();
+ Value *StPtr = cast<StoreInst>(Stores[0])->getPointerOperand();
// TODO: Compute alignment.
Align StAlign(1);
- auto StWhereIt = std::next(VecUtils::getLowest(Bndl)->getIterator());
- StoreInst::create(VecOp, StPtr, StAlign, StWhereIt, Ctx);
+ auto StWhereIt = std::next(VecUtils::getLowest(Stores)->getIterator());
+ StoreInst::create(VecOp, StPtr, StAlign, StWhereIt, *Ctx);
- tryEraseDeadInstrs(Bndl, Operands);
+ DeadInstrMorgue.collectPotentiallyDeadInstrs(Stores);
+ if (AllLoads)
+ DeadInstrMorgue.collectPotentiallyDeadInstrs<Value>(Operands);
+ DeadInstrMorgue.tryEraseDeadInstrs();
return acceptOrRevert();
}
-bool LoadStoreVec::runOnRegion(Region &Rgn, const Analyses &A) {
+LoadInst *LoadStoreVec::vectorizeLoads(ArrayRef<Instruction *> Loads,
+ Region &Rgn) {
+ if (!VecUtils::areConsecutive<LoadInst, Instruction>(
+ Loads, A->getScalarEvolution(), *DL))
+ return nullptr;
+ auto VecTy = canVectorize(Loads);
+ if (!VecTy)
+ return nullptr;
+
+ // TODO: Support mixed-type top-level load chains.
+ Type *VecElemTy = cast<FixedVectorType>(*VecTy)->getElementType();
+ if (!all_of(Loads, [VecElemTy](Instruction *I) {
+ return VecUtils::getElementType(I->getType()) == VecElemTy;
+ }))
+ return nullptr;
+
+ saveIR(Rgn);
+
+ auto *VecLoad = createVectorLoad(Loads);
+ if (VecLoad == nullptr) {
+ Ctx->accept();
+ return nullptr;
+ }
+
+ BasicBlock::iterator WhereIt = std::next(VecLoad->getIterator());
+ for (auto [Lane, OrigV] : VecUtils::enumerateLanes(Loads)) {
+ auto *OrigLoad = cast<LoadInst>(OrigV);
+ if (OrigLoad->hasNUses(0))
+ continue;
+ Value *Unpacked =
+ VecUtils::unpack(VecLoad, OrigLoad->getType(), Lane, WhereIt);
+ OrigLoad->replaceAllUsesWith(Unpacked);
+ }
+
+ DeadInstrMorgue.collectPotentiallyDeadInstrs(Loads);
+ DeadInstrMorgue.tryEraseDeadInstrs();
+
+ if (!acceptOrRevert())
+ return nullptr;
+ return VecLoad;
+}
+
+bool LoadStoreVec::runOnRegion(Region &Rgn, const Analyses &RegionAnalyses) {
SmallVector<Instruction *, 8> Bndl(Rgn.getAux().begin(), Rgn.getAux().end());
if (Bndl.size() < 2)
return false;
Function &F = *Bndl[0]->getParent()->getParent();
DL = &F.getParent()->getDataLayout();
- Scheduler Sched(A.getAA(), F.getContext(), SchedDirection::BottomUp);
- return vectorizeStores(Bndl, Rgn, Sched, A);
+ Ctx = &F.getContext();
+ A = &RegionAnalyses;
+ Sched =
+ std::make_unique<Scheduler>(A->getAA(), *Ctx, SchedDirection::BottomUp);
+
+ // SeedCollection only ever gives us a homogeneous seed slice: stores and
+ // loads are collected in separate passes over the BB, never mixed into one
----------------
vporpo wrote:
Too much detail in this comment. We don't need to mention that they get collected in separate passes over the BB.
https://github.com/llvm/llvm-project/pull/215944
More information about the llvm-commits
mailing list