LLVM 24.0.0git
LoadStoreVec.cpp
Go to the documentation of this file.
1//===- LoadStoreVec.cpp - Vectorizer pass short load-store chains ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
19
20namespace llvm {
21
22extern cl::opt<int> CostThreshold; // Defined in TransactionAcceptOrRevert.cpp
23
24namespace sandboxir {
25
26#define DEBUG_PREFIX_LOCAL DEBUG_PREFIX "LoadStoreVec: "
27
28std::optional<Type *> LoadStoreVec::canVectorize(ArrayRef<Instruction *> Bndl,
29 Scheduler &Sched) {
30 // Check if in the same BB.
32 return std::nullopt;
33
34 // Check if instructions repeat.
36 return std::nullopt;
37
38 // Check scheduling.
39 if (!Sched.trySchedule(Bndl))
40 return std::nullopt;
41
43}
44
45void LoadStoreVec::tryEraseDeadInstrs(ArrayRef<Instruction *> Stores,
47 SmallPtrSet<Instruction *, 8> DeadCandidates;
48 for (auto *SI : Stores) {
49 if (auto *PtrI =
51 DeadCandidates.insert(PtrI);
52 SI->eraseFromParent();
53 }
54 for (auto *Op : Operands) {
55 if (auto *LI = dyn_cast<LoadInst>(Op)) {
56 if (auto *PtrI =
58 DeadCandidates.insert(PtrI);
59 cast<LoadInst>(LI)->eraseFromParent();
60 }
61 }
62 for (auto *PtrI : DeadCandidates)
63 if (!PtrI->hasNUsesOrMore(1))
64 PtrI->eraseFromParent();
65}
66
67void LoadStoreVec::saveIR(Region &Rgn) {
68 SavedRgn = &Rgn;
69 const auto &SB = cast<RegionWithScore>(Rgn).getScoreboard();
70 CostBefore = SB.getAfterCost() - SB.getBeforeCost();
71 Rgn.getContext().save();
72}
73
74bool LoadStoreVec::acceptOrRevert() {
75 auto &Ctx = SavedRgn->getContext();
76 const auto &SB = cast<RegionWithScore>(*SavedRgn).getScoreboard();
77 InstructionCost CostAfter = SB.getAfterCost() - SB.getBeforeCost();
78 InstructionCost CostGain = CostAfter - CostBefore;
79 LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "CostGain=" << CostGain
80 << " (After=" << CostAfter << " Before=" << CostBefore
81 << ")\n");
82 if (CostGain > CostThreshold) {
83 LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "Not profitable, reverting.\n");
84 Ctx.revert();
85 return false;
86 }
87 LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "Profitable accepting.\n");
88 Ctx.accept();
89 return true;
90}
91
92bool LoadStoreVec::vectorizeStores(ArrayRef<Instruction *> Bndl, Region &Rgn,
93 Scheduler &Sched, const Analyses &A) {
94 Function &F = *Bndl[0]->getParent()->getParent();
95 auto &Ctx = F.getContext();
97 Bndl, A.getScalarEvolution(), *DL))
98 return false;
99 if (!canVectorize(Bndl, Sched))
100 return false;
101
102 SmallVector<Value *, 4> Operands;
103 Operands.reserve(Bndl.size());
104 for (auto *I : Bndl) {
105 auto *Op = cast<StoreInst>(I)->getValueOperand();
106 Operands.push_back(Op);
107 }
108 BasicBlock *BB = Bndl[0]->getParent();
109 // TODO: For now we only support load operands.
110 // TODO: For now we don't cross BBs.
111 // TODO: For now don't vectorize if the loads have external uses.
112 bool AllLoads = all_of(Operands, [BB](Value *V) {
113 auto *LI = dyn_cast<LoadInst>(V);
114 if (LI == nullptr)
115 return false;
116 // TODO: For now we don't cross BBs.
117 if (LI->getParent() != BB)
118 return false;
119 if (LI->hasNUsesOrMore(2))
120 return false;
121 return true;
122 });
123 bool AllConstants =
124 all_of(Operands, [](Value *V) { return isa<Constant>(V); });
125 if (!AllLoads && !AllConstants)
126 return false;
127
128 // Vectorizing mixed floats and integers with external uses may not be
129 // profitable on some targets, so save state here.
130 saveIR(Rgn);
131
132 Value *VecOp = nullptr;
133 if (AllLoads) {
134 // TODO: Try to avoid the extra copy to an instruction vector.
135 SmallVector<Instruction *, 8> Loads;
136 Loads.reserve(Operands.size());
137 for (Value *Op : Operands)
138 Loads.push_back(cast<Instruction>(Op));
139
141 Loads, A.getScalarEvolution(), *DL);
142 if (!Consecutive) {
143 Ctx.accept();
144 return false;
145 }
146 if (!canVectorize(Loads, Sched)) {
147 Ctx.accept();
148 return false;
149 }
150
151 // Generate vector load.
153 Value *LdPtr = cast<LoadInst>(Loads[0])->getPointerOperand();
154 // TODO: Compute alignment.
155 Align LdAlign(1);
156 auto LdWhereIt = std::next(VecUtils::getLowest(Loads)->getIterator());
157 VecOp = LoadInst::create(Ty, LdPtr, LdAlign, LdWhereIt, Ctx, "VecIinitL");
158 } else if (AllConstants) {
160 Constants.reserve(Operands.size());
161 for (Value *Op : Operands) {
162 auto *COp = cast<Constant>(Op);
163 if (auto *AggrCOp = dyn_cast<ConstantAggregate>(COp)) {
164 // If the operand is a constant aggregate, then append all its elements.
165 for (Value *Elm : AggrCOp->operands())
166 Constants.push_back(cast<Constant>(Elm));
167 } else if (auto *SeqCOp = dyn_cast<ConstantDataSequential>(COp)) {
168 for (auto ElmIdx : seq<unsigned>(SeqCOp->getNumElements()))
169 Constants.push_back(SeqCOp->getElementAsConstant(ElmIdx));
170 } else if (auto *Zero = dyn_cast<ConstantAggregateZero>(COp)) {
171 auto *ZeroElm = Zero->getSequentialElement();
172 for ([[maybe_unused]] auto Cnt :
173 seq<unsigned>(Zero->getElementCount().getFixedValue()))
174 Constants.push_back(ZeroElm);
175 } else if (isa<ConstantInt>(COp) && isa<VectorType>(COp->getType())) {
176 auto *Elm = ConstantInt::get(Ctx, cast<ConstantInt>(COp)->getValue());
177 for ([[maybe_unused]] auto Cnt :
178 seq<unsigned>(cast<VectorType>(COp->getType())
179 ->getElementCount()
180 .getFixedValue()))
181 Constants.push_back(Elm);
182 } else if (isa<ConstantFP>(COp) && isa<VectorType>(COp->getType())) {
183 auto *Elm = ConstantFP::get(cast<ConstantFP>(COp)->getValue(), Ctx);
184 for ([[maybe_unused]] auto Cnt :
185 seq<unsigned>(cast<VectorType>(COp->getType())
186 ->getElementCount()
187 .getFixedValue()))
188 Constants.push_back(Elm);
189 } else {
190 Constants.push_back(COp);
191 }
192 }
193 VecOp = ConstantVector::get(Constants);
194 }
195
196 // Generate vector store.
197 Value *StPtr = cast<StoreInst>(Bndl[0])->getPointerOperand();
198 // TODO: Compute alignment.
199 Align StAlign(1);
200 auto StWhereIt = std::next(VecUtils::getLowest(Bndl)->getIterator());
201 StoreInst::create(VecOp, StPtr, StAlign, StWhereIt, Ctx);
202
203 tryEraseDeadInstrs(Bndl, Operands);
204
205 return acceptOrRevert();
206}
207
209 SmallVector<Instruction *, 8> Bndl(Rgn.getAux().begin(), Rgn.getAux().end());
210 if (Bndl.size() < 2)
211 return false;
212 Function &F = *Bndl[0]->getParent()->getParent();
213 DL = &F.getParent()->getDataLayout();
214 Scheduler Sched(A.getAA(), F.getContext(), SchedDirection::BottomUp);
215 return vectorizeStores(Bndl, Rgn, Sched, A);
216}
217
218} // namespace sandboxir
219
220} // namespace llvm
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file defines an InstructionCost class that is used when calculating the cost of an instruction,...
static constexpr Value * getValue(Ty &ValueOrUse)
#define DEBUG_PREFIX_LOCAL
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
PostRA Machine Instruction Scheduler
SI Fold Operands
#define LLVM_DEBUG(...)
Definition Debug.h:119
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI Constant * get(Type *Ty, double V)
This returns a ConstantFP, or a vector containing a splat of a ConstantFP, for the specified value in...
Definition Constant.cpp:90
static LLVM_ABI Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
Definition Constant.cpp:48
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
Definition Constant.cpp:176
static bool differentBlock(ArrayRef< ValueT * > Instrs)
Definition Legality.h:350
static bool areUnique(ArrayRef< ValueT * > Values)
Definition Legality.h:358
static LLVM_ABI LoadInst * create(Type *Ty, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx, const Twine &Name="")
bool runOnRegion(Region &Rgn, const Analyses &A) final
\Returns true if it modifies R.
const SmallVector< Instruction * > & getAux() const
\Returns the auxiliary vector.
Definition Region.h:177
The list scheduler.
Definition Scheduler.h:302
static LLVM_ABI StoreInst * create(Value *V, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx)
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition VecUtils.h:145
static Type * getCombinedVectorTypeFor(ArrayRef< Instruction * > Bndl, const DataLayout &DL)
\Returns the combined vector type for Bndl, even when the element types differ.
Definition VecUtils.h:124
static bool areConsecutive(LoadOrStoreT *I1, LoadOrStoreT *I2, ScalarEvolution &SE, const DataLayout &DL)
\Returns true if I1 and I2 are load/stores accessing consecutive memory addresses.
Definition VecUtils.h:57
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
static cl::opt< unsigned > CostThreshold("dfa-cost-threshold", cl::desc("Maximum cost accepted for the transformation"), cl::Hidden, cl::init(50))