Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- llvm/CodeGen/GlobalISel/LegalizerInfo.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 | /// \file |
||
9 | /// Interface for Targets to specify which operations they can successfully |
||
10 | /// select and how the others should be expanded most efficiently. |
||
11 | /// |
||
12 | //===----------------------------------------------------------------------===// |
||
13 | |||
14 | #ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H |
||
15 | #define LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H |
||
16 | |||
17 | #include "llvm/ADT/SmallBitVector.h" |
||
18 | #include "llvm/ADT/SmallVector.h" |
||
19 | #include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h" |
||
20 | #include "llvm/CodeGen/MachineMemOperand.h" |
||
21 | #include "llvm/CodeGen/TargetOpcodes.h" |
||
22 | #include "llvm/MC/MCInstrDesc.h" |
||
23 | #include "llvm/Support/AtomicOrdering.h" |
||
24 | #include "llvm/Support/CommandLine.h" |
||
25 | #include "llvm/Support/LowLevelTypeImpl.h" |
||
26 | #include <cassert> |
||
27 | #include <cstdint> |
||
28 | #include <tuple> |
||
29 | #include <utility> |
||
30 | |||
31 | namespace llvm { |
||
32 | |||
33 | extern cl::opt<bool> DisableGISelLegalityCheck; |
||
34 | |||
35 | class MachineFunction; |
||
36 | class raw_ostream; |
||
37 | class LegalizerHelper; |
||
38 | class MachineInstr; |
||
39 | class MachineRegisterInfo; |
||
40 | class MCInstrInfo; |
||
41 | |||
42 | namespace LegalizeActions { |
||
43 | enum LegalizeAction : std::uint8_t { |
||
44 | /// The operation is expected to be selectable directly by the target, and |
||
45 | /// no transformation is necessary. |
||
46 | Legal, |
||
47 | |||
48 | /// The operation should be synthesized from multiple instructions acting on |
||
49 | /// a narrower scalar base-type. For example a 64-bit add might be |
||
50 | /// implemented in terms of 32-bit add-with-carry. |
||
51 | NarrowScalar, |
||
52 | |||
53 | /// The operation should be implemented in terms of a wider scalar |
||
54 | /// base-type. For example a <2 x s8> add could be implemented as a <2 |
||
55 | /// x s32> add (ignoring the high bits). |
||
56 | WidenScalar, |
||
57 | |||
58 | /// The (vector) operation should be implemented by splitting it into |
||
59 | /// sub-vectors where the operation is legal. For example a <8 x s64> add |
||
60 | /// might be implemented as 4 separate <2 x s64> adds. There can be a leftover |
||
61 | /// if there are not enough elements for last sub-vector e.g. <7 x s64> add |
||
62 | /// will be implemented as 3 separate <2 x s64> adds and one s64 add. Leftover |
||
63 | /// types can be avoided by doing MoreElements first. |
||
64 | FewerElements, |
||
65 | |||
66 | /// The (vector) operation should be implemented by widening the input |
||
67 | /// vector and ignoring the lanes added by doing so. For example <2 x i8> is |
||
68 | /// rarely legal, but you might perform an <8 x i8> and then only look at |
||
69 | /// the first two results. |
||
70 | MoreElements, |
||
71 | |||
72 | /// Perform the operation on a different, but equivalently sized type. |
||
73 | Bitcast, |
||
74 | |||
75 | /// The operation itself must be expressed in terms of simpler actions on |
||
76 | /// this target. E.g. a SREM replaced by an SDIV and subtraction. |
||
77 | Lower, |
||
78 | |||
79 | /// The operation should be implemented as a call to some kind of runtime |
||
80 | /// support library. For example this usually happens on machines that don't |
||
81 | /// support floating-point operations natively. |
||
82 | Libcall, |
||
83 | |||
84 | /// The target wants to do something special with this combination of |
||
85 | /// operand and type. A callback will be issued when it is needed. |
||
86 | Custom, |
||
87 | |||
88 | /// This operation is completely unsupported on the target. A programming |
||
89 | /// error has occurred. |
||
90 | Unsupported, |
||
91 | |||
92 | /// Sentinel value for when no action was found in the specified table. |
||
93 | NotFound, |
||
94 | |||
95 | /// Fall back onto the old rules. |
||
96 | /// TODO: Remove this once we've migrated |
||
97 | UseLegacyRules, |
||
98 | }; |
||
99 | } // end namespace LegalizeActions |
||
100 | raw_ostream &operator<<(raw_ostream &OS, LegalizeActions::LegalizeAction Action); |
||
101 | |||
102 | using LegalizeActions::LegalizeAction; |
||
103 | |||
104 | /// The LegalityQuery object bundles together all the information that's needed |
||
105 | /// to decide whether a given operation is legal or not. |
||
106 | /// For efficiency, it doesn't make a copy of Types so care must be taken not |
||
107 | /// to free it before using the query. |
||
108 | struct LegalityQuery { |
||
109 | unsigned Opcode; |
||
110 | ArrayRef<LLT> Types; |
||
111 | |||
112 | struct MemDesc { |
||
113 | LLT MemoryTy; |
||
114 | uint64_t AlignInBits; |
||
115 | AtomicOrdering Ordering; |
||
116 | |||
117 | MemDesc() = default; |
||
118 | MemDesc(LLT MemoryTy, uint64_t AlignInBits, AtomicOrdering Ordering) |
||
119 | : MemoryTy(MemoryTy), AlignInBits(AlignInBits), Ordering(Ordering) {} |
||
120 | MemDesc(const MachineMemOperand &MMO) |
||
121 | : MemoryTy(MMO.getMemoryType()), |
||
122 | AlignInBits(MMO.getAlign().value() * 8), |
||
123 | Ordering(MMO.getSuccessOrdering()) {} |
||
124 | }; |
||
125 | |||
126 | /// Operations which require memory can use this to place requirements on the |
||
127 | /// memory type for each MMO. |
||
128 | ArrayRef<MemDesc> MMODescrs; |
||
129 | |||
130 | constexpr LegalityQuery(unsigned Opcode, const ArrayRef<LLT> Types, |
||
131 | const ArrayRef<MemDesc> MMODescrs) |
||
132 | : Opcode(Opcode), Types(Types), MMODescrs(MMODescrs) {} |
||
133 | constexpr LegalityQuery(unsigned Opcode, const ArrayRef<LLT> Types) |
||
134 | : LegalityQuery(Opcode, Types, {}) {} |
||
135 | |||
136 | raw_ostream &print(raw_ostream &OS) const; |
||
137 | }; |
||
138 | |||
139 | /// The result of a query. It either indicates a final answer of Legal or |
||
140 | /// Unsupported or describes an action that must be taken to make an operation |
||
141 | /// more legal. |
||
142 | struct LegalizeActionStep { |
||
143 | /// The action to take or the final answer. |
||
144 | LegalizeAction Action; |
||
145 | /// If describing an action, the type index to change. Otherwise zero. |
||
146 | unsigned TypeIdx; |
||
147 | /// If describing an action, the new type for TypeIdx. Otherwise LLT{}. |
||
148 | LLT NewType; |
||
149 | |||
150 | LegalizeActionStep(LegalizeAction Action, unsigned TypeIdx, |
||
151 | const LLT NewType) |
||
152 | : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {} |
||
153 | |||
154 | LegalizeActionStep(LegacyLegalizeActionStep Step) |
||
155 | : TypeIdx(Step.TypeIdx), NewType(Step.NewType) { |
||
156 | switch (Step.Action) { |
||
157 | case LegacyLegalizeActions::Legal: |
||
158 | Action = LegalizeActions::Legal; |
||
159 | break; |
||
160 | case LegacyLegalizeActions::NarrowScalar: |
||
161 | Action = LegalizeActions::NarrowScalar; |
||
162 | break; |
||
163 | case LegacyLegalizeActions::WidenScalar: |
||
164 | Action = LegalizeActions::WidenScalar; |
||
165 | break; |
||
166 | case LegacyLegalizeActions::FewerElements: |
||
167 | Action = LegalizeActions::FewerElements; |
||
168 | break; |
||
169 | case LegacyLegalizeActions::MoreElements: |
||
170 | Action = LegalizeActions::MoreElements; |
||
171 | break; |
||
172 | case LegacyLegalizeActions::Bitcast: |
||
173 | Action = LegalizeActions::Bitcast; |
||
174 | break; |
||
175 | case LegacyLegalizeActions::Lower: |
||
176 | Action = LegalizeActions::Lower; |
||
177 | break; |
||
178 | case LegacyLegalizeActions::Libcall: |
||
179 | Action = LegalizeActions::Libcall; |
||
180 | break; |
||
181 | case LegacyLegalizeActions::Custom: |
||
182 | Action = LegalizeActions::Custom; |
||
183 | break; |
||
184 | case LegacyLegalizeActions::Unsupported: |
||
185 | Action = LegalizeActions::Unsupported; |
||
186 | break; |
||
187 | case LegacyLegalizeActions::NotFound: |
||
188 | Action = LegalizeActions::NotFound; |
||
189 | break; |
||
190 | } |
||
191 | } |
||
192 | |||
193 | bool operator==(const LegalizeActionStep &RHS) const { |
||
194 | return std::tie(Action, TypeIdx, NewType) == |
||
195 | std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType); |
||
196 | } |
||
197 | }; |
||
198 | |||
199 | using LegalityPredicate = std::function<bool (const LegalityQuery &)>; |
||
200 | using LegalizeMutation = |
||
201 | std::function<std::pair<unsigned, LLT>(const LegalityQuery &)>; |
||
202 | |||
203 | namespace LegalityPredicates { |
||
204 | struct TypePairAndMemDesc { |
||
205 | LLT Type0; |
||
206 | LLT Type1; |
||
207 | LLT MemTy; |
||
208 | uint64_t Align; |
||
209 | |||
210 | bool operator==(const TypePairAndMemDesc &Other) const { |
||
211 | return Type0 == Other.Type0 && Type1 == Other.Type1 && |
||
212 | Align == Other.Align && MemTy == Other.MemTy; |
||
213 | } |
||
214 | |||
215 | /// \returns true if this memory access is legal with for the access described |
||
216 | /// by \p Other (The alignment is sufficient for the size and result type). |
||
217 | bool isCompatible(const TypePairAndMemDesc &Other) const { |
||
218 | return Type0 == Other.Type0 && Type1 == Other.Type1 && |
||
219 | Align >= Other.Align && |
||
220 | // FIXME: This perhaps should be stricter, but the current legality |
||
221 | // rules are written only considering the size. |
||
222 | MemTy.getSizeInBits() == Other.MemTy.getSizeInBits(); |
||
223 | } |
||
224 | }; |
||
225 | |||
226 | /// True iff P0 and P1 are true. |
||
227 | template<typename Predicate> |
||
228 | Predicate all(Predicate P0, Predicate P1) { |
||
229 | return [=](const LegalityQuery &Query) { |
||
230 | return P0(Query) && P1(Query); |
||
231 | }; |
||
232 | } |
||
233 | /// True iff all given predicates are true. |
||
234 | template<typename Predicate, typename... Args> |
||
235 | Predicate all(Predicate P0, Predicate P1, Args... args) { |
||
236 | return all(all(P0, P1), args...); |
||
237 | } |
||
238 | |||
239 | /// True iff P0 or P1 are true. |
||
240 | template<typename Predicate> |
||
241 | Predicate any(Predicate P0, Predicate P1) { |
||
242 | return [=](const LegalityQuery &Query) { |
||
243 | return P0(Query) || P1(Query); |
||
244 | }; |
||
245 | } |
||
246 | /// True iff any given predicates are true. |
||
247 | template<typename Predicate, typename... Args> |
||
248 | Predicate any(Predicate P0, Predicate P1, Args... args) { |
||
249 | return any(any(P0, P1), args...); |
||
250 | } |
||
251 | |||
252 | /// True iff the given type index is the specified type. |
||
253 | LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit); |
||
254 | /// True iff the given type index is one of the specified types. |
||
255 | LegalityPredicate typeInSet(unsigned TypeIdx, |
||
256 | std::initializer_list<LLT> TypesInit); |
||
257 | |||
258 | /// True iff the given type index is not the specified type. |
||
259 | inline LegalityPredicate typeIsNot(unsigned TypeIdx, LLT Type) { |
||
260 | return [=](const LegalityQuery &Query) { |
||
261 | return Query.Types[TypeIdx] != Type; |
||
262 | }; |
||
263 | } |
||
264 | |||
265 | /// True iff the given types for the given pair of type indexes is one of the |
||
266 | /// specified type pairs. |
||
267 | LegalityPredicate |
||
268 | typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1, |
||
269 | std::initializer_list<std::pair<LLT, LLT>> TypesInit); |
||
270 | /// True iff the given types for the given pair of type indexes is one of the |
||
271 | /// specified type pairs. |
||
272 | LegalityPredicate typePairAndMemDescInSet( |
||
273 | unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx, |
||
274 | std::initializer_list<TypePairAndMemDesc> TypesAndMemDescInit); |
||
275 | /// True iff the specified type index is a scalar. |
||
276 | LegalityPredicate isScalar(unsigned TypeIdx); |
||
277 | /// True iff the specified type index is a vector. |
||
278 | LegalityPredicate isVector(unsigned TypeIdx); |
||
279 | /// True iff the specified type index is a pointer (with any address space). |
||
280 | LegalityPredicate isPointer(unsigned TypeIdx); |
||
281 | /// True iff the specified type index is a pointer with the specified address |
||
282 | /// space. |
||
283 | LegalityPredicate isPointer(unsigned TypeIdx, unsigned AddrSpace); |
||
284 | |||
285 | /// True if the type index is a vector with element type \p EltTy |
||
286 | LegalityPredicate elementTypeIs(unsigned TypeIdx, LLT EltTy); |
||
287 | |||
288 | /// True iff the specified type index is a scalar that's narrower than the given |
||
289 | /// size. |
||
290 | LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size); |
||
291 | |||
292 | /// True iff the specified type index is a scalar that's wider than the given |
||
293 | /// size. |
||
294 | LegalityPredicate scalarWiderThan(unsigned TypeIdx, unsigned Size); |
||
295 | |||
296 | /// True iff the specified type index is a scalar or vector with an element type |
||
297 | /// that's narrower than the given size. |
||
298 | LegalityPredicate scalarOrEltNarrowerThan(unsigned TypeIdx, unsigned Size); |
||
299 | |||
300 | /// True iff the specified type index is a scalar or a vector with an element |
||
301 | /// type that's wider than the given size. |
||
302 | LegalityPredicate scalarOrEltWiderThan(unsigned TypeIdx, unsigned Size); |
||
303 | |||
304 | /// True iff the specified type index is a scalar whose size is not a multiple |
||
305 | /// of Size. |
||
306 | LegalityPredicate sizeNotMultipleOf(unsigned TypeIdx, unsigned Size); |
||
307 | |||
308 | /// True iff the specified type index is a scalar whose size is not a power of |
||
309 | /// 2. |
||
310 | LegalityPredicate sizeNotPow2(unsigned TypeIdx); |
||
311 | |||
312 | /// True iff the specified type index is a scalar or vector whose element size |
||
313 | /// is not a power of 2. |
||
314 | LegalityPredicate scalarOrEltSizeNotPow2(unsigned TypeIdx); |
||
315 | |||
316 | /// True if the total bitwidth of the specified type index is \p Size bits. |
||
317 | LegalityPredicate sizeIs(unsigned TypeIdx, unsigned Size); |
||
318 | |||
319 | /// True iff the specified type indices are both the same bit size. |
||
320 | LegalityPredicate sameSize(unsigned TypeIdx0, unsigned TypeIdx1); |
||
321 | |||
322 | /// True iff the first type index has a larger total bit size than second type |
||
323 | /// index. |
||
324 | LegalityPredicate largerThan(unsigned TypeIdx0, unsigned TypeIdx1); |
||
325 | |||
326 | /// True iff the first type index has a smaller total bit size than second type |
||
327 | /// index. |
||
328 | LegalityPredicate smallerThan(unsigned TypeIdx0, unsigned TypeIdx1); |
||
329 | |||
330 | /// True iff the specified MMO index has a size (rounded to bytes) that is not a |
||
331 | /// power of 2. |
||
332 | LegalityPredicate memSizeInBytesNotPow2(unsigned MMOIdx); |
||
333 | |||
334 | /// True iff the specified MMO index has a size that is not an even byte size, |
||
335 | /// or that even byte size is not a power of 2. |
||
336 | LegalityPredicate memSizeNotByteSizePow2(unsigned MMOIdx); |
||
337 | |||
338 | /// True iff the specified type index is a vector whose element count is not a |
||
339 | /// power of 2. |
||
340 | LegalityPredicate numElementsNotPow2(unsigned TypeIdx); |
||
341 | /// True iff the specified MMO index has at an atomic ordering of at Ordering or |
||
342 | /// stronger. |
||
343 | LegalityPredicate atomicOrderingAtLeastOrStrongerThan(unsigned MMOIdx, |
||
344 | AtomicOrdering Ordering); |
||
345 | } // end namespace LegalityPredicates |
||
346 | |||
347 | namespace LegalizeMutations { |
||
348 | /// Select this specific type for the given type index. |
||
349 | LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty); |
||
350 | |||
351 | /// Keep the same type as the given type index. |
||
352 | LegalizeMutation changeTo(unsigned TypeIdx, unsigned FromTypeIdx); |
||
353 | |||
354 | /// Keep the same scalar or element type as the given type index. |
||
355 | LegalizeMutation changeElementTo(unsigned TypeIdx, unsigned FromTypeIdx); |
||
356 | |||
357 | /// Keep the same scalar or element type as the given type. |
||
358 | LegalizeMutation changeElementTo(unsigned TypeIdx, LLT Ty); |
||
359 | |||
360 | /// Keep the same scalar or element type as \p TypeIdx, but take the number of |
||
361 | /// elements from \p FromTypeIdx. |
||
362 | LegalizeMutation changeElementCountTo(unsigned TypeIdx, unsigned FromTypeIdx); |
||
363 | |||
364 | /// Keep the same scalar or element type as \p TypeIdx, but take the number of |
||
365 | /// elements from \p Ty. |
||
366 | LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty); |
||
367 | |||
368 | /// Change the scalar size or element size to have the same scalar size as type |
||
369 | /// index \p FromIndex. Unlike changeElementTo, this discards pointer types and |
||
370 | /// only changes the size. |
||
371 | LegalizeMutation changeElementSizeTo(unsigned TypeIdx, unsigned FromTypeIdx); |
||
372 | |||
373 | /// Widen the scalar type or vector element type for the given type index to the |
||
374 | /// next power of 2. |
||
375 | LegalizeMutation widenScalarOrEltToNextPow2(unsigned TypeIdx, unsigned Min = 0); |
||
376 | |||
377 | /// Widen the scalar type or vector element type for the given type index to |
||
378 | /// next multiple of \p Size. |
||
379 | LegalizeMutation widenScalarOrEltToNextMultipleOf(unsigned TypeIdx, |
||
380 | unsigned Size); |
||
381 | |||
382 | /// Add more elements to the type for the given type index to the next power of |
||
383 | /// 2. |
||
384 | LegalizeMutation moreElementsToNextPow2(unsigned TypeIdx, unsigned Min = 0); |
||
385 | /// Break up the vector type for the given type index into the element type. |
||
386 | LegalizeMutation scalarize(unsigned TypeIdx); |
||
387 | } // end namespace LegalizeMutations |
||
388 | |||
389 | /// A single rule in a legalizer info ruleset. |
||
390 | /// The specified action is chosen when the predicate is true. Where appropriate |
||
391 | /// for the action (e.g. for WidenScalar) the new type is selected using the |
||
392 | /// given mutator. |
||
393 | class LegalizeRule { |
||
394 | LegalityPredicate Predicate; |
||
395 | LegalizeAction Action; |
||
396 | LegalizeMutation Mutation; |
||
397 | |||
398 | public: |
||
399 | LegalizeRule(LegalityPredicate Predicate, LegalizeAction Action, |
||
400 | LegalizeMutation Mutation = nullptr) |
||
401 | : Predicate(Predicate), Action(Action), Mutation(Mutation) {} |
||
402 | |||
403 | /// Test whether the LegalityQuery matches. |
||
404 | bool match(const LegalityQuery &Query) const { |
||
405 | return Predicate(Query); |
||
406 | } |
||
407 | |||
408 | LegalizeAction getAction() const { return Action; } |
||
409 | |||
410 | /// Determine the change to make. |
||
411 | std::pair<unsigned, LLT> determineMutation(const LegalityQuery &Query) const { |
||
412 | if (Mutation) |
||
413 | return Mutation(Query); |
||
414 | return std::make_pair(0, LLT{}); |
||
415 | } |
||
416 | }; |
||
417 | |||
418 | class LegalizeRuleSet { |
||
419 | /// When non-zero, the opcode we are an alias of |
||
420 | unsigned AliasOf = 0; |
||
421 | /// If true, there is another opcode that aliases this one |
||
422 | bool IsAliasedByAnother = false; |
||
423 | SmallVector<LegalizeRule, 2> Rules; |
||
424 | |||
425 | #ifndef NDEBUG |
||
426 | /// If bit I is set, this rule set contains a rule that may handle (predicate |
||
427 | /// or perform an action upon (or both)) the type index I. The uncertainty |
||
428 | /// comes from free-form rules executing user-provided lambda functions. We |
||
429 | /// conservatively assume such rules do the right thing and cover all type |
||
430 | /// indices. The bitset is intentionally 1 bit wider than it absolutely needs |
||
431 | /// to be to distinguish such cases from the cases where all type indices are |
||
432 | /// individually handled. |
||
433 | SmallBitVector TypeIdxsCovered{MCOI::OPERAND_LAST_GENERIC - |
||
434 | MCOI::OPERAND_FIRST_GENERIC + 2}; |
||
435 | SmallBitVector ImmIdxsCovered{MCOI::OPERAND_LAST_GENERIC_IMM - |
||
436 | MCOI::OPERAND_FIRST_GENERIC_IMM + 2}; |
||
437 | #endif |
||
438 | |||
439 | unsigned typeIdx(unsigned TypeIdx) { |
||
440 | assert(TypeIdx <= |
||
441 | (MCOI::OPERAND_LAST_GENERIC - MCOI::OPERAND_FIRST_GENERIC) && |
||
442 | "Type Index is out of bounds"); |
||
443 | #ifndef NDEBUG |
||
444 | TypeIdxsCovered.set(TypeIdx); |
||
445 | #endif |
||
446 | return TypeIdx; |
||
447 | } |
||
448 | |||
449 | void markAllIdxsAsCovered() { |
||
450 | #ifndef NDEBUG |
||
451 | TypeIdxsCovered.set(); |
||
452 | ImmIdxsCovered.set(); |
||
453 | #endif |
||
454 | } |
||
455 | |||
456 | void add(const LegalizeRule &Rule) { |
||
457 | assert(AliasOf == 0 && |
||
458 | "RuleSet is aliased, change the representative opcode instead"); |
||
459 | Rules.push_back(Rule); |
||
460 | } |
||
461 | |||
462 | static bool always(const LegalityQuery &) { return true; } |
||
463 | |||
464 | /// Use the given action when the predicate is true. |
||
465 | /// Action should not be an action that requires mutation. |
||
466 | LegalizeRuleSet &actionIf(LegalizeAction Action, |
||
467 | LegalityPredicate Predicate) { |
||
468 | add({Predicate, Action}); |
||
469 | return *this; |
||
470 | } |
||
471 | /// Use the given action when the predicate is true. |
||
472 | /// Action should be an action that requires mutation. |
||
473 | LegalizeRuleSet &actionIf(LegalizeAction Action, LegalityPredicate Predicate, |
||
474 | LegalizeMutation Mutation) { |
||
475 | add({Predicate, Action, Mutation}); |
||
476 | return *this; |
||
477 | } |
||
478 | /// Use the given action when type index 0 is any type in the given list. |
||
479 | /// Action should not be an action that requires mutation. |
||
480 | LegalizeRuleSet &actionFor(LegalizeAction Action, |
||
481 | std::initializer_list<LLT> Types) { |
||
482 | using namespace LegalityPredicates; |
||
483 | return actionIf(Action, typeInSet(typeIdx(0), Types)); |
||
484 | } |
||
485 | /// Use the given action when type index 0 is any type in the given list. |
||
486 | /// Action should be an action that requires mutation. |
||
487 | LegalizeRuleSet &actionFor(LegalizeAction Action, |
||
488 | std::initializer_list<LLT> Types, |
||
489 | LegalizeMutation Mutation) { |
||
490 | using namespace LegalityPredicates; |
||
491 | return actionIf(Action, typeInSet(typeIdx(0), Types), Mutation); |
||
492 | } |
||
493 | /// Use the given action when type indexes 0 and 1 is any type pair in the |
||
494 | /// given list. |
||
495 | /// Action should not be an action that requires mutation. |
||
496 | LegalizeRuleSet &actionFor(LegalizeAction Action, |
||
497 | std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
498 | using namespace LegalityPredicates; |
||
499 | return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types)); |
||
500 | } |
||
501 | /// Use the given action when type indexes 0 and 1 is any type pair in the |
||
502 | /// given list. |
||
503 | /// Action should be an action that requires mutation. |
||
504 | LegalizeRuleSet &actionFor(LegalizeAction Action, |
||
505 | std::initializer_list<std::pair<LLT, LLT>> Types, |
||
506 | LegalizeMutation Mutation) { |
||
507 | using namespace LegalityPredicates; |
||
508 | return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types), |
||
509 | Mutation); |
||
510 | } |
||
511 | /// Use the given action when type index 0 is any type in the given list and |
||
512 | /// imm index 0 is anything. Action should not be an action that requires |
||
513 | /// mutation. |
||
514 | LegalizeRuleSet &actionForTypeWithAnyImm(LegalizeAction Action, |
||
515 | std::initializer_list<LLT> Types) { |
||
516 | using namespace LegalityPredicates; |
||
517 | immIdx(0); // Inform verifier imm idx 0 is handled. |
||
518 | return actionIf(Action, typeInSet(typeIdx(0), Types)); |
||
519 | } |
||
520 | |||
521 | LegalizeRuleSet &actionForTypeWithAnyImm( |
||
522 | LegalizeAction Action, std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
523 | using namespace LegalityPredicates; |
||
524 | immIdx(0); // Inform verifier imm idx 0 is handled. |
||
525 | return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types)); |
||
526 | } |
||
527 | |||
528 | /// Use the given action when type indexes 0 and 1 are both in the given list. |
||
529 | /// That is, the type pair is in the cartesian product of the list. |
||
530 | /// Action should not be an action that requires mutation. |
||
531 | LegalizeRuleSet &actionForCartesianProduct(LegalizeAction Action, |
||
532 | std::initializer_list<LLT> Types) { |
||
533 | using namespace LegalityPredicates; |
||
534 | return actionIf(Action, all(typeInSet(typeIdx(0), Types), |
||
535 | typeInSet(typeIdx(1), Types))); |
||
536 | } |
||
537 | /// Use the given action when type indexes 0 and 1 are both in their |
||
538 | /// respective lists. |
||
539 | /// That is, the type pair is in the cartesian product of the lists |
||
540 | /// Action should not be an action that requires mutation. |
||
541 | LegalizeRuleSet & |
||
542 | actionForCartesianProduct(LegalizeAction Action, |
||
543 | std::initializer_list<LLT> Types0, |
||
544 | std::initializer_list<LLT> Types1) { |
||
545 | using namespace LegalityPredicates; |
||
546 | return actionIf(Action, all(typeInSet(typeIdx(0), Types0), |
||
547 | typeInSet(typeIdx(1), Types1))); |
||
548 | } |
||
549 | /// Use the given action when type indexes 0, 1, and 2 are all in their |
||
550 | /// respective lists. |
||
551 | /// That is, the type triple is in the cartesian product of the lists |
||
552 | /// Action should not be an action that requires mutation. |
||
553 | LegalizeRuleSet &actionForCartesianProduct( |
||
554 | LegalizeAction Action, std::initializer_list<LLT> Types0, |
||
555 | std::initializer_list<LLT> Types1, std::initializer_list<LLT> Types2) { |
||
556 | using namespace LegalityPredicates; |
||
557 | return actionIf(Action, all(typeInSet(typeIdx(0), Types0), |
||
558 | all(typeInSet(typeIdx(1), Types1), |
||
559 | typeInSet(typeIdx(2), Types2)))); |
||
560 | } |
||
561 | |||
562 | public: |
||
563 | LegalizeRuleSet() = default; |
||
564 | |||
565 | bool isAliasedByAnother() { return IsAliasedByAnother; } |
||
566 | void setIsAliasedByAnother() { IsAliasedByAnother = true; } |
||
567 | void aliasTo(unsigned Opcode) { |
||
568 | assert((AliasOf == 0 || AliasOf == Opcode) && |
||
569 | "Opcode is already aliased to another opcode"); |
||
570 | assert(Rules.empty() && "Aliasing will discard rules"); |
||
571 | AliasOf = Opcode; |
||
572 | } |
||
573 | unsigned getAlias() const { return AliasOf; } |
||
574 | |||
575 | unsigned immIdx(unsigned ImmIdx) { |
||
576 | assert(ImmIdx <= (MCOI::OPERAND_LAST_GENERIC_IMM - |
||
577 | MCOI::OPERAND_FIRST_GENERIC_IMM) && |
||
578 | "Imm Index is out of bounds"); |
||
579 | #ifndef NDEBUG |
||
580 | ImmIdxsCovered.set(ImmIdx); |
||
581 | #endif |
||
582 | return ImmIdx; |
||
583 | } |
||
584 | |||
585 | /// The instruction is legal if predicate is true. |
||
586 | LegalizeRuleSet &legalIf(LegalityPredicate Predicate) { |
||
587 | // We have no choice but conservatively assume that the free-form |
||
588 | // user-provided Predicate properly handles all type indices: |
||
589 | markAllIdxsAsCovered(); |
||
590 | return actionIf(LegalizeAction::Legal, Predicate); |
||
591 | } |
||
592 | /// The instruction is legal when type index 0 is any type in the given list. |
||
593 | LegalizeRuleSet &legalFor(std::initializer_list<LLT> Types) { |
||
594 | return actionFor(LegalizeAction::Legal, Types); |
||
595 | } |
||
596 | /// The instruction is legal when type indexes 0 and 1 is any type pair in the |
||
597 | /// given list. |
||
598 | LegalizeRuleSet &legalFor(std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
599 | return actionFor(LegalizeAction::Legal, Types); |
||
600 | } |
||
601 | /// The instruction is legal when type index 0 is any type in the given list |
||
602 | /// and imm index 0 is anything. |
||
603 | LegalizeRuleSet &legalForTypeWithAnyImm(std::initializer_list<LLT> Types) { |
||
604 | markAllIdxsAsCovered(); |
||
605 | return actionForTypeWithAnyImm(LegalizeAction::Legal, Types); |
||
606 | } |
||
607 | |||
608 | LegalizeRuleSet &legalForTypeWithAnyImm( |
||
609 | std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
610 | markAllIdxsAsCovered(); |
||
611 | return actionForTypeWithAnyImm(LegalizeAction::Legal, Types); |
||
612 | } |
||
613 | |||
614 | /// The instruction is legal when type indexes 0 and 1 along with the memory |
||
615 | /// size and minimum alignment is any type and size tuple in the given list. |
||
616 | LegalizeRuleSet &legalForTypesWithMemDesc( |
||
617 | std::initializer_list<LegalityPredicates::TypePairAndMemDesc> |
||
618 | TypesAndMemDesc) { |
||
619 | return actionIf(LegalizeAction::Legal, |
||
620 | LegalityPredicates::typePairAndMemDescInSet( |
||
621 | typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemDesc)); |
||
622 | } |
||
623 | /// The instruction is legal when type indexes 0 and 1 are both in the given |
||
624 | /// list. That is, the type pair is in the cartesian product of the list. |
||
625 | LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types) { |
||
626 | return actionForCartesianProduct(LegalizeAction::Legal, Types); |
||
627 | } |
||
628 | /// The instruction is legal when type indexes 0 and 1 are both their |
||
629 | /// respective lists. |
||
630 | LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types0, |
||
631 | std::initializer_list<LLT> Types1) { |
||
632 | return actionForCartesianProduct(LegalizeAction::Legal, Types0, Types1); |
||
633 | } |
||
634 | /// The instruction is legal when type indexes 0, 1, and 2 are both their |
||
635 | /// respective lists. |
||
636 | LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types0, |
||
637 | std::initializer_list<LLT> Types1, |
||
638 | std::initializer_list<LLT> Types2) { |
||
639 | return actionForCartesianProduct(LegalizeAction::Legal, Types0, Types1, |
||
640 | Types2); |
||
641 | } |
||
642 | |||
643 | LegalizeRuleSet &alwaysLegal() { |
||
644 | using namespace LegalizeMutations; |
||
645 | markAllIdxsAsCovered(); |
||
646 | return actionIf(LegalizeAction::Legal, always); |
||
647 | } |
||
648 | |||
649 | /// The specified type index is coerced if predicate is true. |
||
650 | LegalizeRuleSet &bitcastIf(LegalityPredicate Predicate, |
||
651 | LegalizeMutation Mutation) { |
||
652 | // We have no choice but conservatively assume that lowering with a |
||
653 | // free-form user provided Predicate properly handles all type indices: |
||
654 | markAllIdxsAsCovered(); |
||
655 | return actionIf(LegalizeAction::Bitcast, Predicate, Mutation); |
||
656 | } |
||
657 | |||
658 | /// The instruction is lowered. |
||
659 | LegalizeRuleSet &lower() { |
||
660 | using namespace LegalizeMutations; |
||
661 | // We have no choice but conservatively assume that predicate-less lowering |
||
662 | // properly handles all type indices by design: |
||
663 | markAllIdxsAsCovered(); |
||
664 | return actionIf(LegalizeAction::Lower, always); |
||
665 | } |
||
666 | /// The instruction is lowered if predicate is true. Keep type index 0 as the |
||
667 | /// same type. |
||
668 | LegalizeRuleSet &lowerIf(LegalityPredicate Predicate) { |
||
669 | using namespace LegalizeMutations; |
||
670 | // We have no choice but conservatively assume that lowering with a |
||
671 | // free-form user provided Predicate properly handles all type indices: |
||
672 | markAllIdxsAsCovered(); |
||
673 | return actionIf(LegalizeAction::Lower, Predicate); |
||
674 | } |
||
675 | /// The instruction is lowered if predicate is true. |
||
676 | LegalizeRuleSet &lowerIf(LegalityPredicate Predicate, |
||
677 | LegalizeMutation Mutation) { |
||
678 | // We have no choice but conservatively assume that lowering with a |
||
679 | // free-form user provided Predicate properly handles all type indices: |
||
680 | markAllIdxsAsCovered(); |
||
681 | return actionIf(LegalizeAction::Lower, Predicate, Mutation); |
||
682 | } |
||
683 | /// The instruction is lowered when type index 0 is any type in the given |
||
684 | /// list. Keep type index 0 as the same type. |
||
685 | LegalizeRuleSet &lowerFor(std::initializer_list<LLT> Types) { |
||
686 | return actionFor(LegalizeAction::Lower, Types); |
||
687 | } |
||
688 | /// The instruction is lowered when type index 0 is any type in the given |
||
689 | /// list. |
||
690 | LegalizeRuleSet &lowerFor(std::initializer_list<LLT> Types, |
||
691 | LegalizeMutation Mutation) { |
||
692 | return actionFor(LegalizeAction::Lower, Types, Mutation); |
||
693 | } |
||
694 | /// The instruction is lowered when type indexes 0 and 1 is any type pair in |
||
695 | /// the given list. Keep type index 0 as the same type. |
||
696 | LegalizeRuleSet &lowerFor(std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
697 | return actionFor(LegalizeAction::Lower, Types); |
||
698 | } |
||
699 | /// The instruction is lowered when type indexes 0 and 1 is any type pair in |
||
700 | /// the given list. |
||
701 | LegalizeRuleSet &lowerFor(std::initializer_list<std::pair<LLT, LLT>> Types, |
||
702 | LegalizeMutation Mutation) { |
||
703 | return actionFor(LegalizeAction::Lower, Types, Mutation); |
||
704 | } |
||
705 | /// The instruction is lowered when type indexes 0 and 1 are both in their |
||
706 | /// respective lists. |
||
707 | LegalizeRuleSet &lowerForCartesianProduct(std::initializer_list<LLT> Types0, |
||
708 | std::initializer_list<LLT> Types1) { |
||
709 | using namespace LegalityPredicates; |
||
710 | return actionForCartesianProduct(LegalizeAction::Lower, Types0, Types1); |
||
711 | } |
||
712 | /// The instruction is lowered when when type indexes 0, 1, and 2 are all in |
||
713 | /// their respective lists. |
||
714 | LegalizeRuleSet &lowerForCartesianProduct(std::initializer_list<LLT> Types0, |
||
715 | std::initializer_list<LLT> Types1, |
||
716 | std::initializer_list<LLT> Types2) { |
||
717 | using namespace LegalityPredicates; |
||
718 | return actionForCartesianProduct(LegalizeAction::Lower, Types0, Types1, |
||
719 | Types2); |
||
720 | } |
||
721 | |||
722 | /// The instruction is emitted as a library call. |
||
723 | LegalizeRuleSet &libcall() { |
||
724 | using namespace LegalizeMutations; |
||
725 | // We have no choice but conservatively assume that predicate-less lowering |
||
726 | // properly handles all type indices by design: |
||
727 | markAllIdxsAsCovered(); |
||
728 | return actionIf(LegalizeAction::Libcall, always); |
||
729 | } |
||
730 | |||
731 | /// Like legalIf, but for the Libcall action. |
||
732 | LegalizeRuleSet &libcallIf(LegalityPredicate Predicate) { |
||
733 | // We have no choice but conservatively assume that a libcall with a |
||
734 | // free-form user provided Predicate properly handles all type indices: |
||
735 | markAllIdxsAsCovered(); |
||
736 | return actionIf(LegalizeAction::Libcall, Predicate); |
||
737 | } |
||
738 | LegalizeRuleSet &libcallFor(std::initializer_list<LLT> Types) { |
||
739 | return actionFor(LegalizeAction::Libcall, Types); |
||
740 | } |
||
741 | LegalizeRuleSet & |
||
742 | libcallFor(std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
743 | return actionFor(LegalizeAction::Libcall, Types); |
||
744 | } |
||
745 | LegalizeRuleSet & |
||
746 | libcallForCartesianProduct(std::initializer_list<LLT> Types) { |
||
747 | return actionForCartesianProduct(LegalizeAction::Libcall, Types); |
||
748 | } |
||
749 | LegalizeRuleSet & |
||
750 | libcallForCartesianProduct(std::initializer_list<LLT> Types0, |
||
751 | std::initializer_list<LLT> Types1) { |
||
752 | return actionForCartesianProduct(LegalizeAction::Libcall, Types0, Types1); |
||
753 | } |
||
754 | |||
755 | /// Widen the scalar to the one selected by the mutation if the predicate is |
||
756 | /// true. |
||
757 | LegalizeRuleSet &widenScalarIf(LegalityPredicate Predicate, |
||
758 | LegalizeMutation Mutation) { |
||
759 | // We have no choice but conservatively assume that an action with a |
||
760 | // free-form user provided Predicate properly handles all type indices: |
||
761 | markAllIdxsAsCovered(); |
||
762 | return actionIf(LegalizeAction::WidenScalar, Predicate, Mutation); |
||
763 | } |
||
764 | /// Narrow the scalar to the one selected by the mutation if the predicate is |
||
765 | /// true. |
||
766 | LegalizeRuleSet &narrowScalarIf(LegalityPredicate Predicate, |
||
767 | LegalizeMutation Mutation) { |
||
768 | // We have no choice but conservatively assume that an action with a |
||
769 | // free-form user provided Predicate properly handles all type indices: |
||
770 | markAllIdxsAsCovered(); |
||
771 | return actionIf(LegalizeAction::NarrowScalar, Predicate, Mutation); |
||
772 | } |
||
773 | /// Narrow the scalar, specified in mutation, when type indexes 0 and 1 is any |
||
774 | /// type pair in the given list. |
||
775 | LegalizeRuleSet & |
||
776 | narrowScalarFor(std::initializer_list<std::pair<LLT, LLT>> Types, |
||
777 | LegalizeMutation Mutation) { |
||
778 | return actionFor(LegalizeAction::NarrowScalar, Types, Mutation); |
||
779 | } |
||
780 | |||
781 | /// Add more elements to reach the type selected by the mutation if the |
||
782 | /// predicate is true. |
||
783 | LegalizeRuleSet &moreElementsIf(LegalityPredicate Predicate, |
||
784 | LegalizeMutation Mutation) { |
||
785 | // We have no choice but conservatively assume that an action with a |
||
786 | // free-form user provided Predicate properly handles all type indices: |
||
787 | markAllIdxsAsCovered(); |
||
788 | return actionIf(LegalizeAction::MoreElements, Predicate, Mutation); |
||
789 | } |
||
790 | /// Remove elements to reach the type selected by the mutation if the |
||
791 | /// predicate is true. |
||
792 | LegalizeRuleSet &fewerElementsIf(LegalityPredicate Predicate, |
||
793 | LegalizeMutation Mutation) { |
||
794 | // We have no choice but conservatively assume that an action with a |
||
795 | // free-form user provided Predicate properly handles all type indices: |
||
796 | markAllIdxsAsCovered(); |
||
797 | return actionIf(LegalizeAction::FewerElements, Predicate, Mutation); |
||
798 | } |
||
799 | |||
800 | /// The instruction is unsupported. |
||
801 | LegalizeRuleSet &unsupported() { |
||
802 | markAllIdxsAsCovered(); |
||
803 | return actionIf(LegalizeAction::Unsupported, always); |
||
804 | } |
||
805 | LegalizeRuleSet &unsupportedIf(LegalityPredicate Predicate) { |
||
806 | return actionIf(LegalizeAction::Unsupported, Predicate); |
||
807 | } |
||
808 | |||
809 | LegalizeRuleSet &unsupportedFor(std::initializer_list<LLT> Types) { |
||
810 | return actionFor(LegalizeAction::Unsupported, Types); |
||
811 | } |
||
812 | |||
813 | LegalizeRuleSet &unsupportedIfMemSizeNotPow2() { |
||
814 | return actionIf(LegalizeAction::Unsupported, |
||
815 | LegalityPredicates::memSizeInBytesNotPow2(0)); |
||
816 | } |
||
817 | |||
818 | /// Lower a memory operation if the memory size, rounded to bytes, is not a |
||
819 | /// power of 2. For example, this will not trigger for s1 or s7, but will for |
||
820 | /// s24. |
||
821 | LegalizeRuleSet &lowerIfMemSizeNotPow2() { |
||
822 | return actionIf(LegalizeAction::Lower, |
||
823 | LegalityPredicates::memSizeInBytesNotPow2(0)); |
||
824 | } |
||
825 | |||
826 | /// Lower a memory operation if the memory access size is not a round power of |
||
827 | /// 2 byte size. This is stricter than lowerIfMemSizeNotPow2, and more likely |
||
828 | /// what you want (e.g. this will lower s1, s7 and s24). |
||
829 | LegalizeRuleSet &lowerIfMemSizeNotByteSizePow2() { |
||
830 | return actionIf(LegalizeAction::Lower, |
||
831 | LegalityPredicates::memSizeNotByteSizePow2(0)); |
||
832 | } |
||
833 | |||
834 | LegalizeRuleSet &customIf(LegalityPredicate Predicate) { |
||
835 | // We have no choice but conservatively assume that a custom action with a |
||
836 | // free-form user provided Predicate properly handles all type indices: |
||
837 | markAllIdxsAsCovered(); |
||
838 | return actionIf(LegalizeAction::Custom, Predicate); |
||
839 | } |
||
840 | LegalizeRuleSet &customFor(std::initializer_list<LLT> Types) { |
||
841 | return actionFor(LegalizeAction::Custom, Types); |
||
842 | } |
||
843 | |||
844 | /// The instruction is custom when type indexes 0 and 1 is any type pair in the |
||
845 | /// given list. |
||
846 | LegalizeRuleSet &customFor(std::initializer_list<std::pair<LLT, LLT>> Types) { |
||
847 | return actionFor(LegalizeAction::Custom, Types); |
||
848 | } |
||
849 | |||
850 | LegalizeRuleSet &customForCartesianProduct(std::initializer_list<LLT> Types) { |
||
851 | return actionForCartesianProduct(LegalizeAction::Custom, Types); |
||
852 | } |
||
853 | /// The instruction is custom when type indexes 0 and 1 are both in their |
||
854 | /// respective lists. |
||
855 | LegalizeRuleSet & |
||
856 | customForCartesianProduct(std::initializer_list<LLT> Types0, |
||
857 | std::initializer_list<LLT> Types1) { |
||
858 | return actionForCartesianProduct(LegalizeAction::Custom, Types0, Types1); |
||
859 | } |
||
860 | /// The instruction is custom when when type indexes 0, 1, and 2 are all in |
||
861 | /// their respective lists. |
||
862 | LegalizeRuleSet & |
||
863 | customForCartesianProduct(std::initializer_list<LLT> Types0, |
||
864 | std::initializer_list<LLT> Types1, |
||
865 | std::initializer_list<LLT> Types2) { |
||
866 | return actionForCartesianProduct(LegalizeAction::Custom, Types0, Types1, |
||
867 | Types2); |
||
868 | } |
||
869 | |||
870 | /// Unconditionally custom lower. |
||
871 | LegalizeRuleSet &custom() { |
||
872 | return customIf(always); |
||
873 | } |
||
874 | |||
875 | /// Widen the scalar to the next power of two that is at least MinSize. |
||
876 | /// No effect if the type is not a scalar or is a power of two. |
||
877 | LegalizeRuleSet &widenScalarToNextPow2(unsigned TypeIdx, |
||
878 | unsigned MinSize = 0) { |
||
879 | using namespace LegalityPredicates; |
||
880 | return actionIf( |
||
881 | LegalizeAction::WidenScalar, sizeNotPow2(typeIdx(TypeIdx)), |
||
882 | LegalizeMutations::widenScalarOrEltToNextPow2(TypeIdx, MinSize)); |
||
883 | } |
||
884 | |||
885 | /// Widen the scalar to the next multiple of Size. No effect if the |
||
886 | /// type is not a scalar or is a multiple of Size. |
||
887 | LegalizeRuleSet &widenScalarToNextMultipleOf(unsigned TypeIdx, |
||
888 | unsigned Size) { |
||
889 | using namespace LegalityPredicates; |
||
890 | return actionIf( |
||
891 | LegalizeAction::WidenScalar, sizeNotMultipleOf(typeIdx(TypeIdx), Size), |
||
892 | LegalizeMutations::widenScalarOrEltToNextMultipleOf(TypeIdx, Size)); |
||
893 | } |
||
894 | |||
895 | /// Widen the scalar or vector element type to the next power of two that is |
||
896 | /// at least MinSize. No effect if the scalar size is a power of two. |
||
897 | LegalizeRuleSet &widenScalarOrEltToNextPow2(unsigned TypeIdx, |
||
898 | unsigned MinSize = 0) { |
||
899 | using namespace LegalityPredicates; |
||
900 | return actionIf( |
||
901 | LegalizeAction::WidenScalar, scalarOrEltSizeNotPow2(typeIdx(TypeIdx)), |
||
902 | LegalizeMutations::widenScalarOrEltToNextPow2(TypeIdx, MinSize)); |
||
903 | } |
||
904 | |||
905 | LegalizeRuleSet &narrowScalar(unsigned TypeIdx, LegalizeMutation Mutation) { |
||
906 | using namespace LegalityPredicates; |
||
907 | return actionIf(LegalizeAction::NarrowScalar, isScalar(typeIdx(TypeIdx)), |
||
908 | Mutation); |
||
909 | } |
||
910 | |||
911 | LegalizeRuleSet &scalarize(unsigned TypeIdx) { |
||
912 | using namespace LegalityPredicates; |
||
913 | return actionIf(LegalizeAction::FewerElements, isVector(typeIdx(TypeIdx)), |
||
914 | LegalizeMutations::scalarize(TypeIdx)); |
||
915 | } |
||
916 | |||
917 | LegalizeRuleSet &scalarizeIf(LegalityPredicate Predicate, unsigned TypeIdx) { |
||
918 | using namespace LegalityPredicates; |
||
919 | return actionIf(LegalizeAction::FewerElements, |
||
920 | all(Predicate, isVector(typeIdx(TypeIdx))), |
||
921 | LegalizeMutations::scalarize(TypeIdx)); |
||
922 | } |
||
923 | |||
924 | /// Ensure the scalar or element is at least as wide as Ty. |
||
925 | LegalizeRuleSet &minScalarOrElt(unsigned TypeIdx, const LLT Ty) { |
||
926 | using namespace LegalityPredicates; |
||
927 | using namespace LegalizeMutations; |
||
928 | return actionIf(LegalizeAction::WidenScalar, |
||
929 | scalarOrEltNarrowerThan(TypeIdx, Ty.getScalarSizeInBits()), |
||
930 | changeElementTo(typeIdx(TypeIdx), Ty)); |
||
931 | } |
||
932 | |||
933 | /// Ensure the scalar or element is at least as wide as Ty. |
||
934 | LegalizeRuleSet &minScalarOrEltIf(LegalityPredicate Predicate, |
||
935 | unsigned TypeIdx, const LLT Ty) { |
||
936 | using namespace LegalityPredicates; |
||
937 | using namespace LegalizeMutations; |
||
938 | return actionIf(LegalizeAction::WidenScalar, |
||
939 | all(Predicate, scalarOrEltNarrowerThan( |
||
940 | TypeIdx, Ty.getScalarSizeInBits())), |
||
941 | changeElementTo(typeIdx(TypeIdx), Ty)); |
||
942 | } |
||
943 | |||
944 | /// Ensure the scalar is at least as wide as Ty. |
||
945 | LegalizeRuleSet &minScalar(unsigned TypeIdx, const LLT Ty) { |
||
946 | using namespace LegalityPredicates; |
||
947 | using namespace LegalizeMutations; |
||
948 | return actionIf(LegalizeAction::WidenScalar, |
||
949 | scalarNarrowerThan(TypeIdx, Ty.getSizeInBits()), |
||
950 | changeTo(typeIdx(TypeIdx), Ty)); |
||
951 | } |
||
952 | |||
953 | /// Ensure the scalar is at least as wide as Ty if condition is met. |
||
954 | LegalizeRuleSet &minScalarIf(LegalityPredicate Predicate, unsigned TypeIdx, |
||
955 | const LLT Ty) { |
||
956 | using namespace LegalityPredicates; |
||
957 | using namespace LegalizeMutations; |
||
958 | return actionIf( |
||
959 | LegalizeAction::WidenScalar, |
||
960 | [=](const LegalityQuery &Query) { |
||
961 | const LLT QueryTy = Query.Types[TypeIdx]; |
||
962 | return QueryTy.isScalar() && |
||
963 | QueryTy.getSizeInBits() < Ty.getSizeInBits() && |
||
964 | Predicate(Query); |
||
965 | }, |
||
966 | changeTo(typeIdx(TypeIdx), Ty)); |
||
967 | } |
||
968 | |||
969 | /// Ensure the scalar is at most as wide as Ty. |
||
970 | LegalizeRuleSet &maxScalarOrElt(unsigned TypeIdx, const LLT Ty) { |
||
971 | using namespace LegalityPredicates; |
||
972 | using namespace LegalizeMutations; |
||
973 | return actionIf(LegalizeAction::NarrowScalar, |
||
974 | scalarOrEltWiderThan(TypeIdx, Ty.getScalarSizeInBits()), |
||
975 | changeElementTo(typeIdx(TypeIdx), Ty)); |
||
976 | } |
||
977 | |||
978 | /// Ensure the scalar is at most as wide as Ty. |
||
979 | LegalizeRuleSet &maxScalar(unsigned TypeIdx, const LLT Ty) { |
||
980 | using namespace LegalityPredicates; |
||
981 | using namespace LegalizeMutations; |
||
982 | return actionIf(LegalizeAction::NarrowScalar, |
||
983 | scalarWiderThan(TypeIdx, Ty.getSizeInBits()), |
||
984 | changeTo(typeIdx(TypeIdx), Ty)); |
||
985 | } |
||
986 | |||
987 | /// Conditionally limit the maximum size of the scalar. |
||
988 | /// For example, when the maximum size of one type depends on the size of |
||
989 | /// another such as extracting N bits from an M bit container. |
||
990 | LegalizeRuleSet &maxScalarIf(LegalityPredicate Predicate, unsigned TypeIdx, |
||
991 | const LLT Ty) { |
||
992 | using namespace LegalityPredicates; |
||
993 | using namespace LegalizeMutations; |
||
994 | return actionIf( |
||
995 | LegalizeAction::NarrowScalar, |
||
996 | [=](const LegalityQuery &Query) { |
||
997 | const LLT QueryTy = Query.Types[TypeIdx]; |
||
998 | return QueryTy.isScalar() && |
||
999 | QueryTy.getSizeInBits() > Ty.getSizeInBits() && |
||
1000 | Predicate(Query); |
||
1001 | }, |
||
1002 | changeElementTo(typeIdx(TypeIdx), Ty)); |
||
1003 | } |
||
1004 | |||
1005 | /// Limit the range of scalar sizes to MinTy and MaxTy. |
||
1006 | LegalizeRuleSet &clampScalar(unsigned TypeIdx, const LLT MinTy, |
||
1007 | const LLT MaxTy) { |
||
1008 | assert(MinTy.isScalar() && MaxTy.isScalar() && "Expected scalar types"); |
||
1009 | return minScalar(TypeIdx, MinTy).maxScalar(TypeIdx, MaxTy); |
||
1010 | } |
||
1011 | |||
1012 | /// Limit the range of scalar sizes to MinTy and MaxTy. |
||
1013 | LegalizeRuleSet &clampScalarOrElt(unsigned TypeIdx, const LLT MinTy, |
||
1014 | const LLT MaxTy) { |
||
1015 | return minScalarOrElt(TypeIdx, MinTy).maxScalarOrElt(TypeIdx, MaxTy); |
||
1016 | } |
||
1017 | |||
1018 | /// Widen the scalar to match the size of another. |
||
1019 | LegalizeRuleSet &minScalarSameAs(unsigned TypeIdx, unsigned LargeTypeIdx) { |
||
1020 | typeIdx(TypeIdx); |
||
1021 | return widenScalarIf( |
||
1022 | [=](const LegalityQuery &Query) { |
||
1023 | return Query.Types[LargeTypeIdx].getScalarSizeInBits() > |
||
1024 | Query.Types[TypeIdx].getSizeInBits(); |
||
1025 | }, |
||
1026 | LegalizeMutations::changeElementSizeTo(TypeIdx, LargeTypeIdx)); |
||
1027 | } |
||
1028 | |||
1029 | /// Narrow the scalar to match the size of another. |
||
1030 | LegalizeRuleSet &maxScalarSameAs(unsigned TypeIdx, unsigned NarrowTypeIdx) { |
||
1031 | typeIdx(TypeIdx); |
||
1032 | return narrowScalarIf( |
||
1033 | [=](const LegalityQuery &Query) { |
||
1034 | return Query.Types[NarrowTypeIdx].getScalarSizeInBits() < |
||
1035 | Query.Types[TypeIdx].getSizeInBits(); |
||
1036 | }, |
||
1037 | LegalizeMutations::changeElementSizeTo(TypeIdx, NarrowTypeIdx)); |
||
1038 | } |
||
1039 | |||
1040 | /// Change the type \p TypeIdx to have the same scalar size as type \p |
||
1041 | /// SameSizeIdx. |
||
1042 | LegalizeRuleSet &scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx) { |
||
1043 | return minScalarSameAs(TypeIdx, SameSizeIdx) |
||
1044 | .maxScalarSameAs(TypeIdx, SameSizeIdx); |
||
1045 | } |
||
1046 | |||
1047 | /// Conditionally widen the scalar or elt to match the size of another. |
||
1048 | LegalizeRuleSet &minScalarEltSameAsIf(LegalityPredicate Predicate, |
||
1049 | unsigned TypeIdx, unsigned LargeTypeIdx) { |
||
1050 | typeIdx(TypeIdx); |
||
1051 | return widenScalarIf( |
||
1052 | [=](const LegalityQuery &Query) { |
||
1053 | return Query.Types[LargeTypeIdx].getScalarSizeInBits() > |
||
1054 | Query.Types[TypeIdx].getScalarSizeInBits() && |
||
1055 | Predicate(Query); |
||
1056 | }, |
||
1057 | [=](const LegalityQuery &Query) { |
||
1058 | LLT T = Query.Types[LargeTypeIdx]; |
||
1059 | if (T.isVector() && T.getElementType().isPointer()) |
||
1060 | T = T.changeElementType(LLT::scalar(T.getScalarSizeInBits())); |
||
1061 | return std::make_pair(TypeIdx, T); |
||
1062 | }); |
||
1063 | } |
||
1064 | |||
1065 | /// Conditionally narrow the scalar or elt to match the size of another. |
||
1066 | LegalizeRuleSet &maxScalarEltSameAsIf(LegalityPredicate Predicate, |
||
1067 | unsigned TypeIdx, |
||
1068 | unsigned SmallTypeIdx) { |
||
1069 | typeIdx(TypeIdx); |
||
1070 | return narrowScalarIf( |
||
1071 | [=](const LegalityQuery &Query) { |
||
1072 | return Query.Types[SmallTypeIdx].getScalarSizeInBits() < |
||
1073 | Query.Types[TypeIdx].getScalarSizeInBits() && |
||
1074 | Predicate(Query); |
||
1075 | }, |
||
1076 | [=](const LegalityQuery &Query) { |
||
1077 | LLT T = Query.Types[SmallTypeIdx]; |
||
1078 | return std::make_pair(TypeIdx, T); |
||
1079 | }); |
||
1080 | } |
||
1081 | |||
1082 | /// Add more elements to the vector to reach the next power of two. |
||
1083 | /// No effect if the type is not a vector or the element count is a power of |
||
1084 | /// two. |
||
1085 | LegalizeRuleSet &moreElementsToNextPow2(unsigned TypeIdx) { |
||
1086 | using namespace LegalityPredicates; |
||
1087 | return actionIf(LegalizeAction::MoreElements, |
||
1088 | numElementsNotPow2(typeIdx(TypeIdx)), |
||
1089 | LegalizeMutations::moreElementsToNextPow2(TypeIdx)); |
||
1090 | } |
||
1091 | |||
1092 | /// Limit the number of elements in EltTy vectors to at least MinElements. |
||
1093 | LegalizeRuleSet &clampMinNumElements(unsigned TypeIdx, const LLT EltTy, |
||
1094 | unsigned MinElements) { |
||
1095 | // Mark the type index as covered: |
||
1096 | typeIdx(TypeIdx); |
||
1097 | return actionIf( |
||
1098 | LegalizeAction::MoreElements, |
||
1099 | [=](const LegalityQuery &Query) { |
||
1100 | LLT VecTy = Query.Types[TypeIdx]; |
||
1101 | return VecTy.isVector() && VecTy.getElementType() == EltTy && |
||
1102 | VecTy.getNumElements() < MinElements; |
||
1103 | }, |
||
1104 | [=](const LegalityQuery &Query) { |
||
1105 | LLT VecTy = Query.Types[TypeIdx]; |
||
1106 | return std::make_pair( |
||
1107 | TypeIdx, LLT::fixed_vector(MinElements, VecTy.getElementType())); |
||
1108 | }); |
||
1109 | } |
||
1110 | |||
1111 | /// Set number of elements to nearest larger multiple of NumElts. |
||
1112 | LegalizeRuleSet &alignNumElementsTo(unsigned TypeIdx, const LLT EltTy, |
||
1113 | unsigned NumElts) { |
||
1114 | typeIdx(TypeIdx); |
||
1115 | return actionIf( |
||
1116 | LegalizeAction::MoreElements, |
||
1117 | [=](const LegalityQuery &Query) { |
||
1118 | LLT VecTy = Query.Types[TypeIdx]; |
||
1119 | return VecTy.isVector() && VecTy.getElementType() == EltTy && |
||
1120 | (VecTy.getNumElements() % NumElts != 0); |
||
1121 | }, |
||
1122 | [=](const LegalityQuery &Query) { |
||
1123 | LLT VecTy = Query.Types[TypeIdx]; |
||
1124 | unsigned NewSize = alignTo(VecTy.getNumElements(), NumElts); |
||
1125 | return std::make_pair( |
||
1126 | TypeIdx, LLT::fixed_vector(NewSize, VecTy.getElementType())); |
||
1127 | }); |
||
1128 | } |
||
1129 | |||
1130 | /// Limit the number of elements in EltTy vectors to at most MaxElements. |
||
1131 | LegalizeRuleSet &clampMaxNumElements(unsigned TypeIdx, const LLT EltTy, |
||
1132 | unsigned MaxElements) { |
||
1133 | // Mark the type index as covered: |
||
1134 | typeIdx(TypeIdx); |
||
1135 | return actionIf( |
||
1136 | LegalizeAction::FewerElements, |
||
1137 | [=](const LegalityQuery &Query) { |
||
1138 | LLT VecTy = Query.Types[TypeIdx]; |
||
1139 | return VecTy.isVector() && VecTy.getElementType() == EltTy && |
||
1140 | VecTy.getNumElements() > MaxElements; |
||
1141 | }, |
||
1142 | [=](const LegalityQuery &Query) { |
||
1143 | LLT VecTy = Query.Types[TypeIdx]; |
||
1144 | LLT NewTy = LLT::scalarOrVector(ElementCount::getFixed(MaxElements), |
||
1145 | VecTy.getElementType()); |
||
1146 | return std::make_pair(TypeIdx, NewTy); |
||
1147 | }); |
||
1148 | } |
||
1149 | /// Limit the number of elements for the given vectors to at least MinTy's |
||
1150 | /// number of elements and at most MaxTy's number of elements. |
||
1151 | /// |
||
1152 | /// No effect if the type is not a vector or does not have the same element |
||
1153 | /// type as the constraints. |
||
1154 | /// The element type of MinTy and MaxTy must match. |
||
1155 | LegalizeRuleSet &clampNumElements(unsigned TypeIdx, const LLT MinTy, |
||
1156 | const LLT MaxTy) { |
||
1157 | assert(MinTy.getElementType() == MaxTy.getElementType() && |
||
1158 | "Expected element types to agree"); |
||
1159 | |||
1160 | const LLT EltTy = MinTy.getElementType(); |
||
1161 | return clampMinNumElements(TypeIdx, EltTy, MinTy.getNumElements()) |
||
1162 | .clampMaxNumElements(TypeIdx, EltTy, MaxTy.getNumElements()); |
||
1163 | } |
||
1164 | |||
1165 | /// Express \p EltTy vectors strictly using vectors with \p NumElts elements |
||
1166 | /// (or scalars when \p NumElts equals 1). |
||
1167 | /// First pad with undef elements to nearest larger multiple of \p NumElts. |
||
1168 | /// Then perform split with all sub-instructions having the same type. |
||
1169 | /// Using clampMaxNumElements (non-strict) can result in leftover instruction |
||
1170 | /// with different type (fewer elements then \p NumElts or scalar). |
||
1171 | /// No effect if the type is not a vector. |
||
1172 | LegalizeRuleSet &clampMaxNumElementsStrict(unsigned TypeIdx, const LLT EltTy, |
||
1173 | unsigned NumElts) { |
||
1174 | return alignNumElementsTo(TypeIdx, EltTy, NumElts) |
||
1175 | .clampMaxNumElements(TypeIdx, EltTy, NumElts); |
||
1176 | } |
||
1177 | |||
1178 | /// Fallback on the previous implementation. This should only be used while |
||
1179 | /// porting a rule. |
||
1180 | LegalizeRuleSet &fallback() { |
||
1181 | add({always, LegalizeAction::UseLegacyRules}); |
||
1182 | return *this; |
||
1183 | } |
||
1184 | |||
1185 | /// Check if there is no type index which is obviously not handled by the |
||
1186 | /// LegalizeRuleSet in any way at all. |
||
1187 | /// \pre Type indices of the opcode form a dense [0, \p NumTypeIdxs) set. |
||
1188 | bool verifyTypeIdxsCoverage(unsigned NumTypeIdxs) const; |
||
1189 | /// Check if there is no imm index which is obviously not handled by the |
||
1190 | /// LegalizeRuleSet in any way at all. |
||
1191 | /// \pre Type indices of the opcode form a dense [0, \p NumTypeIdxs) set. |
||
1192 | bool verifyImmIdxsCoverage(unsigned NumImmIdxs) const; |
||
1193 | |||
1194 | /// Apply the ruleset to the given LegalityQuery. |
||
1195 | LegalizeActionStep apply(const LegalityQuery &Query) const; |
||
1196 | }; |
||
1197 | |||
1198 | class LegalizerInfo { |
||
1199 | public: |
||
1200 | virtual ~LegalizerInfo() = default; |
||
1201 | |||
1202 | const LegacyLegalizerInfo &getLegacyLegalizerInfo() const { |
||
1203 | return LegacyInfo; |
||
1204 | } |
||
1205 | LegacyLegalizerInfo &getLegacyLegalizerInfo() { return LegacyInfo; } |
||
1206 | |||
1207 | unsigned getOpcodeIdxForOpcode(unsigned Opcode) const; |
||
1208 | unsigned getActionDefinitionsIdx(unsigned Opcode) const; |
||
1209 | |||
1210 | /// Perform simple self-diagnostic and assert if there is anything obviously |
||
1211 | /// wrong with the actions set up. |
||
1212 | void verify(const MCInstrInfo &MII) const; |
||
1213 | |||
1214 | /// Get the action definitions for the given opcode. Use this to run a |
||
1215 | /// LegalityQuery through the definitions. |
||
1216 | const LegalizeRuleSet &getActionDefinitions(unsigned Opcode) const; |
||
1217 | |||
1218 | /// Get the action definition builder for the given opcode. Use this to define |
||
1219 | /// the action definitions. |
||
1220 | /// |
||
1221 | /// It is an error to request an opcode that has already been requested by the |
||
1222 | /// multiple-opcode variant. |
||
1223 | LegalizeRuleSet &getActionDefinitionsBuilder(unsigned Opcode); |
||
1224 | |||
1225 | /// Get the action definition builder for the given set of opcodes. Use this |
||
1226 | /// to define the action definitions for multiple opcodes at once. The first |
||
1227 | /// opcode given will be considered the representative opcode and will hold |
||
1228 | /// the definitions whereas the other opcodes will be configured to refer to |
||
1229 | /// the representative opcode. This lowers memory requirements and very |
||
1230 | /// slightly improves performance. |
||
1231 | /// |
||
1232 | /// It would be very easy to introduce unexpected side-effects as a result of |
||
1233 | /// this aliasing if it were permitted to request different but intersecting |
||
1234 | /// sets of opcodes but that is difficult to keep track of. It is therefore an |
||
1235 | /// error to request the same opcode twice using this API, to request an |
||
1236 | /// opcode that already has definitions, or to use the single-opcode API on an |
||
1237 | /// opcode that has already been requested by this API. |
||
1238 | LegalizeRuleSet & |
||
1239 | getActionDefinitionsBuilder(std::initializer_list<unsigned> Opcodes); |
||
1240 | void aliasActionDefinitions(unsigned OpcodeTo, unsigned OpcodeFrom); |
||
1241 | |||
1242 | /// Determine what action should be taken to legalize the described |
||
1243 | /// instruction. Requires computeTables to have been called. |
||
1244 | /// |
||
1245 | /// \returns a description of the next legalization step to perform. |
||
1246 | LegalizeActionStep getAction(const LegalityQuery &Query) const; |
||
1247 | |||
1248 | /// Determine what action should be taken to legalize the given generic |
||
1249 | /// instruction. |
||
1250 | /// |
||
1251 | /// \returns a description of the next legalization step to perform. |
||
1252 | LegalizeActionStep getAction(const MachineInstr &MI, |
||
1253 | const MachineRegisterInfo &MRI) const; |
||
1254 | |||
1255 | bool isLegal(const LegalityQuery &Query) const { |
||
1256 | return getAction(Query).Action == LegalizeAction::Legal; |
||
1257 | } |
||
1258 | |||
1259 | bool isLegalOrCustom(const LegalityQuery &Query) const { |
||
1260 | auto Action = getAction(Query).Action; |
||
1261 | return Action == LegalizeAction::Legal || Action == LegalizeAction::Custom; |
||
1262 | } |
||
1263 | |||
1264 | bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const; |
||
1265 | bool isLegalOrCustom(const MachineInstr &MI, |
||
1266 | const MachineRegisterInfo &MRI) const; |
||
1267 | |||
1268 | /// Called for instructions with the Custom LegalizationAction. |
||
1269 | virtual bool legalizeCustom(LegalizerHelper &Helper, |
||
1270 | MachineInstr &MI) const { |
||
1271 | llvm_unreachable("must implement this if custom action is used"); |
||
1272 | } |
||
1273 | |||
1274 | /// \returns true if MI is either legal or has been legalized and false if not |
||
1275 | /// legal. |
||
1276 | /// Return true if MI is either legal or has been legalized and false |
||
1277 | /// if not legal. |
||
1278 | virtual bool legalizeIntrinsic(LegalizerHelper &Helper, |
||
1279 | MachineInstr &MI) const { |
||
1280 | return true; |
||
1281 | } |
||
1282 | |||
1283 | /// Return the opcode (SEXT/ZEXT/ANYEXT) that should be performed while |
||
1284 | /// widening a constant of type SmallTy which targets can override. |
||
1285 | /// For eg, the DAG does (SmallTy.isByteSized() ? G_SEXT : G_ZEXT) which |
||
1286 | /// will be the default. |
||
1287 | virtual unsigned getExtOpcodeForWideningConstant(LLT SmallTy) const; |
||
1288 | |||
1289 | private: |
||
1290 | static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START; |
||
1291 | static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; |
||
1292 | |||
1293 | LegalizeRuleSet RulesForOpcode[LastOp - FirstOp + 1]; |
||
1294 | LegacyLegalizerInfo LegacyInfo; |
||
1295 | }; |
||
1296 | |||
1297 | #ifndef NDEBUG |
||
1298 | /// Checks that MIR is fully legal, returns an illegal instruction if it's not, |
||
1299 | /// nullptr otherwise |
||
1300 | const MachineInstr *machineFunctionIsIllegal(const MachineFunction &MF); |
||
1301 | #endif |
||
1302 | |||
1303 | } // end namespace llvm. |
||
1304 | |||
1305 | #endif // LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H |