@@ -54,6 +54,8 @@ class SeedBundle {
54
54
NumUnusedBits += Utils::getNumBits (I);
55
55
}
56
56
57
+ virtual void insert (Instruction *I, ScalarEvolution &SE) = 0;
58
+
57
59
unsigned getFirstUnusedElementIdx () const {
58
60
for (unsigned ElmIdx : seq<unsigned >(0 , Seeds.size ()))
59
61
if (!isUsed (ElmIdx))
@@ -96,6 +98,9 @@ class SeedBundle {
96
98
MutableArrayRef<Instruction *>
97
99
getSlice (unsigned StartIdx, unsigned MaxVecRegBits, bool ForcePowOf2);
98
100
101
+ // / \Returns the number of seed elements in the bundle.
102
+ std::size_t size () const { return Seeds.size (); }
103
+
99
104
protected:
100
105
SmallVector<Instruction *> Seeds;
101
106
// / The lanes that we have already vectorized.
@@ -148,7 +153,7 @@ template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
148
153
" Expected LoadInst or StoreInst!" );
149
154
assert (isa<LoadOrStoreT>(MemI) && " Expected Load or Store!" );
150
155
}
151
- void insert (sandboxir::Instruction *I, ScalarEvolution &SE) {
156
+ void insert (sandboxir::Instruction *I, ScalarEvolution &SE) override {
152
157
assert (isa<LoadOrStoreT>(I) && " Expected a Store or a Load!" );
153
158
auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
154
159
return Utils::atLowerAddress (cast<LoadOrStoreT>(I0),
@@ -162,5 +167,123 @@ template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
162
167
using StoreSeedBundle = MemSeedBundle<sandboxir::StoreInst>;
163
168
using LoadSeedBundle = MemSeedBundle<sandboxir::LoadInst>;
164
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.
174
+ class SeedContainer {
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.
184
+ using ValT = SmallVector<std::unique_ptr<SeedBundle>>;
185
+ using BundleMapT = MapVector<KeyT, ValT>;
186
+ // Map from {pointer, Type, Opcode} to a vector of bundles.
187
+ BundleMapT Bundles;
188
+ // Allows finding a particular Instruction's bundle.
189
+ DenseMap<Instruction *, SeedBundle *> SeedLookupMap;
190
+
191
+ ScalarEvolution &SE;
192
+
193
+ template <typename LoadOrStoreT> KeyT getKey (LoadOrStoreT *LSI) const ;
194
+
195
+ public:
196
+ SeedContainer (ScalarEvolution &SE) : SE(SE) {}
197
+
198
+ class iterator {
199
+ BundleMapT *Map = nullptr ;
200
+ BundleMapT::iterator MapIt;
201
+ ValT *Vec = nullptr ;
202
+ size_t VecIdx;
203
+
204
+ public:
205
+ using difference_type = std::ptrdiff_t ;
206
+ using value_type = SeedBundle;
207
+ using pointer = value_type *;
208
+ using reference = value_type &;
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
+ iterator (BundleMapT &Map, BundleMapT::iterator MapIt, ValT *Vec, int VecIdx)
227
+ : Map(&Map), MapIt(MapIt), Vec(Vec), VecIdx(VecIdx) {}
228
+ value_type &operator *() {
229
+ assert (Vec != nullptr && " Already at end!" );
230
+ return *(*Vec)[VecIdx];
231
+ }
232
+ // Skip completely used bundles by repeatedly calling operator++().
233
+ void skipUsed () {
234
+ while (Vec && VecIdx < Vec->size () && this ->operator *().allUsed ())
235
+ ++(*this );
236
+ }
237
+ // Iterators iterate over the bundles
238
+ iterator &operator ++() {
239
+ assert (VecIdx >= 0 && " Already at end!" );
240
+ ++VecIdx;
241
+ if (VecIdx >= Vec->size ()) {
242
+ assert (MapIt != Map->end () && " Already at end!" );
243
+ VecIdx = 0 ;
244
+ ++MapIt;
245
+ if (MapIt != Map->end ())
246
+ Vec = &MapIt->second ;
247
+ else {
248
+ Vec = nullptr ;
249
+ }
250
+ }
251
+ skipUsed ();
252
+ return *this ;
253
+ }
254
+ iterator operator ++(int ) {
255
+ auto Copy = *this ;
256
+ ++(*this );
257
+ return Copy;
258
+ }
259
+ bool operator ==(const iterator &Other) const {
260
+ assert (Map == Other.Map && " Iterator of different objects!" );
261
+ return MapIt == Other.MapIt && VecIdx == Other.VecIdx ;
262
+ }
263
+ bool operator !=(const iterator &Other) const { return !(*this == Other); }
264
+ };
265
+ using const_iterator = BundleMapT::const_iterator;
266
+ template <typename LoadOrStoreT> void insert (LoadOrStoreT *LSI);
267
+ // To support constant-time erase, these just mark the element used, rather
268
+ // than actually removing them from the bundle.
269
+ bool erase (Instruction *I);
270
+ bool erase (const KeyT &Key) { return Bundles.erase (Key); }
271
+ iterator begin () {
272
+ if (Bundles.empty ())
273
+ return end ();
274
+ auto BeginIt =
275
+ iterator (Bundles, Bundles.begin (), &Bundles.begin ()->second , 0 );
276
+ BeginIt.skipUsed ();
277
+ return BeginIt;
278
+ }
279
+ iterator end () { return iterator (Bundles, Bundles.end (), nullptr , 0 ); }
280
+ unsigned size () const { return Bundles.size (); }
281
+
282
+ #ifndef NDEBUG
283
+ LLVM_DUMP_METHOD void dump () const ;
284
+ #endif // NDEBUG
285
+ };
286
+
165
287
} // namespace llvm::sandboxir
288
+
166
289
#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
0 commit comments