@@ -54,6 +54,8 @@ class SeedBundle {
5454 NumUnusedBits += Utils::getNumBits (I);
5555 }
5656
57+ virtual void insert (Instruction *I, ScalarEvolution &SE) = 0;
58+
5759 unsigned getFirstUnusedElementIdx () const {
5860 for (unsigned ElmIdx : seq<unsigned >(0 , Seeds.size ()))
5961 if (!isUsed (ElmIdx))
@@ -96,6 +98,9 @@ class SeedBundle {
9698 MutableArrayRef<Instruction *>
9799 getSlice (unsigned StartIdx, unsigned MaxVecRegBits, bool ForcePowOf2);
98100
101+ // / \Returns the number of seed elements in the bundle.
102+ std::size_t size () const { return Seeds.size (); }
103+
99104protected:
100105 SmallVector<Instruction *> Seeds;
101106 // / The lanes that we have already vectorized.
@@ -148,7 +153,7 @@ template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
148153 " Expected LoadInst or StoreInst!" );
149154 assert (isa<LoadOrStoreT>(MemI) && " Expected Load or Store!" );
150155 }
151- void insert (sandboxir::Instruction *I, ScalarEvolution &SE) {
156+ void insert (sandboxir::Instruction *I, ScalarEvolution &SE) override {
152157 assert (isa<LoadOrStoreT>(I) && " Expected a Store or a Load!" );
153158 auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
154159 return Utils::atLowerAddress (cast<LoadOrStoreT>(I0),
@@ -162,5 +167,123 @@ template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
162167using StoreSeedBundle = MemSeedBundle<sandboxir::StoreInst>;
163168using LoadSeedBundle = MemSeedBundle<sandboxir::LoadInst>;
164169
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+
165287} // namespace llvm::sandboxir
288+
166289#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
0 commit comments