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
10#include "llvm/ADT/DenseSet.h"
21
22namespace llvm {
23
24extern cl::opt<int> CostThreshold; // Defined in TransactionAcceptOrRevert.cpp
25
26namespace sandboxir {
27
28#define DEBUG_PREFIX_LOCAL DEBUG_PREFIX "LoadStoreVec: "
29
30std::optional<Type *> LoadStoreVec::canVectorize(BndlRef<Instruction *> Bndl) {
31 // Check if in the same BB.
33 return std::nullopt;
34
35 // Check if instructions repeat.
37 return std::nullopt;
38
39 // Check scheduling.
40 if (!Sched->trySchedule(Bndl))
41 return std::nullopt;
42
44}
45
46void LoadStoreVec::saveIR(Region &R) {
47 Rgn = &R;
48 const auto &SB = cast<RegionWithScore>(Rgn)->getScoreboard();
49 CostBefore = SB.getAfterCost() - SB.getBeforeCost();
50 Rgn->getContext().save();
51}
52
53bool LoadStoreVec::acceptOrRevert() {
54 const auto &SB = cast<RegionWithScore>(*Rgn).getScoreboard();
55 InstructionCost CostAfter = SB.getAfterCost() - SB.getBeforeCost();
56 InstructionCost CostGain = CostAfter - CostBefore;
57 LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "CostGain=" << CostGain
58 << " (After=" << CostAfter << " Before=" << CostBefore
59 << ")\n");
60 if (CostGain > CostThreshold) {
61 LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "Not profitable, reverting.\n");
62 Ctx->revert();
63 return false;
64 }
65 LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "Profitable accepting.\n");
66 Ctx->accept();
67 return true;
68}
69
70LoadInst *LoadStoreVec::createVectorLoad(BndlRef<Instruction *> Loads) {
72 Loads, A->getScalarEvolution(), *DL))
73 return nullptr;
74 if (!canVectorize(Loads))
75 return nullptr;
76
78 Value *LdPtr = cast<LoadInst>(Loads[0])->getPointerOperand();
79 // TODO: Compute alignment.
80 Align LdAlign(1);
81 auto LdWhereIt = std::next(VecUtils::getLowest(Loads)->getIterator());
82 return LoadInst::create(Ty, LdPtr, LdAlign, LdWhereIt, *Ctx, "VecIinitL");
83}
84
85Value *LoadStoreVec::createConstantVector(BndlRef<Value *> Operands) {
87 Constants.reserve(Operands.size());
88 for (Value *Op : Operands) {
89 auto *COp = cast<Constant>(Op);
90 if (auto *AggrCOp = dyn_cast<ConstantAggregate>(COp)) {
91 // If the operand is a constant aggregate, then append all its elements.
92 for (Value *Elm : AggrCOp->operands())
93 Constants.push_back(cast<Constant>(Elm));
94 } else if (auto *SeqCOp = dyn_cast<ConstantDataSequential>(COp)) {
95 for (auto ElmIdx : seq<unsigned>(SeqCOp->getNumElements()))
96 Constants.push_back(SeqCOp->getElementAsConstant(ElmIdx));
97 } else if (auto *Zero = dyn_cast<ConstantAggregateZero>(COp)) {
98 auto *ZeroElm = Zero->getSequentialElement();
99 for ([[maybe_unused]] auto Cnt :
100 seq<unsigned>(Zero->getElementCount().getFixedValue()))
101 Constants.push_back(ZeroElm);
102 } else if (isa<ConstantInt>(COp) && isa<VectorType>(COp->getType())) {
103 auto *Elm = ConstantInt::get(*Ctx, cast<ConstantInt>(COp)->getValue());
104 for ([[maybe_unused]] auto Cnt :
105 seq<unsigned>(cast<VectorType>(COp->getType())
106 ->getElementCount()
107 .getFixedValue()))
108 Constants.push_back(Elm);
109 } else if (isa<ConstantFP>(COp) && isa<VectorType>(COp->getType())) {
110 auto *Elm = ConstantFP::get(cast<ConstantFP>(COp)->getValue(), *Ctx);
111 for ([[maybe_unused]] auto Cnt :
112 seq<unsigned>(cast<VectorType>(COp->getType())
113 ->getElementCount()
114 .getFixedValue()))
115 Constants.push_back(Elm);
116 } else {
117 Constants.push_back(COp);
118 }
119 }
120 return ConstantVector::get(Constants);
121}
122
123bool LoadStoreVec::vectorizeStores(BndlRef<Instruction *> Stores, Region &Rgn) {
125 Stores, A->getScalarEvolution(), *DL))
126 return false;
127 if (!canVectorize(Stores))
128 return false;
129 SmallVector<Value *, 4> Operands;
130 Operands.reserve(Stores.size());
131 for (auto *I : Stores) {
132 auto *Op = cast<StoreInst>(I)->getValueOperand();
133 Operands.push_back(Op);
134 }
135 BasicBlock *BB = Stores[0]->getParent();
136 // TODO: For now we only support load operands.
137 // TODO: For now we don't cross BBs.
138 // TODO: For now don't vectorize if the loads have external uses.
139 bool AllLoads = all_of(Operands, [BB](Value *V) {
140 auto *LI = dyn_cast<LoadInst>(V);
141 if (LI == nullptr)
142 return false;
143 // TODO: For now we don't cross BBs.
144 if (LI->getParent() != BB)
145 return false;
146 if (LI->hasNUsesOrMore(2))
147 return false;
148 return true;
149 });
150 bool AllConstants =
151 all_of(Operands, [](Value *V) { return isa<Constant>(V); });
152 if (!AllLoads && !AllConstants)
153 return false;
154
155 // Vectorizing mixed floats and integers with external uses may not be
156 // profitable on some targets, so save state here.
157 saveIR(Rgn);
158 Value *VecOp = nullptr;
159 if (AllLoads) {
160 // TODO: Try to avoid the extra copy to an instruction vector.
161 SmallVector<Instruction *, 8> Loads;
162 Loads.reserve(Operands.size());
163 for (Value *Op : Operands)
164 Loads.push_back(cast<Instruction>(Op));
165 VecOp = createVectorLoad(Loads);
166 if (VecOp == nullptr) {
167 Ctx->accept();
168 return false;
169 }
170 } else if (AllConstants) {
171 VecOp = createConstantVector(Operands);
172 }
173
174 // Generate vector store.
175 Value *StPtr = cast<StoreInst>(Stores[0])->getPointerOperand();
176 // TODO: Compute alignment.
177 Align StAlign(1);
178 auto StWhereIt = std::next(VecUtils::getLowest(Stores)->getIterator());
179 StoreInst::create(VecOp, StPtr, StAlign, StWhereIt, *Ctx);
180
181 DeadInstrMorgue.collectPotentiallyDeadInstrs(Stores);
182 if (AllLoads)
183 DeadInstrMorgue.collectPotentiallyDeadInstrs<Value>(Operands);
184 DeadInstrMorgue.tryEraseDeadInstrs();
185
186 return acceptOrRevert();
187}
188
189LoadInst *LoadStoreVec::vectorizeLoads(BndlRef<Instruction *> Loads,
190 Region &Rgn) {
192 Loads, A->getScalarEvolution(), *DL))
193 return nullptr;
194 auto VecTy = canVectorize(Loads);
195 if (!VecTy)
196 return nullptr;
197
198 // TODO: Support mixed-type top-level load chains.
199 Type *VecElemTy = cast<FixedVectorType>(*VecTy)->getElementType();
200 if (!all_of(Loads, [VecElemTy](Instruction *I) {
201 return VecUtils::getElementType(I->getType()) == VecElemTy;
202 }))
203 return nullptr;
204
205 saveIR(Rgn);
206
207 auto *VecLoad = createVectorLoad(Loads);
208 if (VecLoad == nullptr) {
209 Ctx->accept();
210 return nullptr;
211 }
212
213 BasicBlock::iterator WhereIt = std::next(VecLoad->getIterator());
214 for (auto [Lane, OrigV] : VecUtils::enumerateLanes(Loads)) {
215 auto *OrigLoad = cast<LoadInst>(OrigV);
216 if (OrigLoad->hasNUses(0))
217 continue;
218 Value *Unpacked =
219 VecUtils::unpack(VecLoad, OrigLoad->getType(), Lane, WhereIt);
220 OrigLoad->replaceAllUsesWith(Unpacked);
221 }
222
223 DeadInstrMorgue.collectPotentiallyDeadInstrs(Loads);
224 DeadInstrMorgue.tryEraseDeadInstrs();
225
226 if (!acceptOrRevert())
227 return nullptr;
228 return VecLoad;
229}
230
231bool LoadStoreVec::runOnRegion(Region &Rgn, const Analyses &RegionAnalyses) {
232 SmallVector<Instruction *, 8> Bndl(Rgn.getAux().begin(), Rgn.getAux().end());
233 if (Bndl.size() < 2)
234 return false;
235 Function &F = *Bndl[0]->getParent()->getParent();
236 DL = &F.getParent()->getDataLayout();
237 Ctx = &F.getContext();
238 A = &RegionAnalyses;
239 Sched =
240 std::make_unique<Scheduler>(A->getAA(), *Ctx, SchedDirection::BottomUp);
241
242 auto Opc = Bndl[0]->getOpcode();
243 assert(
244 all_of(Bndl, [Opc](Instruction *I) { return I->getOpcode() == Opc; }) &&
245 "Expected a homogeneous seed slice!");
246
247 bool Changed = false;
248 switch (Opc) {
249 case Instruction::Opcode::Load:
250 Changed = vectorizeLoads(Bndl, Rgn) != nullptr;
251 break;
252 case Instruction::Opcode::Store:
253 Changed = vectorizeStores(Bndl, Rgn);
254 break;
255 default:
256 llvm_unreachable("Expected Load or Store");
257 }
258 Sched.reset();
259 return Changed;
260}
261
262} // namespace sandboxir
263
264} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file defines the DenseSet and SmallDenseSet classes.
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
SI Fold Operands
#define LLVM_DEBUG(...)
Definition Debug.h:119
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An ArrayRef of Values or Instructions that we can print/dump for debugging.
Definition VecUtils.h:459
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
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition Instruction.h:43
static bool areUnique(BndlRef< ValueT * > Values)
Definition Legality.h:358
static bool differentBlock(BndlRef< ValueT * > Instrs)
Definition Legality.h:350
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.
static LLVM_ABI StoreInst * create(Value *V, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx)
A SandboxIR Value has users. This is the base class.
Definition Value.h:72
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition VecUtils.h:146
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:125
static Value * unpack(Value *FromVec, Type *ExtrTy, unsigned Lane, BasicBlock::iterator WhereIt)
Emits the necessary instruction sequence to extract element of type ExtrTy at Lane from FromVec.
Definition VecUtils.h:324
static auto enumerateLanes(const ValueContainerT &Range)
Helper for creating LaneValueEnumerator ranges.
Definition VecUtils.h:442
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:58
static Type * getElementType(Type *Ty)
Returns Ty if scalar or its element type if vector.
Definition VecUtils.h:51
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
BndlRef(const T &OneElt) -> BndlRef< T >
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
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:1755
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
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
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))