File indexing completed on 2026-05-10 08:44:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
0013 #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H
0014
0015 #include "llvm/ADT/BitVector.h"
0016 #include "llvm/ADT/iterator_range.h"
0017 #include "llvm/Analysis/ScalarEvolution.h"
0018 #include "llvm/SandboxIR/Instruction.h"
0019 #include "llvm/SandboxIR/Utils.h"
0020 #include "llvm/SandboxIR/Value.h"
0021 #include <iterator>
0022 #include <memory>
0023
0024 namespace llvm::sandboxir {
0025
0026
0027 class SeedBundle {
0028 public:
0029
0030 explicit SeedBundle(Instruction *I) { insertAt(begin(), I); }
0031 explicit SeedBundle(SmallVector<Instruction *> &&L) : Seeds(std::move(L)) {
0032 for (auto &S : Seeds)
0033 NumUnusedBits += Utils::getNumBits(S);
0034 }
0035
0036 SeedBundle(const SeedBundle &) = delete;
0037 SeedBundle &operator=(const SeedBundle &) = delete;
0038 virtual ~SeedBundle() {}
0039
0040 using iterator = SmallVector<Instruction *>::iterator;
0041 using const_iterator = SmallVector<Instruction *>::const_iterator;
0042 iterator begin() { return Seeds.begin(); }
0043 iterator end() { return Seeds.end(); }
0044 const_iterator begin() const { return Seeds.begin(); }
0045 const_iterator end() const { return Seeds.end(); }
0046
0047 Instruction *operator[](unsigned Idx) const { return Seeds[Idx]; }
0048
0049
0050
0051
0052 void insertAt(iterator Pos, Instruction *I) {
0053 Seeds.insert(Pos, I);
0054 NumUnusedBits += Utils::getNumBits(I);
0055 }
0056
0057 virtual void insert(Instruction *I, ScalarEvolution &SE) = 0;
0058
0059 unsigned getFirstUnusedElementIdx() const {
0060 for (unsigned ElmIdx : seq<unsigned>(0, Seeds.size()))
0061 if (!isUsed(ElmIdx))
0062 return ElmIdx;
0063 return Seeds.size();
0064 }
0065
0066
0067
0068
0069 void setUsed(Instruction *I) {
0070 auto It = std::find(begin(), end(), I);
0071 assert(It != end() && "Instruction not in the bundle!");
0072 auto Idx = It - begin();
0073 setUsed(Idx, 1, false);
0074 }
0075
0076 void setUsed(unsigned ElementIdx, unsigned Sz = 1, bool VerifyUnused = true) {
0077 if (ElementIdx + Sz >= UsedLanes.size())
0078 UsedLanes.resize(ElementIdx + Sz);
0079 for (unsigned Idx : seq<unsigned>(ElementIdx, ElementIdx + Sz)) {
0080 assert((!VerifyUnused || !UsedLanes.test(Idx)) &&
0081 "Already marked as used!");
0082 UsedLanes.set(Idx);
0083 UsedLaneCount++;
0084 }
0085 NumUnusedBits -= Utils::getNumBits(Seeds[ElementIdx]);
0086 }
0087
0088 bool isUsed(unsigned Element) const {
0089 return Element < UsedLanes.size() && UsedLanes.test(Element);
0090 }
0091 bool allUsed() const { return UsedLaneCount == Seeds.size(); }
0092 unsigned getNumUnusedBits() const { return NumUnusedBits; }
0093
0094
0095
0096
0097
0098 ArrayRef<Instruction *> getSlice(unsigned StartIdx, unsigned MaxVecRegBits,
0099 bool ForcePowOf2);
0100
0101
0102 std::size_t size() const { return Seeds.size(); }
0103
0104 protected:
0105 SmallVector<Instruction *> Seeds;
0106
0107 BitVector UsedLanes;
0108
0109 unsigned UsedLaneCount = 0;
0110
0111 unsigned NumUnusedBits = 0;
0112
0113 public:
0114 #ifndef NDEBUG
0115 void dump(raw_ostream &OS) const {
0116 for (auto [ElmIdx, I] : enumerate(*this)) {
0117 OS.indent(2) << ElmIdx << ". ";
0118 if (isUsed(ElmIdx))
0119 OS << "[USED]";
0120 else
0121 OS << *I;
0122 OS << "\n";
0123 }
0124 }
0125 LLVM_DUMP_METHOD void dump() const {
0126 dump(dbgs());
0127 dbgs() << "\n";
0128 }
0129 #endif
0130 };
0131
0132
0133
0134
0135 template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
0136 public:
0137 explicit MemSeedBundle(SmallVector<Instruction *> &&SV, ScalarEvolution &SE)
0138 : SeedBundle(std::move(SV)) {
0139 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
0140 std::is_same<LoadOrStoreT, StoreInst>::value,
0141 "Expected LoadInst or StoreInst!");
0142 assert(all_of(Seeds, [](auto *S) { return isa<LoadOrStoreT>(S); }) &&
0143 "Expected Load or Store instructions!");
0144 auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
0145 return Utils::atLowerAddress(cast<LoadOrStoreT>(I0),
0146 cast<LoadOrStoreT>(I1), SE);
0147 };
0148 std::sort(Seeds.begin(), Seeds.end(), Cmp);
0149 }
0150 explicit MemSeedBundle(LoadOrStoreT *MemI) : SeedBundle(MemI) {
0151 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
0152 std::is_same<LoadOrStoreT, StoreInst>::value,
0153 "Expected LoadInst or StoreInst!");
0154 assert(isa<LoadOrStoreT>(MemI) && "Expected Load or Store!");
0155 }
0156 void insert(sandboxir::Instruction *I, ScalarEvolution &SE) override {
0157 assert(isa<LoadOrStoreT>(I) && "Expected a Store or a Load!");
0158 auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
0159 return Utils::atLowerAddress(cast<LoadOrStoreT>(I0),
0160 cast<LoadOrStoreT>(I1), SE);
0161 };
0162
0163 insertAt(std::upper_bound(begin(), end(), I, Cmp), I);
0164 }
0165 };
0166
0167 using StoreSeedBundle = MemSeedBundle<sandboxir::StoreInst>;
0168 using LoadSeedBundle = MemSeedBundle<sandboxir::LoadInst>;
0169
0170
0171
0172
0173
0174 class SeedContainer {
0175
0176
0177
0178 using KeyT = std::tuple<Value *, Type *, Instruction::Opcode>;
0179
0180
0181
0182
0183
0184 using ValT = SmallVector<std::unique_ptr<SeedBundle>>;
0185 using BundleMapT = MapVector<KeyT, ValT>;
0186
0187 BundleMapT Bundles;
0188
0189 DenseMap<Instruction *, SeedBundle *> SeedLookupMap;
0190
0191 ScalarEvolution &SE;
0192
0193 template <typename LoadOrStoreT> KeyT getKey(LoadOrStoreT *LSI) const;
0194
0195 public:
0196 SeedContainer(ScalarEvolution &SE) : SE(SE) {}
0197
0198 class iterator {
0199 BundleMapT *Map = nullptr;
0200 BundleMapT::iterator MapIt;
0201 ValT *Vec = nullptr;
0202 size_t VecIdx;
0203
0204 public:
0205 using difference_type = std::ptrdiff_t;
0206 using value_type = SeedBundle;
0207 using pointer = value_type *;
0208 using reference = value_type &;
0209 using iterator_category = std::input_iterator_tag;
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 iterator(BundleMapT &Map, BundleMapT::iterator MapIt, ValT *Vec, int VecIdx)
0231 : Map(&Map), MapIt(MapIt), Vec(Vec), VecIdx(VecIdx) {}
0232 value_type &operator*() {
0233 assert(Vec != nullptr && "Already at end!");
0234 return *(*Vec)[VecIdx];
0235 }
0236
0237 void skipUsed() {
0238 while (Vec && VecIdx < Vec->size() && this->operator*().allUsed())
0239 ++(*this);
0240 }
0241
0242 iterator &operator++() {
0243 ++VecIdx;
0244 if (VecIdx >= Vec->size()) {
0245 assert(MapIt != Map->end() && "Already at end!");
0246 VecIdx = 0;
0247 ++MapIt;
0248 if (MapIt != Map->end())
0249 Vec = &MapIt->second;
0250 else {
0251 Vec = nullptr;
0252 }
0253 }
0254 skipUsed();
0255 return *this;
0256 }
0257 iterator operator++(int) {
0258 auto Copy = *this;
0259 ++(*this);
0260 return Copy;
0261 }
0262 bool operator==(const iterator &Other) const {
0263 assert(Map == Other.Map && "Iterator of different objects!");
0264 return MapIt == Other.MapIt && VecIdx == Other.VecIdx;
0265 }
0266 bool operator!=(const iterator &Other) const { return !(*this == Other); }
0267 };
0268 using const_iterator = BundleMapT::const_iterator;
0269 template <typename LoadOrStoreT> void insert(LoadOrStoreT *LSI);
0270
0271
0272 bool erase(Instruction *I);
0273 bool erase(const KeyT &Key) { return Bundles.erase(Key); }
0274 iterator begin() {
0275 if (Bundles.empty())
0276 return end();
0277 auto BeginIt =
0278 iterator(Bundles, Bundles.begin(), &Bundles.begin()->second, 0);
0279 BeginIt.skipUsed();
0280 return BeginIt;
0281 }
0282 iterator end() { return iterator(Bundles, Bundles.end(), nullptr, 0); }
0283 unsigned size() const { return Bundles.size(); }
0284
0285 #ifndef NDEBUG
0286 void print(raw_ostream &OS) const;
0287 LLVM_DUMP_METHOD void dump() const;
0288 #endif
0289 };
0290
0291 class SeedCollector {
0292 SeedContainer StoreSeeds;
0293 SeedContainer LoadSeeds;
0294 Context &Ctx;
0295 Context::CallbackID EraseCallbackID;
0296
0297
0298 unsigned totalNumSeedGroups() const {
0299 return StoreSeeds.size() + LoadSeeds.size();
0300 }
0301
0302 public:
0303 SeedCollector(BasicBlock *BB, ScalarEvolution &SE);
0304 ~SeedCollector();
0305
0306 iterator_range<SeedContainer::iterator> getStoreSeeds() {
0307 return {StoreSeeds.begin(), StoreSeeds.end()};
0308 }
0309 iterator_range<SeedContainer::iterator> getLoadSeeds() {
0310 return {LoadSeeds.begin(), LoadSeeds.end()};
0311 }
0312 #ifndef NDEBUG
0313 void print(raw_ostream &OS) const;
0314 LLVM_DUMP_METHOD void dump() const;
0315 #endif
0316 };
0317
0318 }
0319
0320 #endif