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
26class LegalityAnalysis;
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
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.
89enum class ResultReason {
95 DiffBBs,
102};
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.
186 [[maybe_unused]] 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)
216
217public:
218 static bool classof(const LegalityResult *From) {
219 return From->getSubclassID() == LegalityResultID::DiamondReuse;
220 }
221 Action *getVector() const { return Vec; }
222};
223
225 friend class LegalityAnalysis;
226 Action *Vec;
227 ShuffleMask Mask;
230 Mask(Mask) {}
231
232public:
233 static bool classof(const LegalityResult *From) {
234 return From->getSubclassID() == LegalityResultID::DiamondReuseWithShuffle;
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)
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:
276 : Descrs(std::move(Descrs)) {}
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
304 friend class LegalityAnalysis;
305 CollectDescr Descr;
308 Descr(std::move(Descr)) {}
309
310public:
311 static bool classof(const LegalityResult *From) {
312 return From->getSubclassID() == LegalityResultID::DiamondReuseMultiInput;
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'.
355 return createLegalityResult<Pack>(ResultReason::ForcePackForDebugging);
356 }
357 LLVM_ABI void clear();
358};
359
360} // namespace llvm::sandboxir
361
362#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_LEGALITY_H
static SDValue Widen(SelectionDAG *CurDAG, SDValue N)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
BlockVerifier::State From
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
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
raw_pwrite_stream & OS
A private abstract base class describing the concept of an individual alias analysis implementation.
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...
Definition: PointerUnion.h:118
The main scalar evolution driver.
size_t size() const
Definition: SmallVector.h:79
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
void reserve(size_type N)
Definition: SmallVector.h:664
void push_back(const T &Elt)
Definition: SmallVector.h:414
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
Describes how to get a value element.
Definition: Legality.h:256
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
bool hasVectorInputs() const
Definition: Legality.h:295
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
Base class for results with reason.
Definition: Legality.h:185
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.
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
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
A SandboxIR Value has users. This is the base class.
Definition: Value.h:66
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.
@ DiamondReuse
‍Vectorize by combining scalars to a vector.
@ DiamondReuseWithShuffle
‍Don't generate new code, reuse existing vector.
@ Widen
‍Collect scalar values.
@ DiamondReuseMultiInput
‍Reuse the existing vector but add a shuffle.
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:338
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:2491
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:2212
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2155
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:1751
@ Other
Any other memory.
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:1886
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:856
static const char * getVecReason(ResultReason Reason)
Definition: Legality.h:122
static const char * getLegalityResultID(LegalityResultID ID)
Definition: Legality.h:106