LLVM 22.0.0git
Legality.h
Go to the documentation of this file.
1//===- Legality.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//
9// Legality checks for the Sandbox Vectorizer.
10//
11
12#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_LEGALITY_H
13#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_LEGALITY_H
14
15#include "llvm/ADT/ArrayRef.h"
17#include "llvm/IR/DataLayout.h"
23
24namespace llvm::sandboxir {
25
27class Value;
28class InstrMaps;
29
31public:
33
34private:
35 IndicesVecT Indices;
36
37public:
38 ShuffleMask(SmallVectorImpl<int> &&Indices) : Indices(std::move(Indices)) {}
39 ShuffleMask(std::initializer_list<int> Indices) : Indices(Indices) {}
40 explicit ShuffleMask(ArrayRef<int> Indices) : Indices(Indices) {}
41 operator ArrayRef<int>() const { return Indices; }
42 /// Creates and returns an identity shuffle mask of size \p Sz.
43 /// For example if Sz == 4 the returned mask is {0, 1, 2, 3}.
44 static ShuffleMask getIdentity(unsigned Sz) {
45 IndicesVecT Indices;
46 Indices.reserve(Sz);
47 llvm::append_range(Indices, seq<int>(0, (int)Sz));
48 return ShuffleMask(std::move(Indices));
49 }
50 /// \Returns true if the mask is a perfect identity mask with consecutive
51 /// indices, i.e., performs no lane shuffling, like 0,1,2,3...
52 bool isIdentity() const {
53 for (auto [Idx, Elm] : enumerate(Indices)) {
54 if ((int)Idx != Elm)
55 return false;
56 }
57 return true;
58 }
59 bool operator==(const ShuffleMask &Other) const {
60 return Indices == Other.Indices;
61 }
62 bool operator!=(const ShuffleMask &Other) const { return !(*this == Other); }
63 size_t size() const { return Indices.size(); }
64 int operator[](int Idx) const { return Indices[Idx]; }
66 const_iterator begin() const { return Indices.begin(); }
67 const_iterator end() const { return Indices.end(); }
68#ifndef NDEBUG
69 friend raw_ostream &operator<<(raw_ostream &OS, const ShuffleMask &Mask) {
70 Mask.print(OS);
71 return OS;
72 }
73 void print(raw_ostream &OS) const {
74 interleave(Indices, OS, [&OS](auto Elm) { OS << Elm; }, ",");
75 }
76 LLVM_DUMP_METHOD void dump() const;
77#endif
78};
79
80enum class LegalityResultID {
81 Pack, ///> Collect scalar values.
82 Widen, ///> Vectorize by combining scalars to a vector.
83 DiamondReuse, ///> Don't generate new code, reuse existing vector.
84 DiamondReuseWithShuffle, ///> Reuse the existing vector but add a shuffle.
85 DiamondReuseMultiInput, ///> Reuse more than one vector and/or scalars.
86};
87
88/// The reason for vectorizing or not vectorizing.
103
104#ifndef NDEBUG
105struct ToStr {
107 switch (ID) {
109 return "Pack";
111 return "Widen";
113 return "DiamondReuse";
115 return "DiamondReuseWithShuffle";
117 return "DiamondReuseMultiInput";
118 }
119 llvm_unreachable("Unknown LegalityResultID enum");
120 }
121
122 static const char *getVecReason(ResultReason Reason) {
123 switch (Reason) {
125 return "NotInstructions";
127 return "DiffOpcodes";
129 return "DiffTypes";
131 return "DiffMathFlags";
133 return "DiffWrapFlags";
135 return "DiffBBs";
137 return "RepeatedInstrs";
139 return "NotConsecutive";
141 return "CantSchedule";
143 return "Unimplemented";
145 return "Infeasible";
147 return "ForcePackForDebugging";
148 }
149 llvm_unreachable("Unknown ResultReason enum");
150 }
151};
152#endif // NDEBUG
153
154/// The legality outcome is represented by a class rather than an enum class
155/// because in some cases the legality checks are expensive and look for a
156/// particular instruction that can be passed along to the vectorizer to avoid
157/// repeating the same expensive computation.
159protected:
161 /// Only Legality can create LegalityResults.
163 friend class LegalityAnalysis;
164
165 /// We shouldn't need copies.
168
169public:
170 virtual ~LegalityResult() {}
172#ifndef NDEBUG
173 virtual void print(raw_ostream &OS) const {
175 }
176 LLVM_DUMP_METHOD void dump() const;
178 LR.print(OS);
179 return OS;
180 }
181#endif // NDEBUG
182};
183
184/// Base class for results with reason.
185class LegalityResultWithReason : public LegalityResult {
186 [[maybe_unused]] ResultReason Reason;
187 LegalityResultWithReason(LegalityResultID ID, ResultReason Reason)
188 : LegalityResult(ID), Reason(Reason) {}
189 friend class Pack; // For constructor.
190
191public:
192 ResultReason getReason() const { return Reason; }
193#ifndef NDEBUG
194 void print(raw_ostream &OS) const override {
196 OS << " Reason: " << ToStr::getVecReason(Reason);
197 }
198#endif
199};
200
201class Widen final : public LegalityResult {
202 friend class LegalityAnalysis;
204
205public:
206 static bool classof(const LegalityResult *From) {
207 return From->getSubclassID() == LegalityResultID::Widen;
208 }
209};
210
211class DiamondReuse final : public LegalityResult {
212 friend class LegalityAnalysis;
213 Action *Vec;
214 DiamondReuse(Action *Vec)
215 : LegalityResult(LegalityResultID::DiamondReuse), Vec(Vec) {}
216
217public:
218 static bool classof(const LegalityResult *From) {
220 }
221 Action *getVector() const { return Vec; }
222};
223
224class DiamondReuseWithShuffle final : public LegalityResult {
225 friend class LegalityAnalysis;
226 Action *Vec;
227 ShuffleMask Mask;
229 : LegalityResult(LegalityResultID::DiamondReuseWithShuffle), Vec(Vec),
230 Mask(Mask) {}
231
232public:
233 static bool classof(const LegalityResult *From) {
235 }
236 Action *getVector() const { return Vec; }
237 const ShuffleMask &getMask() const { return Mask; }
238};
239
240class Pack final : public LegalityResultWithReason {
241 Pack(ResultReason Reason)
242 : LegalityResultWithReason(LegalityResultID::Pack, Reason) {}
243 friend class LegalityAnalysis; // For constructor.
244
245public:
246 static bool classof(const LegalityResult *From) {
247 return From->getSubclassID() == LegalityResultID::Pack;
248 }
249};
250
251/// Describes how to collect the values needed by each lane.
253public:
254 /// Describes how to get a value element. If the value is a vector then it
255 /// also provides the index to extract it from.
258 /// The index in `V` that the value can be extracted from.
259 int ExtractIdx = 0;
260
261 public:
262 ExtractElementDescr(Action *V, int ExtractIdx)
263 : V(V), ExtractIdx(ExtractIdx) {}
265 Action *getValue() const { return cast<Action *>(V); }
266 Value *getScalar() const { return cast<Value *>(V); }
267 bool needsExtract() const { return isa<Action *>(V); }
268 int getExtractIdx() const { return ExtractIdx; }
269 };
270
273
274public:
277 /// If all elements come from a single vector input, then return that vector
278 /// and also the shuffle mask required to get them in order.
279 std::optional<std::pair<Action *, ShuffleMask>> getSingleInput() const {
280 const auto &Descr0 = *Descrs.begin();
281 if (!Descr0.needsExtract())
282 return std::nullopt;
283 auto *V0 = Descr0.getValue();
284 ShuffleMask::IndicesVecT MaskIndices;
285 MaskIndices.push_back(Descr0.getExtractIdx());
286 for (const auto &Descr : drop_begin(Descrs)) {
287 if (!Descr.needsExtract())
288 return std::nullopt;
289 if (Descr.getValue() != V0)
290 return std::nullopt;
291 MaskIndices.push_back(Descr.getExtractIdx());
292 }
293 return std::make_pair(V0, ShuffleMask(std::move(MaskIndices)));
294 }
295 bool hasVectorInputs() const {
296 return any_of(Descrs, [](const auto &D) { return D.needsExtract(); });
297 }
299 return Descrs;
300 }
301};
302
303class DiamondReuseMultiInput final : public LegalityResult {
304 friend class LegalityAnalysis;
305 CollectDescr Descr;
307 : LegalityResult(LegalityResultID::DiamondReuseMultiInput),
308 Descr(std::move(Descr)) {}
309
310public:
311 static bool classof(const LegalityResult *From) {
313 }
314 const CollectDescr &getCollectDescr() const { return Descr; }
315};
316
317/// Performs the legality analysis and returns a LegalityResult object.
319 Scheduler Sched;
320 /// Owns the legality result objects created by createLegalityResult().
322 /// Checks opcodes, types and other IR-specifics and returns a ResultReason
323 /// object if not vectorizable, or nullptr otherwise.
324 std::optional<ResultReason>
325 notVectorizableBasedOnOpcodesAndTypes(ArrayRef<Value *> Bndl);
326
327 ScalarEvolution &SE;
328 const DataLayout &DL;
329 InstrMaps &IMaps;
330
331 /// Finds how we can collect the values in \p Bndl from the vectorized or
332 /// non-vectorized code. It returns a map of the value we should extract from
333 /// and the corresponding shuffle mask we need to use.
334 CollectDescr getHowToCollectValues(ArrayRef<Value *> Bndl) const;
335
336public:
338 Context &Ctx, InstrMaps &IMaps)
339 : Sched(AA, Ctx), SE(SE), DL(DL), IMaps(IMaps) {}
340 /// A LegalityResult factory.
341 template <typename ResultT, typename... ArgsT>
342 ResultT &createLegalityResult(ArgsT &&...Args) {
343 ResultPool.push_back(
344 std::unique_ptr<ResultT>(new ResultT(std::move(Args)...)));
345 return cast<ResultT>(*ResultPool.back());
346 }
347 /// Checks if it's legal to vectorize the instructions in \p Bndl.
348 /// \Returns a LegalityResult object owned by LegalityAnalysis.
349 /// \p SkipScheduling skips the scheduler check and is only meant for testing.
350 // TODO: Try to remove the SkipScheduling argument by refactoring the tests.
352 bool SkipScheduling = false);
353 /// \Returns a Pack with reason 'ForcePackForDebugging'.
357 LLVM_ABI void clear();
358};
359
360} // namespace llvm::sandboxir
361
362#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_LEGALITY_H
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_ABI
Definition Compiler.h:213
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:638
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:63
A discriminated union of two or more pointer types, with the discriminator in the low bit of the poin...
The main scalar evolution driver.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
typename SuperClass::const_iterator const_iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
ExtractElementDescr(Action *V, int ExtractIdx)
Definition Legality.h:262
Describes how to collect the values needed by each lane.
Definition Legality.h:252
const SmallVector< ExtractElementDescr, 4 > & getDescrs() const
Definition Legality.h:298
SmallVector< ExtractElementDescr, 4 > DescrVecT
Definition Legality.h:271
std::optional< std::pair< Action *, ShuffleMask > > getSingleInput() const
If all elements come from a single vector input, then return that vector and also the shuffle mask re...
Definition Legality.h:279
CollectDescr(SmallVectorImpl< ExtractElementDescr > &&Descrs)
Definition Legality.h:275
static bool classof(const LegalityResult *From)
Definition Legality.h:311
const CollectDescr & getCollectDescr() const
Definition Legality.h:314
const ShuffleMask & getMask() const
Definition Legality.h:237
static bool classof(const LegalityResult *From)
Definition Legality.h:233
Action * getVector() const
Definition Legality.h:221
static bool classof(const LegalityResult *From)
Definition Legality.h:218
Maps the original instructions to the vectorized instrs and the reverse.
Definition InstrMaps.h:51
Performs the legality analysis and returns a LegalityResult object.
Definition Legality.h:318
const LegalityResult & getForcedPackForDebugging()
\Returns a Pack with reason 'ForcePackForDebugging'.
Definition Legality.h:354
LLVM_ABI const LegalityResult & canVectorize(ArrayRef< Value * > Bndl, bool SkipScheduling=false)
Checks if it's legal to vectorize the instructions in Bndl.
Definition Legality.cpp:212
LegalityAnalysis(AAResults &AA, ScalarEvolution &SE, const DataLayout &DL, Context &Ctx, InstrMaps &IMaps)
Definition Legality.h:337
ResultT & createLegalityResult(ArgsT &&...Args)
A LegalityResult factory.
Definition Legality.h:342
void print(raw_ostream &OS) const override
Definition Legality.h:194
The legality outcome is represented by a class rather than an enum class because in some cases the le...
Definition Legality.h:158
LegalityResult & operator=(const LegalityResult &)=delete
friend raw_ostream & operator<<(raw_ostream &OS, const LegalityResult &LR)
Definition Legality.h:177
LLVM_DUMP_METHOD void dump() const
Definition Legality.cpp:26
LegalityResultID getSubclassID() const
Definition Legality.h:171
virtual void print(raw_ostream &OS) const
Definition Legality.h:173
LegalityResult(LegalityResultID ID)
Only Legality can create LegalityResults.
Definition Legality.h:162
LegalityResult(const LegalityResult &)=delete
We shouldn't need copies.
friend class LegalityAnalysis
Definition Legality.h:243
static bool classof(const LegalityResult *From)
Definition Legality.h:246
The list scheduler.
Definition Scheduler.h:163
ShuffleMask(std::initializer_list< int > Indices)
Definition Legality.h:39
void print(raw_ostream &OS) const
Definition Legality.h:73
bool isIdentity() const
\Returns true if the mask is a perfect identity mask with consecutive indices, i.e....
Definition Legality.h:52
const_iterator end() const
Definition Legality.h:67
ShuffleMask(SmallVectorImpl< int > &&Indices)
Definition Legality.h:38
static ShuffleMask getIdentity(unsigned Sz)
Creates and returns an identity shuffle mask of size Sz.
Definition Legality.h:44
LLVM_DUMP_METHOD void dump() const
Definition Legality.cpp:21
bool operator==(const ShuffleMask &Other) const
Definition Legality.h:59
bool operator!=(const ShuffleMask &Other) const
Definition Legality.h:62
IndicesVecT::const_iterator const_iterator
Definition Legality.h:65
int operator[](int Idx) const
Definition Legality.h:64
friend raw_ostream & operator<<(raw_ostream &OS, const ShuffleMask &Mask)
Definition Legality.h:69
ShuffleMask(ArrayRef< int > Indices)
Definition Legality.h:40
const_iterator begin() const
Definition Legality.h:66
SmallVector< int, 8 > IndicesVecT
Definition Legality.h:32
A SandboxIR Value has users. This is the base class.
Definition Value.h:66
friend class LegalityAnalysis
Definition Legality.h:202
static bool classof(const LegalityResult *From)
Definition Legality.h:206
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
Definition Attributor.h:165
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
ResultReason
The reason for vectorizing or not vectorizing.
Definition Legality.h:89
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:330
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:2474
void interleave(ForwardIterator begin, ForwardIterator end, UnaryFunctor each_fn, NullaryFunctor between_fn)
An STL-style algorithm similar to std::for_each that applies a second functor between every pair of e...
Definition STLExtras.h:2195
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2138
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1734
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:548
@ Other
Any other memory.
Definition ModRef.h:68
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:1869
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:565
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:305
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:851
static const char * getVecReason(ResultReason Reason)
Definition Legality.h:122
static const char * getLegalityResultID(LegalityResultID ID)
Definition Legality.h:106