LLVM 20.0.0git
SeedCollector.h
Go to the documentation of this file.
1//===- SeedCollector.h ------------------------------------------*- C++ -*-===//
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// This file contains the mechanism for collecting the seed instructions that
9// are used as starting points for forming the vectorization graph.
10//===----------------------------------------------------------------------===//
11
12#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
13#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
14
15#include "llvm/ADT/BitVector.h"
21#include <iterator>
22#include <memory>
23
24namespace llvm::sandboxir {
25
26/// A set of candidate Instructions for vectorizing together.
28public:
29 /// Initialize a bundle with \p I.
30 explicit SeedBundle(Instruction *I) { insertAt(begin(), I); }
32 for (auto &S : Seeds)
34 }
35 /// No need to allow copies.
36 SeedBundle(const SeedBundle &) = delete;
37 SeedBundle &operator=(const SeedBundle &) = delete;
38 virtual ~SeedBundle() {}
39
42 iterator begin() { return Seeds.begin(); }
43 iterator end() { return Seeds.end(); }
44 const_iterator begin() const { return Seeds.begin(); }
45 const_iterator end() const { return Seeds.end(); }
46
47 Instruction *operator[](unsigned Idx) const { return Seeds[Idx]; }
48
49 /// Insert \p I into position \p P. Clients should choose Pos
50 /// by symbol, symbol-offset, and program order (which depends if scheduling
51 /// bottom-up or top-down).
53 Seeds.insert(Pos, I);
55 }
56
57 virtual void insert(Instruction *I, ScalarEvolution &SE) = 0;
58
59 unsigned getFirstUnusedElementIdx() const {
60 for (unsigned ElmIdx : seq<unsigned>(0, Seeds.size()))
61 if (!isUsed(ElmIdx))
62 return ElmIdx;
63 return Seeds.size();
64 }
65 /// Marks instruction \p I "used" within the bundle. Clients
66 /// use this property when assembling a vectorized instruction from
67 /// the seeds in a bundle. This allows constant time evaluation
68 /// and "removal" from the list.
70 auto It = std::find(begin(), end(), I);
71 assert(It != end() && "Instruction not in the bundle!");
72 auto Idx = It - begin();
73 setUsed(Idx, 1, /*VerifyUnused=*/false);
74 }
75
76 void setUsed(unsigned ElementIdx, unsigned Sz = 1, bool VerifyUnused = true) {
77 if (ElementIdx + Sz >= UsedLanes.size())
78 UsedLanes.resize(ElementIdx + Sz);
79 for (unsigned Idx : seq<unsigned>(ElementIdx, ElementIdx + Sz)) {
80 assert((!VerifyUnused || !UsedLanes.test(Idx)) &&
81 "Already marked as used!");
84 }
86 }
87 /// \Returns whether or not \p Element has been used.
88 bool isUsed(unsigned Element) const {
89 return Element < UsedLanes.size() && UsedLanes.test(Element);
90 }
91 bool allUsed() const { return UsedLaneCount == Seeds.size(); }
92 unsigned getNumUnusedBits() const { return NumUnusedBits; }
93
94 /// \Returns a slice of seed elements, starting at the element \p StartIdx,
95 /// with a total size <= \p MaxVecRegBits, or an empty slice if the
96 /// requirements cannot be met . If \p ForcePowOf2 is true, then the returned
97 /// slice will have a total number of bits that is a power of 2.
99 getSlice(unsigned StartIdx, unsigned MaxVecRegBits, bool ForcePowOf2);
100
101 /// \Returns the number of seed elements in the bundle.
102 std::size_t size() const { return Seeds.size(); }
103
104protected:
106 /// The lanes that we have already vectorized.
108 /// Tracks used lanes for constant-time accessor.
109 unsigned UsedLaneCount = 0;
110 /// Tracks the remaining bits available to vectorize
111 unsigned NumUnusedBits = 0;
112
113public:
114#ifndef NDEBUG
115 void dump(raw_ostream &OS) const {
116 for (auto [ElmIdx, I] : enumerate(*this)) {
117 OS.indent(2) << ElmIdx << ". ";
118 if (isUsed(ElmIdx))
119 OS << "[USED]";
120 else
121 OS << *I;
122 OS << "\n";
123 }
124 }
125 LLVM_DUMP_METHOD void dump() const {
126 dump(dbgs());
127 dbgs() << "\n";
128 }
129#endif // NDEBUG
130};
131
132/// Specialization of SeedBundle for memory access instructions. Keeps
133/// seeds sorted in ascending memory order, which is convenient for slicing
134/// these bundles into vectorizable groups.
135template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
136public:
138 : SeedBundle(std::move(SV)) {
139 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
140 std::is_same<LoadOrStoreT, StoreInst>::value,
141 "Expected LoadInst or StoreInst!");
142 assert(all_of(Seeds, [](auto *S) { return isa<LoadOrStoreT>(S); }) &&
143 "Expected Load or Store instructions!");
144 auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
145 return Utils::atLowerAddress(cast<LoadOrStoreT>(I0),
146 cast<LoadOrStoreT>(I1), SE);
147 };
148 std::sort(Seeds.begin(), Seeds.end(), Cmp);
149 }
150 explicit MemSeedBundle(LoadOrStoreT *MemI) : SeedBundle(MemI) {
151 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
152 std::is_same<LoadOrStoreT, StoreInst>::value,
153 "Expected LoadInst or StoreInst!");
154 assert(isa<LoadOrStoreT>(MemI) && "Expected Load or Store!");
155 }
157 assert(isa<LoadOrStoreT>(I) && "Expected a Store or a Load!");
158 auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
159 return Utils::atLowerAddress(cast<LoadOrStoreT>(I0),
160 cast<LoadOrStoreT>(I1), SE);
161 };
162 // Find the first element after I in mem. Then insert I before it.
163 insertAt(std::upper_bound(begin(), end(), I, Cmp), I);
164 }
165};
166
169
170/// Class to conveniently track Seeds within SeedBundles. Saves newly collected
171/// seeds in the proper bundle. Supports constant-time removal, as seeds and
172/// entire bundles are vectorized and marked used to signify removal. Iterators
173/// skip bundles that are completely used.
175 // Use the same key for different seeds if they are the same type and
176 // reference the same pointer, even if at different offsets. This directs
177 // potentially vectorizable seeds into the same bundle.
178 using KeyT = std::tuple<Value *, Type *, Instruction::Opcode>;
179 // Trying to vectorize too many seeds at once is expensive in
180 // compilation-time. Use a vector of bundles (all with the same key) to
181 // partition the candidate set into more manageable units. Each bundle is
182 // size-limited by sbvec-seed-bundle-size-limit. TODO: There might be a
183 // better way to divide these than by simple insertion order.
186 // Map from {pointer, Type, Opcode} to a vector of bundles.
187 BundleMapT Bundles;
188 // Allows finding a particular Instruction's bundle.
190
191 ScalarEvolution &SE;
192
193 template <typename LoadOrStoreT> KeyT getKey(LoadOrStoreT *LSI) const;
194
195public:
197
198 class iterator {
199 BundleMapT *Map = nullptr;
201 ValT *Vec = nullptr;
202 size_t VecIdx;
203
204 public:
205 using difference_type = std::ptrdiff_t;
209 using iterator_category = std::input_iterator_tag;
210
211 /// Iterates over the \p Map of SeedBundle Vectors, starting at \p MapIt,
212 /// and \p Vec at \p VecIdx, skipping vectors that are completely
213 /// used. Iteration order over the keys {Pointer, Type, Opcode} follows
214 /// DenseMap iteration order. For a given key, the vectors of
215 /// SeedBundles will be returned in insertion order. As in the
216 /// pseudo code below:
217 ///
218 /// for Key,Value in Bundles
219 /// for SeedBundleVector in Value
220 /// for SeedBundle in SeedBundleVector
221 /// if !SeedBundle.allUsed() ...
222 ///
223 /// Note that the bundles themselves may have additional ordering, created
224 /// by the subclasses by insertAt. The bundles themselves may also have used
225 /// instructions.
226
227 // TODO: Range_size counts fully used-bundles. Further, iterating over
228 // anything other than the Bundles in a SeedContainer includes used
229 // seeds. Rework the iterator logic to clean this up.
230 iterator(BundleMapT &Map, BundleMapT::iterator MapIt, ValT *Vec, int VecIdx)
231 : Map(&Map), MapIt(MapIt), Vec(Vec), VecIdx(VecIdx) {}
233 assert(Vec != nullptr && "Already at end!");
234 return *(*Vec)[VecIdx];
235 }
236 // Skip completely used bundles by repeatedly calling operator++().
237 void skipUsed() {
238 while (Vec && VecIdx < Vec->size() && this->operator*().allUsed())
239 ++(*this);
240 }
241 // Iterators iterate over the bundles
243 ++VecIdx;
244 if (VecIdx >= Vec->size()) {
245 assert(MapIt != Map->end() && "Already at end!");
246 VecIdx = 0;
247 ++MapIt;
248 if (MapIt != Map->end())
249 Vec = &MapIt->second;
250 else {
251 Vec = nullptr;
252 }
253 }
254 skipUsed();
255 return *this;
256 }
258 auto Copy = *this;
259 ++(*this);
260 return Copy;
261 }
262 bool operator==(const iterator &Other) const {
263 assert(Map == Other.Map && "Iterator of different objects!");
264 return MapIt == Other.MapIt && VecIdx == Other.VecIdx;
265 }
266 bool operator!=(const iterator &Other) const { return !(*this == Other); }
267 };
269 template <typename LoadOrStoreT> void insert(LoadOrStoreT *LSI);
270 // To support constant-time erase, these just mark the element used, rather
271 // than actually removing them from the bundle.
272 bool erase(Instruction *I);
273 bool erase(const KeyT &Key) { return Bundles.erase(Key); }
275 if (Bundles.empty())
276 return end();
277 auto BeginIt =
278 iterator(Bundles, Bundles.begin(), &Bundles.begin()->second, 0);
279 BeginIt.skipUsed();
280 return BeginIt;
281 }
282 iterator end() { return iterator(Bundles, Bundles.end(), nullptr, 0); }
283 unsigned size() const { return Bundles.size(); }
284
285#ifndef NDEBUG
286 void print(raw_ostream &OS) const;
287 LLVM_DUMP_METHOD void dump() const;
288#endif // NDEBUG
289};
290
292 SeedContainer StoreSeeds;
293 SeedContainer LoadSeeds;
294 Context &Ctx;
295 Context::CallbackID EraseCallbackID;
296 /// \Returns the number of SeedBundle groups for all seed types.
297 /// This is to be used for limiting compilation time.
298 unsigned totalNumSeedGroups() const {
299 return StoreSeeds.size() + LoadSeeds.size();
300 }
301
302public:
305
307 return {StoreSeeds.begin(), StoreSeeds.end()};
308 }
310 return {LoadSeeds.begin(), LoadSeeds.end()};
311 }
312#ifndef NDEBUG
313 void print(raw_ostream &OS) const;
314 LLVM_DUMP_METHOD void dump() const;
315#endif
316};
317
318} // namespace llvm::sandboxir
319
320#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
This file implements the BitVector class.
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:622
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
bool test(unsigned Idx) const
Definition: BitVector.h:461
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Definition: BitVector.h:341
BitVector & set()
Definition: BitVector.h:351
size_type size() const
size - Returns the number of bits in this bitvector.
Definition: BitVector.h:159
typename VectorType::iterator iterator
Definition: MapVector.h:49
iterator end()
Definition: MapVector.h:71
VectorType::iterator erase(typename VectorType::iterator Iterator)
Remove the element given by Iterator.
Definition: MapVector.h:193
bool empty() const
Definition: MapVector.h:79
iterator begin()
Definition: MapVector.h:69
size_type size() const
Definition: MapVector.h:60
typename VectorType::const_iterator const_iterator
Definition: MapVector.h:50
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:310
The main scalar evolution driver.
size_t size() const
Definition: SmallVector.h:78
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
Contains a list of sandboxir::Instruction's.
Definition: BasicBlock.h:67
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition: Instruction.h:42
Specialization of SeedBundle for memory access instructions.
MemSeedBundle(SmallVector< Instruction * > &&SV, ScalarEvolution &SE)
void insert(sandboxir::Instruction *I, ScalarEvolution &SE) override
MemSeedBundle(LoadOrStoreT *MemI)
A set of candidate Instructions for vectorizing together.
Definition: SeedCollector.h:27
SeedBundle & operator=(const SeedBundle &)=delete
bool isUsed(unsigned Element) const
\Returns whether or not Element has been used.
Definition: SeedCollector.h:88
SmallVector< Instruction * > Seeds
void setUsed(unsigned ElementIdx, unsigned Sz=1, bool VerifyUnused=true)
Definition: SeedCollector.h:76
void insertAt(iterator Pos, Instruction *I)
Insert I into position P.
Definition: SeedCollector.h:52
unsigned getNumUnusedBits() const
Definition: SeedCollector.h:92
const_iterator begin() const
Definition: SeedCollector.h:44
unsigned NumUnusedBits
Tracks the remaining bits available to vectorize.
SeedBundle(const SeedBundle &)=delete
No need to allow copies.
void setUsed(Instruction *I)
Marks instruction I "used" within the bundle.
Definition: SeedCollector.h:69
MutableArrayRef< Instruction * > getSlice(unsigned StartIdx, unsigned MaxVecRegBits, bool ForcePowOf2)
\Returns a slice of seed elements, starting at the element StartIdx, with a total size <= MaxVecRegBi...
SeedBundle(SmallVector< Instruction * > &&L)
Definition: SeedCollector.h:31
virtual void insert(Instruction *I, ScalarEvolution &SE)=0
SeedBundle(Instruction *I)
Initialize a bundle with I.
Definition: SeedCollector.h:30
unsigned getFirstUnusedElementIdx() const
Definition: SeedCollector.h:59
std::size_t size() const
\Returns the number of seed elements in the bundle.
Instruction * operator[](unsigned Idx) const
Definition: SeedCollector.h:47
BitVector UsedLanes
The lanes that we have already vectorized.
const_iterator end() const
Definition: SeedCollector.h:45
unsigned UsedLaneCount
Tracks used lanes for constant-time accessor.
void dump(raw_ostream &OS) const
LLVM_DUMP_METHOD void dump() const
iterator_range< SeedContainer::iterator > getLoadSeeds()
iterator_range< SeedContainer::iterator > getStoreSeeds()
void print(raw_ostream &OS) const
LLVM_DUMP_METHOD void dump() const
bool operator==(const iterator &Other) const
iterator(BundleMapT &Map, BundleMapT::iterator MapIt, ValT *Vec, int VecIdx)
Iterates over the Map of SeedBundle Vectors, starting at MapIt, and Vec at VecIdx,...
std::input_iterator_tag iterator_category
bool operator!=(const iterator &Other) const
Class to conveniently track Seeds within SeedBundles.
void print(raw_ostream &OS) const
void insert(LoadOrStoreT *LSI)
bool erase(const KeyT &Key)
SeedContainer(ScalarEvolution &SE)
BundleMapT::const_iterator const_iterator
LLVM_DUMP_METHOD void dump() const
bool erase(Instruction *I)
static unsigned getNumBits(Value *V, const DataLayout &DL)
\Returns the number of bits required to represent the operands or return value of V in DL.
Definition: Utils.h:65
static bool atLowerAddress(LoadOrStoreT *I0, LoadOrStoreT *I1, ScalarEvolution &SE)
\Returns true if I0 accesses a memory location lower than I1.
Definition: Utils.h:106
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
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
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition: STLExtras.h:2448
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
@ Other
Any other memory.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858