LLVM 23.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
15
16namespace llvm {
17
18namespace sandboxir {
19
20std::optional<Type *> LoadStoreVec::canVectorize(ArrayRef<Instruction *> Bndl,
21 Scheduler &Sched) {
22 // Check if in the same BB.
24 return std::nullopt;
25
26 // Check if instructions repeat.
28 return std::nullopt;
29
30 // TODO: This is target-dependent.
31 // Don't mix integer with floating point.
32 bool IsFloat = false;
33 bool IsInteger = false;
34 for ([[maybe_unused]] auto *I : Bndl) {
35 if (Utils::getExpectedType(I)->getScalarType()->isFloatingPointTy())
36 IsFloat = true;
37 else
38 IsInteger = true;
39 }
40 if (IsFloat && IsInteger)
41 return std::nullopt;
42
43 // Check scheduling.
44 if (!Sched.trySchedule(Bndl))
45 return std::nullopt;
46
47 return VecUtils::getCombinedVectorTypeFor(Bndl, *DL);
48}
49
50void LoadStoreVec::tryEraseDeadInstrs(ArrayRef<Instruction *> Stores,
51 ArrayRef<Value *> Operands) {
52 SmallPtrSet<Instruction *, 8> DeadCandidates;
53 for (auto *SI : Stores) {
54 if (auto *PtrI =
56 DeadCandidates.insert(PtrI);
57 SI->eraseFromParent();
58 }
59 for (auto *Op : Operands) {
60 if (auto *LI = dyn_cast<LoadInst>(Op)) {
61 if (auto *PtrI =
63 DeadCandidates.insert(PtrI);
64 cast<LoadInst>(LI)->eraseFromParent();
65 }
66 }
67 for (auto *PtrI : DeadCandidates)
68 if (!PtrI->hasNUsesOrMore(1))
69 PtrI->eraseFromParent();
70}
71
73 SmallVector<Instruction *, 8> Bndl(Rgn.getAux().begin(), Rgn.getAux().end());
74 if (Bndl.size() < 2)
75 return false;
76 Function &F = *Bndl[0]->getParent()->getParent();
77 DL = &F.getParent()->getDataLayout();
78 auto &Ctx = F.getContext();
79 Scheduler Sched(A.getAA(), Ctx);
81 Bndl, A.getScalarEvolution(), *DL))
82 return false;
83 if (!canVectorize(Bndl, Sched))
84 return false;
85
87 Operands.reserve(Bndl.size());
88 for (auto *I : Bndl) {
89 auto *Op = cast<StoreInst>(I)->getValueOperand();
90 Operands.push_back(Op);
91 }
92 BasicBlock *BB = Bndl[0]->getParent();
93 // TODO: For now we only support load operands.
94 // TODO: For now we don't cross BBs.
95 // TODO: For now don't vectorize if the loads have external uses.
96 bool AllLoads = all_of(Operands, [BB](Value *V) {
97 auto *LI = dyn_cast<LoadInst>(V);
98 if (LI == nullptr)
99 return false;
100 // TODO: For now we don't cross BBs.
101 if (LI->getParent() != BB)
102 return false;
103 if (LI->hasNUsesOrMore(2))
104 return false;
105 return true;
106 });
107 bool AllConstants =
108 all_of(Operands, [](Value *V) { return isa<Constant>(V); });
109 if (!AllLoads && !AllConstants)
110 return false;
111
112 Value *VecOp = nullptr;
113 if (AllLoads) {
114 // TODO: Try to avoid the extra copy to an instruction vector.
116 Loads.reserve(Operands.size());
117 for (Value *Op : Operands)
119
121 Loads, A.getScalarEvolution(), *DL);
122 if (!Consecutive)
123 return false;
124 if (!canVectorize(Loads, Sched))
125 return false;
126
127 // Generate vector load.
129 Value *LdPtr = cast<LoadInst>(Loads[0])->getPointerOperand();
130 // TODO: Compute alignment.
131 Align LdAlign(1);
132 auto LdWhereIt = std::next(VecUtils::getLowest(Loads)->getIterator());
133 VecOp = LoadInst::create(Ty, LdPtr, LdAlign, LdWhereIt, Ctx, "VecIinitL");
134 } else if (AllConstants) {
136 Constants.reserve(Operands.size());
137 for (Value *Op : Operands) {
138 auto *COp = cast<Constant>(Op);
139 if (auto *AggrCOp = dyn_cast<ConstantAggregate>(COp)) {
140 // If the operand is a constant aggregate, then append all its elements.
141 for (Value *Elm : AggrCOp->operands())
142 Constants.push_back(cast<Constant>(Elm));
143 } else if (auto *SeqCOp = dyn_cast<ConstantDataSequential>(COp)) {
144 for (auto ElmIdx : seq<unsigned>(SeqCOp->getNumElements()))
145 Constants.push_back(SeqCOp->getElementAsConstant(ElmIdx));
146 } else if (auto *Zero = dyn_cast<ConstantAggregateZero>(COp)) {
147 auto *ZeroElm = Zero->getSequentialElement();
148 for ([[maybe_unused]] auto Cnt :
149 seq<unsigned>(Zero->getElementCount().getFixedValue()))
150 Constants.push_back(ZeroElm);
151 } else {
152 Constants.push_back(COp);
153 }
154 }
155 VecOp = ConstantVector::get(Constants);
156 }
157
158 // Generate vector store.
159 Value *StPtr = cast<StoreInst>(Bndl[0])->getPointerOperand();
160 // TODO: Compute alignment.
161 Align StAlign(1);
162 auto StWhereIt = std::next(VecUtils::getLowest(Bndl)->getIterator());
163 StoreInst::create(VecOp, StPtr, StAlign, StWhereIt, Ctx);
164
165 tryEraseDeadInstrs(Bndl, Operands);
166 return true;
167}
168
169} // namespace sandboxir
170
171} // namespace llvm
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
The main job of the Region is to point to new instructions generated by vectorization passes.
Definition Region.h:96
const SmallVector< Instruction * > & getAux() const
\Returns the auxiliary vector.
Definition Region.h:156
The list scheduler.
Definition Scheduler.h:163
static LLVM_ABI StoreInst * create(Value *V, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx)
Just like llvm::Type these are immutable, unique, never get freed and can only be created via static ...
Definition Type.h:47
static Type * getExpectedType(const Value *V)
\Returns the expected type of Value V.
Definition Utils.h:32
A SandboxIR Value has users. This is the base class.
Definition Value.h:68
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition VecUtils.h:147
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:126
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:59
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.
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
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:305
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39