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_LEGALITY_H
0013 #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_LEGALITY_H
0014
0015 #include "llvm/ADT/ArrayRef.h"
0016 #include "llvm/Analysis/ScalarEvolution.h"
0017 #include "llvm/IR/DataLayout.h"
0018 #include "llvm/Support/Casting.h"
0019 #include "llvm/Support/raw_ostream.h"
0020 #include "llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h"
0021
0022 namespace llvm::sandboxir {
0023
0024 class LegalityAnalysis;
0025 class Value;
0026 class InstrMaps;
0027
0028 class ShuffleMask {
0029 public:
0030 using IndicesVecT = SmallVector<int, 8>;
0031
0032 private:
0033 IndicesVecT Indices;
0034
0035 public:
0036 ShuffleMask(SmallVectorImpl<int> &&Indices) : Indices(std::move(Indices)) {}
0037 ShuffleMask(std::initializer_list<int> Indices) : Indices(Indices) {}
0038 explicit ShuffleMask(ArrayRef<int> Indices) : Indices(Indices) {}
0039 operator ArrayRef<int>() const { return Indices; }
0040
0041
0042 static ShuffleMask getIdentity(unsigned Sz) {
0043 IndicesVecT Indices;
0044 Indices.reserve(Sz);
0045 for (auto Idx : seq<int>(0, (int)Sz))
0046 Indices.push_back(Idx);
0047 return ShuffleMask(std::move(Indices));
0048 }
0049
0050
0051 bool isIdentity() const {
0052 for (auto [Idx, Elm] : enumerate(Indices)) {
0053 if ((int)Idx != Elm)
0054 return false;
0055 }
0056 return true;
0057 }
0058 bool operator==(const ShuffleMask &Other) const {
0059 return Indices == Other.Indices;
0060 }
0061 bool operator!=(const ShuffleMask &Other) const { return !(*this == Other); }
0062 size_t size() const { return Indices.size(); }
0063 int operator[](int Idx) const { return Indices[Idx]; }
0064 using const_iterator = IndicesVecT::const_iterator;
0065 const_iterator begin() const { return Indices.begin(); }
0066 const_iterator end() const { return Indices.end(); }
0067 #ifndef NDEBUG
0068 friend raw_ostream &operator<<(raw_ostream &OS, const ShuffleMask &Mask) {
0069 Mask.print(OS);
0070 return OS;
0071 }
0072 void print(raw_ostream &OS) const {
0073 interleave(Indices, OS, [&OS](auto Elm) { OS << Elm; }, ",");
0074 }
0075 LLVM_DUMP_METHOD void dump() const;
0076 #endif
0077 };
0078
0079 enum class LegalityResultID {
0080 Pack,
0081 Widen,
0082 DiamondReuse,
0083 DiamondReuseWithShuffle,
0084 DiamondReuseMultiInput,
0085 };
0086
0087
0088 enum class ResultReason {
0089 NotInstructions,
0090 DiffOpcodes,
0091 DiffTypes,
0092 DiffMathFlags,
0093 DiffWrapFlags,
0094 DiffBBs,
0095 NotConsecutive,
0096 CantSchedule,
0097 Unimplemented,
0098 Infeasible,
0099 };
0100
0101 #ifndef NDEBUG
0102 struct ToStr {
0103 static const char *getLegalityResultID(LegalityResultID ID) {
0104 switch (ID) {
0105 case LegalityResultID::Pack:
0106 return "Pack";
0107 case LegalityResultID::Widen:
0108 return "Widen";
0109 case LegalityResultID::DiamondReuse:
0110 return "DiamondReuse";
0111 case LegalityResultID::DiamondReuseWithShuffle:
0112 return "DiamondReuseWithShuffle";
0113 case LegalityResultID::DiamondReuseMultiInput:
0114 return "DiamondReuseMultiInput";
0115 }
0116 llvm_unreachable("Unknown LegalityResultID enum");
0117 }
0118
0119 static const char *getVecReason(ResultReason Reason) {
0120 switch (Reason) {
0121 case ResultReason::NotInstructions:
0122 return "NotInstructions";
0123 case ResultReason::DiffOpcodes:
0124 return "DiffOpcodes";
0125 case ResultReason::DiffTypes:
0126 return "DiffTypes";
0127 case ResultReason::DiffMathFlags:
0128 return "DiffMathFlags";
0129 case ResultReason::DiffWrapFlags:
0130 return "DiffWrapFlags";
0131 case ResultReason::DiffBBs:
0132 return "DiffBBs";
0133 case ResultReason::NotConsecutive:
0134 return "NotConsecutive";
0135 case ResultReason::CantSchedule:
0136 return "CantSchedule";
0137 case ResultReason::Unimplemented:
0138 return "Unimplemented";
0139 case ResultReason::Infeasible:
0140 return "Infeasible";
0141 }
0142 llvm_unreachable("Unknown ResultReason enum");
0143 }
0144 };
0145 #endif
0146
0147
0148
0149
0150
0151 class LegalityResult {
0152 protected:
0153 LegalityResultID ID;
0154
0155 LegalityResult(LegalityResultID ID) : ID(ID) {}
0156 friend class LegalityAnalysis;
0157
0158
0159 LegalityResult(const LegalityResult &) = delete;
0160 LegalityResult &operator=(const LegalityResult &) = delete;
0161
0162 public:
0163 virtual ~LegalityResult() {}
0164 LegalityResultID getSubclassID() const { return ID; }
0165 #ifndef NDEBUG
0166 virtual void print(raw_ostream &OS) const {
0167 OS << ToStr::getLegalityResultID(ID);
0168 }
0169 LLVM_DUMP_METHOD void dump() const;
0170 friend raw_ostream &operator<<(raw_ostream &OS, const LegalityResult &LR) {
0171 LR.print(OS);
0172 return OS;
0173 }
0174 #endif
0175 };
0176
0177
0178 class LegalityResultWithReason : public LegalityResult {
0179 [[maybe_unused]] ResultReason Reason;
0180 LegalityResultWithReason(LegalityResultID ID, ResultReason Reason)
0181 : LegalityResult(ID), Reason(Reason) {}
0182 friend class Pack;
0183
0184 public:
0185 ResultReason getReason() const { return Reason; }
0186 #ifndef NDEBUG
0187 void print(raw_ostream &OS) const override {
0188 LegalityResult::print(OS);
0189 OS << " Reason: " << ToStr::getVecReason(Reason);
0190 }
0191 #endif
0192 };
0193
0194 class Widen final : public LegalityResult {
0195 friend class LegalityAnalysis;
0196 Widen() : LegalityResult(LegalityResultID::Widen) {}
0197
0198 public:
0199 static bool classof(const LegalityResult *From) {
0200 return From->getSubclassID() == LegalityResultID::Widen;
0201 }
0202 };
0203
0204 class DiamondReuse final : public LegalityResult {
0205 friend class LegalityAnalysis;
0206 Value *Vec;
0207 DiamondReuse(Value *Vec)
0208 : LegalityResult(LegalityResultID::DiamondReuse), Vec(Vec) {}
0209
0210 public:
0211 static bool classof(const LegalityResult *From) {
0212 return From->getSubclassID() == LegalityResultID::DiamondReuse;
0213 }
0214 Value *getVector() const { return Vec; }
0215 };
0216
0217 class DiamondReuseWithShuffle final : public LegalityResult {
0218 friend class LegalityAnalysis;
0219 Value *Vec;
0220 ShuffleMask Mask;
0221 DiamondReuseWithShuffle(Value *Vec, const ShuffleMask &Mask)
0222 : LegalityResult(LegalityResultID::DiamondReuseWithShuffle), Vec(Vec),
0223 Mask(Mask) {}
0224
0225 public:
0226 static bool classof(const LegalityResult *From) {
0227 return From->getSubclassID() == LegalityResultID::DiamondReuseWithShuffle;
0228 }
0229 Value *getVector() const { return Vec; }
0230 const ShuffleMask &getMask() const { return Mask; }
0231 };
0232
0233 class Pack final : public LegalityResultWithReason {
0234 Pack(ResultReason Reason)
0235 : LegalityResultWithReason(LegalityResultID::Pack, Reason) {}
0236 friend class LegalityAnalysis;
0237
0238 public:
0239 static bool classof(const LegalityResult *From) {
0240 return From->getSubclassID() == LegalityResultID::Pack;
0241 }
0242 };
0243
0244
0245 class CollectDescr {
0246 public:
0247
0248
0249 class ExtractElementDescr {
0250 Value *V;
0251
0252
0253 std::optional<int> ExtractIdx;
0254
0255 public:
0256 ExtractElementDescr(Value *V, int ExtractIdx)
0257 : V(V), ExtractIdx(ExtractIdx) {}
0258 ExtractElementDescr(Value *V) : V(V), ExtractIdx(std::nullopt) {}
0259 Value *getValue() const { return V; }
0260 bool needsExtract() const { return ExtractIdx.has_value(); }
0261 int getExtractIdx() const { return *ExtractIdx; }
0262 };
0263
0264 using DescrVecT = SmallVector<ExtractElementDescr, 4>;
0265 DescrVecT Descrs;
0266
0267 public:
0268 CollectDescr(SmallVectorImpl<ExtractElementDescr> &&Descrs)
0269 : Descrs(std::move(Descrs)) {}
0270
0271
0272 std::optional<std::pair<Value *, ShuffleMask>> getSingleInput() const {
0273 const auto &Descr0 = *Descrs.begin();
0274 Value *V0 = Descr0.getValue();
0275 if (!Descr0.needsExtract())
0276 return std::nullopt;
0277 ShuffleMask::IndicesVecT MaskIndices;
0278 MaskIndices.push_back(Descr0.getExtractIdx());
0279 for (const auto &Descr : drop_begin(Descrs)) {
0280 if (!Descr.needsExtract())
0281 return std::nullopt;
0282 if (Descr.getValue() != V0)
0283 return std::nullopt;
0284 MaskIndices.push_back(Descr.getExtractIdx());
0285 }
0286 return std::make_pair(V0, ShuffleMask(std::move(MaskIndices)));
0287 }
0288 bool hasVectorInputs() const {
0289 return any_of(Descrs, [](const auto &D) { return D.needsExtract(); });
0290 }
0291 const SmallVector<ExtractElementDescr, 4> &getDescrs() const {
0292 return Descrs;
0293 }
0294 };
0295
0296 class DiamondReuseMultiInput final : public LegalityResult {
0297 friend class LegalityAnalysis;
0298 CollectDescr Descr;
0299 DiamondReuseMultiInput(CollectDescr &&Descr)
0300 : LegalityResult(LegalityResultID::DiamondReuseMultiInput),
0301 Descr(std::move(Descr)) {}
0302
0303 public:
0304 static bool classof(const LegalityResult *From) {
0305 return From->getSubclassID() == LegalityResultID::DiamondReuseMultiInput;
0306 }
0307 const CollectDescr &getCollectDescr() const { return Descr; }
0308 };
0309
0310
0311 class LegalityAnalysis {
0312 Scheduler Sched;
0313
0314 SmallVector<std::unique_ptr<LegalityResult>> ResultPool;
0315
0316
0317 std::optional<ResultReason>
0318 notVectorizableBasedOnOpcodesAndTypes(ArrayRef<Value *> Bndl);
0319
0320 ScalarEvolution &SE;
0321 const DataLayout &DL;
0322 InstrMaps &IMaps;
0323
0324
0325
0326
0327 CollectDescr getHowToCollectValues(ArrayRef<Value *> Bndl) const;
0328
0329 public:
0330 LegalityAnalysis(AAResults &AA, ScalarEvolution &SE, const DataLayout &DL,
0331 Context &Ctx, InstrMaps &IMaps)
0332 : Sched(AA, Ctx), SE(SE), DL(DL), IMaps(IMaps) {}
0333
0334 template <typename ResultT, typename... ArgsT>
0335 ResultT &createLegalityResult(ArgsT &&...Args) {
0336 ResultPool.push_back(
0337 std::unique_ptr<ResultT>(new ResultT(std::move(Args)...)));
0338 return cast<ResultT>(*ResultPool.back());
0339 }
0340
0341
0342
0343
0344 const LegalityResult &canVectorize(ArrayRef<Value *> Bndl,
0345 bool SkipScheduling = false);
0346 void clear();
0347 };
0348
0349 }
0350
0351 #endif