LLVM 20.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"
21
22namespace llvm::sandboxir {
23
24class LegalityAnalysis;
25class Value;
26class InstrMaps;
27
29public:
31
32private:
33 IndicesVecT Indices;
34
35public:
36 ShuffleMask(SmallVectorImpl<int> &&Indices) : Indices(std::move(Indices)) {}
37 ShuffleMask(std::initializer_list<int> Indices) : Indices(Indices) {}
38 explicit ShuffleMask(ArrayRef<int> Indices) : Indices(Indices) {}
39 operator ArrayRef<int>() const { return Indices; }
40 /// Creates and returns an identity shuffle mask of size \p Sz.
41 /// For example if Sz == 4 the returned mask is {0, 1, 2, 3}.
42 static ShuffleMask getIdentity(unsigned Sz) {
43 IndicesVecT Indices;
44 Indices.reserve(Sz);
45 for (auto Idx : seq<int>(0, (int)Sz))
46 Indices.push_back(Idx);
47 return ShuffleMask(std::move(Indices));
48 }
49 /// \Returns true if the mask is a perfect identity mask with consecutive
50 /// indices, i.e., performs no lane shuffling, like 0,1,2,3...
51 bool isIdentity() const {
52 for (auto [Idx, Elm] : enumerate(Indices)) {
53 if ((int)Idx != Elm)
54 return false;
55 }
56 return true;
57 }
58 bool operator==(const ShuffleMask &Other) const {
59 return Indices == Other.Indices;
60 }
61 bool operator!=(const ShuffleMask &Other) const { return !(*this == Other); }
62 size_t size() const { return Indices.size(); }
63 int operator[](int Idx) const { return Indices[Idx]; }
65 const_iterator begin() const { return Indices.begin(); }
66 const_iterator end() const { return Indices.end(); }
67#ifndef NDEBUG
69 Mask.print(OS);
70 return OS;
71 }
72 void print(raw_ostream &OS) const {
73 interleave(Indices, OS, [&OS](auto Elm) { OS << Elm; }, ",");
74 }
75 LLVM_DUMP_METHOD void dump() const;
76#endif
77};
78
79enum class LegalityResultID {
80 Pack, ///> Collect scalar values.
81 Widen, ///> Vectorize by combining scalars to a vector.
82 DiamondReuse, ///> Don't generate new code, reuse existing vector.
83 DiamondReuseWithShuffle, ///> Reuse the existing vector but add a shuffle.
84 DiamondReuseMultiInput, ///> Reuse more than one vector and/or scalars.
85};
86
87/// The reason for vectorizing or not vectorizing.
88enum class ResultReason {
98};
99
100#ifndef NDEBUG
101struct ToStr {
103 switch (ID) {
105 return "Pack";
107 return "Widen";
109 return "DiamondReuse";
111 return "DiamondReuseWithShuffle";
113 return "DiamondReuseMultiInput";
114 }
115 llvm_unreachable("Unknown LegalityResultID enum");
116 }
117
118 static const char *getVecReason(ResultReason Reason) {
119 switch (Reason) {
121 return "NotInstructions";
123 return "DiffOpcodes";
125 return "DiffTypes";
127 return "DiffMathFlags";
129 return "DiffWrapFlags";
131 return "NotConsecutive";
133 return "CantSchedule";
135 return "Unimplemented";
137 return "Infeasible";
138 }
139 llvm_unreachable("Unknown ResultReason enum");
140 }
141};
142#endif // NDEBUG
143
144/// The legality outcome is represented by a class rather than an enum class
145/// because in some cases the legality checks are expensive and look for a
146/// particular instruction that can be passed along to the vectorizer to avoid
147/// repeating the same expensive computation.
149protected:
151 /// Only Legality can create LegalityResults.
153 friend class LegalityAnalysis;
154
155 /// We shouldn't need copies.
158
159public:
160 virtual ~LegalityResult() {}
162#ifndef NDEBUG
163 virtual void print(raw_ostream &OS) const {
165 }
166 LLVM_DUMP_METHOD void dump() const;
168 LR.print(OS);
169 return OS;
170 }
171#endif // NDEBUG
172};
173
174/// Base class for results with reason.
176 [[maybe_unused]] ResultReason Reason;
178 : LegalityResult(ID), Reason(Reason) {}
179 friend class Pack; // For constructor.
180
181public:
182 ResultReason getReason() const { return Reason; }
183#ifndef NDEBUG
184 void print(raw_ostream &OS) const override {
186 OS << " Reason: " << ToStr::getVecReason(Reason);
187 }
188#endif
189};
190
191class Widen final : public LegalityResult {
192 friend class LegalityAnalysis;
194
195public:
196 static bool classof(const LegalityResult *From) {
197 return From->getSubclassID() == LegalityResultID::Widen;
198 }
199};
200
201class DiamondReuse final : public LegalityResult {
202 friend class LegalityAnalysis;
203 Value *Vec;
204 DiamondReuse(Value *Vec)
206
207public:
208 static bool classof(const LegalityResult *From) {
209 return From->getSubclassID() == LegalityResultID::DiamondReuse;
210 }
211 Value *getVector() const { return Vec; }
212};
213
215 friend class LegalityAnalysis;
216 Value *Vec;
217 ShuffleMask Mask;
218 DiamondReuseWithShuffle(Value *Vec, const ShuffleMask &Mask)
220 Mask(Mask) {}
221
222public:
223 static bool classof(const LegalityResult *From) {
224 return From->getSubclassID() == LegalityResultID::DiamondReuseWithShuffle;
225 }
226 Value *getVector() const { return Vec; }
227 const ShuffleMask &getMask() const { return Mask; }
228};
229
230class Pack final : public LegalityResultWithReason {
231 Pack(ResultReason Reason)
233 friend class LegalityAnalysis; // For constructor.
234
235public:
236 static bool classof(const LegalityResult *From) {
237 return From->getSubclassID() == LegalityResultID::Pack;
238 }
239};
240
241/// Describes how to collect the values needed by each lane.
243public:
244 /// Describes how to get a value element. If the value is a vector then it
245 /// also provides the index to extract it from.
247 Value *V;
248 /// The index in `V` that the value can be extracted from.
249 /// This is nullopt if we need to use `V` as a whole.
250 std::optional<int> ExtractIdx;
251
252 public:
253 ExtractElementDescr(Value *V, int ExtractIdx)
254 : V(V), ExtractIdx(ExtractIdx) {}
255 ExtractElementDescr(Value *V) : V(V), ExtractIdx(std::nullopt) {}
256 Value *getValue() const { return V; }
257 bool needsExtract() const { return ExtractIdx.has_value(); }
258 int getExtractIdx() const { return *ExtractIdx; }
259 };
260
263
264public:
266 : Descrs(std::move(Descrs)) {}
267 /// If all elements come from a single vector input, then return that vector
268 /// and also the shuffle mask required to get them in order.
269 std::optional<std::pair<Value *, ShuffleMask>> getSingleInput() const {
270 const auto &Descr0 = *Descrs.begin();
271 Value *V0 = Descr0.getValue();
272 if (!Descr0.needsExtract())
273 return std::nullopt;
274 ShuffleMask::IndicesVecT MaskIndices;
275 MaskIndices.push_back(Descr0.getExtractIdx());
276 for (const auto &Descr : drop_begin(Descrs)) {
277 if (!Descr.needsExtract())
278 return std::nullopt;
279 if (Descr.getValue() != V0)
280 return std::nullopt;
281 MaskIndices.push_back(Descr.getExtractIdx());
282 }
283 return std::make_pair(V0, ShuffleMask(std::move(MaskIndices)));
284 }
285 bool hasVectorInputs() const {
286 return any_of(Descrs, [](const auto &D) { return D.needsExtract(); });
287 }
289 return Descrs;
290 }
291};
292
294 friend class LegalityAnalysis;
295 CollectDescr Descr;
298 Descr(std::move(Descr)) {}
299
300public:
301 static bool classof(const LegalityResult *From) {
302 return From->getSubclassID() == LegalityResultID::DiamondReuseMultiInput;
303 }
304 const CollectDescr &getCollectDescr() const { return Descr; }
305};
306
307/// Performs the legality analysis and returns a LegalityResult object.
309 Scheduler Sched;
310 /// Owns the legality result objects created by createLegalityResult().
312 /// Checks opcodes, types and other IR-specifics and returns a ResultReason
313 /// object if not vectorizable, or nullptr otherwise.
314 std::optional<ResultReason>
315 notVectorizableBasedOnOpcodesAndTypes(ArrayRef<Value *> Bndl);
316
317 ScalarEvolution &SE;
318 const DataLayout &DL;
319 InstrMaps &IMaps;
320
321 /// Finds how we can collect the values in \p Bndl from the vectorized or
322 /// non-vectorized code. It returns a map of the value we should extract from
323 /// and the corresponding shuffle mask we need to use.
324 CollectDescr getHowToCollectValues(ArrayRef<Value *> Bndl) const;
325
326public:
328 Context &Ctx, InstrMaps &IMaps)
329 : Sched(AA, Ctx), SE(SE), DL(DL), IMaps(IMaps) {}
330 /// A LegalityResult factory.
331 template <typename ResultT, typename... ArgsT>
332 ResultT &createLegalityResult(ArgsT &&...Args) {
333 ResultPool.push_back(
334 std::unique_ptr<ResultT>(new ResultT(std::move(Args)...)));
335 return cast<ResultT>(*ResultPool.back());
336 }
337 /// Checks if it's legal to vectorize the instructions in \p Bndl.
338 /// \Returns a LegalityResult object owned by LegalityAnalysis.
339 /// \p SkipScheduling skips the scheduler check and is only meant for testing.
340 // TODO: Try to remove the SkipScheduling argument by refactoring the tests.
342 bool SkipScheduling = false);
343 void clear();
344};
345
346} // namespace llvm::sandboxir
347
348#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_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:622
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
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
The main scalar evolution driver.
size_t size() const
Definition: SmallVector.h:78
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
void reserve(size_type N)
Definition: SmallVector.h:663
void push_back(const T &Elt)
Definition: SmallVector.h:413
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
Describes how to get a value element.
Definition: Legality.h:246
ExtractElementDescr(Value *V, int ExtractIdx)
Definition: Legality.h:253
Describes how to collect the values needed by each lane.
Definition: Legality.h:242
const SmallVector< ExtractElementDescr, 4 > & getDescrs() const
Definition: Legality.h:288
std::optional< std::pair< Value *, 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:269
bool hasVectorInputs() const
Definition: Legality.h:285
CollectDescr(SmallVectorImpl< ExtractElementDescr > &&Descrs)
Definition: Legality.h:265
static bool classof(const LegalityResult *From)
Definition: Legality.h:301
const CollectDescr & getCollectDescr() const
Definition: Legality.h:304
const ShuffleMask & getMask() const
Definition: Legality.h:227
static bool classof(const LegalityResult *From)
Definition: Legality.h:223
Value * getVector() const
Definition: Legality.h:211
static bool classof(const LegalityResult *From)
Definition: Legality.h:208
Maps the original instructions to the vectorized instrs and the reverse.
Definition: InstrMaps.h:27
Performs the legality analysis and returns a LegalityResult object.
Definition: Legality.h:308
const LegalityResult & canVectorize(ArrayRef< Value * > Bndl, bool SkipScheduling=false)
Checks if it's legal to vectorize the instructions in Bndl.
Definition: Legality.cpp:209
LegalityAnalysis(AAResults &AA, ScalarEvolution &SE, const DataLayout &DL, Context &Ctx, InstrMaps &IMaps)
Definition: Legality.h:327
ResultT & createLegalityResult(ArgsT &&...Args)
A LegalityResult factory.
Definition: Legality.h:332
Base class for results with reason.
Definition: Legality.h:175
void print(raw_ostream &OS) const override
Definition: Legality.h:184
The legality outcome is represented by a class rather than an enum class because in some cases the le...
Definition: Legality.h:148
LegalityResult & operator=(const LegalityResult &)=delete
friend raw_ostream & operator<<(raw_ostream &OS, const LegalityResult &LR)
Definition: Legality.h:167
LLVM_DUMP_METHOD void dump() const
Definition: Legality.cpp:28
LegalityResultID getSubclassID() const
Definition: Legality.h:161
virtual void print(raw_ostream &OS) const
Definition: Legality.h:163
LegalityResult(LegalityResultID ID)
Only Legality can create LegalityResults.
Definition: Legality.h:152
LegalityResult(const LegalityResult &)=delete
We shouldn't need copies.
static bool classof(const LegalityResult *From)
Definition: Legality.h:236
The list scheduler.
Definition: Scheduler.h:111
ShuffleMask(std::initializer_list< int > Indices)
Definition: Legality.h:37
void print(raw_ostream &OS) const
Definition: Legality.h:72
bool isIdentity() const
\Returns true if the mask is a perfect identity mask with consecutive indices, i.e....
Definition: Legality.h:51
const_iterator end() const
Definition: Legality.h:66
ShuffleMask(SmallVectorImpl< int > &&Indices)
Definition: Legality.h:36
static ShuffleMask getIdentity(unsigned Sz)
Creates and returns an identity shuffle mask of size Sz.
Definition: Legality.h:42
LLVM_DUMP_METHOD void dump() const
Definition: Legality.cpp:23
bool operator==(const ShuffleMask &Other) const
Definition: Legality.h:58
bool operator!=(const ShuffleMask &Other) const
Definition: Legality.h:61
int operator[](int Idx) const
Definition: Legality.h:63
friend raw_ostream & operator<<(raw_ostream &OS, const ShuffleMask &Mask)
Definition: Legality.h:68
ShuffleMask(ArrayRef< int > Indices)
Definition: Legality.h:38
const_iterator begin() const
Definition: Legality.h:65
A SandboxIR Value has users. This is the base class.
Definition: Value.h:63
static bool classof(const LegalityResult *From)
Definition: Legality.h:196
#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:88
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
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:2448
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:2169
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:1746
@ 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:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
static const char * getVecReason(ResultReason Reason)
Definition: Legality.h:118
static const char * getLegalityResultID(LegalityResultID ID)
Definition: Legality.h:102