xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
1 //===- llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.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 /// This implementation has been deprecated for a long time but it still in use
12 /// in a few places.
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
16 #define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
17 
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/CodeGen/LowLevelType.h"
20 #include "llvm/CodeGen/TargetOpcodes.h"
21 #include <unordered_map>
22 #include <vector>
23 
24 namespace llvm {
25 struct LegalityQuery;
26 
27 namespace LegacyLegalizeActions {
28 enum LegacyLegalizeAction : std::uint8_t {
29   /// The operation is expected to be selectable directly by the target, and
30   /// no transformation is necessary.
31   Legal,
32 
33   /// The operation should be synthesized from multiple instructions acting on
34   /// a narrower scalar base-type. For example a 64-bit add might be
35   /// implemented in terms of 32-bit add-with-carry.
36   NarrowScalar,
37 
38   /// The operation should be implemented in terms of a wider scalar
39   /// base-type. For example a <2 x s8> add could be implemented as a <2
40   /// x s32> add (ignoring the high bits).
41   WidenScalar,
42 
43   /// The (vector) operation should be implemented by splitting it into
44   /// sub-vectors where the operation is legal. For example a <8 x s64> add
45   /// might be implemented as 4 separate <2 x s64> adds.
46   FewerElements,
47 
48   /// The (vector) operation should be implemented by widening the input
49   /// vector and ignoring the lanes added by doing so. For example <2 x i8> is
50   /// rarely legal, but you might perform an <8 x i8> and then only look at
51   /// the first two results.
52   MoreElements,
53 
54   /// Perform the operation on a different, but equivalently sized type.
55   Bitcast,
56 
57   /// The operation itself must be expressed in terms of simpler actions on
58   /// this target. E.g. a SREM replaced by an SDIV and subtraction.
59   Lower,
60 
61   /// The operation should be implemented as a call to some kind of runtime
62   /// support library. For example this usually happens on machines that don't
63   /// support floating-point operations natively.
64   Libcall,
65 
66   /// The target wants to do something special with this combination of
67   /// operand and type. A callback will be issued when it is needed.
68   Custom,
69 
70   /// This operation is completely unsupported on the target. A programming
71   /// error has occurred.
72   Unsupported,
73 
74   /// Sentinel value for when no action was found in the specified table.
75   NotFound,
76 };
77 } // end namespace LegacyLegalizeActions
78 raw_ostream &operator<<(raw_ostream &OS,
79                         LegacyLegalizeActions::LegacyLegalizeAction Action);
80 
81 /// Legalization is decided based on an instruction's opcode, which type slot
82 /// we're considering, and what the existing type is. These aspects are gathered
83 /// together for convenience in the InstrAspect class.
84 struct InstrAspect {
85   unsigned Opcode;
86   unsigned Idx = 0;
87   LLT Type;
88 
89   InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {}
90   InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)
91       : Opcode(Opcode), Idx(Idx), Type(Type) {}
92 
93   bool operator==(const InstrAspect &RHS) const {
94     return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type;
95   }
96 };
97 
98 /// The result of a query. It either indicates a final answer of Legal or
99 /// Unsupported or describes an action that must be taken to make an operation
100 /// more legal.
101 struct LegacyLegalizeActionStep {
102   /// The action to take or the final answer.
103   LegacyLegalizeActions::LegacyLegalizeAction Action;
104   /// If describing an action, the type index to change. Otherwise zero.
105   unsigned TypeIdx;
106   /// If describing an action, the new type for TypeIdx. Otherwise LLT{}.
107   LLT NewType;
108 
109   LegacyLegalizeActionStep(LegacyLegalizeActions::LegacyLegalizeAction Action,
110                            unsigned TypeIdx, const LLT NewType)
111       : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {}
112 
113   bool operator==(const LegacyLegalizeActionStep &RHS) const {
114     return std::tie(Action, TypeIdx, NewType) ==
115         std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType);
116   }
117 };
118 
119 
120 class LegacyLegalizerInfo {
121 public:
122   using SizeAndAction =
123       std::pair<uint16_t, LegacyLegalizeActions::LegacyLegalizeAction>;
124   using SizeAndActionsVec = std::vector<SizeAndAction>;
125   using SizeChangeStrategy =
126       std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>;
127 
128   LegacyLegalizerInfo();
129 
130   static bool needsLegalizingToDifferentSize(
131       const LegacyLegalizeActions::LegacyLegalizeAction Action) {
132     using namespace LegacyLegalizeActions;
133     switch (Action) {
134     case NarrowScalar:
135     case WidenScalar:
136     case FewerElements:
137     case MoreElements:
138     case Unsupported:
139       return true;
140     default:
141       return false;
142     }
143   }
144 
145   /// Compute any ancillary tables needed to quickly decide how an operation
146   /// should be handled. This must be called after all "set*Action"methods but
147   /// before any query is made or incorrect results may be returned.
148   void computeTables();
149 
150   /// More friendly way to set an action for common types that have an LLT
151   /// representation.
152   /// The LegacyLegalizeAction must be one for which
153   /// NeedsLegalizingToDifferentSize returns false.
154   void setAction(const InstrAspect &Aspect,
155                  LegacyLegalizeActions::LegacyLegalizeAction Action) {
156     assert(!needsLegalizingToDifferentSize(Action));
157     TablesInitialized = false;
158     const unsigned OpcodeIdx = Aspect.Opcode - FirstOp;
159     if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx)
160       SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1);
161     SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action;
162   }
163 
164   /// The setAction calls record the non-size-changing legalization actions
165   /// to take on specificly-sized types. The SizeChangeStrategy defines what
166   /// to do when the size of the type needs to be changed to reach a legally
167   /// sized type (i.e., one that was defined through a setAction call).
168   /// e.g.
169   /// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal);
170   /// setLegalizeScalarToDifferentSizeStrategy(
171   ///   G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
172   /// will end up defining getAction({G_ADD, 0, T}) to return the following
173   /// actions for different scalar types T:
174   ///  LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)}
175   ///  LLT::scalar(32):                 {Legal, 0, LLT::scalar(32)}
176   ///  LLT::scalar(33)..:               {NarrowScalar, 0, LLT::scalar(32)}
177   ///
178   /// If no SizeChangeAction gets defined, through this function,
179   /// the default is unsupportedForDifferentSizes.
180   void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode,
181                                                 const unsigned TypeIdx,
182                                                 SizeChangeStrategy S) {
183     const unsigned OpcodeIdx = Opcode - FirstOp;
184     if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
185       ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
186     ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
187   }
188 
189   /// See also setLegalizeScalarToDifferentSizeStrategy.
190   /// This function allows to set the SizeChangeStrategy for vector elements.
191   void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode,
192                                                        const unsigned TypeIdx,
193                                                        SizeChangeStrategy S) {
194     const unsigned OpcodeIdx = Opcode - FirstOp;
195     if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
196       VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
197     VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
198   }
199 
200   /// A SizeChangeStrategy for the common case where legalization for a
201   /// particular operation consists of only supporting a specific set of type
202   /// sizes. E.g.
203   ///   setAction ({G_DIV, 0, LLT::scalar(32)}, Legal);
204   ///   setAction ({G_DIV, 0, LLT::scalar(64)}, Legal);
205   ///   setLegalizeScalarToDifferentSizeStrategy(
206   ///     G_DIV, 0, unsupportedForDifferentSizes);
207   /// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64,
208   /// and Unsupported for all other scalar types T.
209   static SizeAndActionsVec
210   unsupportedForDifferentSizes(const SizeAndActionsVec &v) {
211     using namespace LegacyLegalizeActions;
212     return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported,
213                                                      Unsupported);
214   }
215 
216   /// A SizeChangeStrategy for the common case where legalization for a
217   /// particular operation consists of widening the type to a large legal type,
218   /// unless there is no such type and then instead it should be narrowed to the
219   /// largest legal type.
220   static SizeAndActionsVec
221   widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) {
222     using namespace LegacyLegalizeActions;
223     assert(v.size() > 0 &&
224            "At least one size that can be legalized towards is needed"
225            " for this SizeChangeStrategy");
226     return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
227                                                      NarrowScalar);
228   }
229 
230   static SizeAndActionsVec
231   widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) {
232     using namespace LegacyLegalizeActions;
233     return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
234                                                      Unsupported);
235   }
236 
237   static SizeAndActionsVec
238   narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) {
239     using namespace LegacyLegalizeActions;
240     return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
241                                                        Unsupported);
242   }
243 
244   /// A SizeChangeStrategy for the common case where legalization for a
245   /// particular vector operation consists of having more elements in the
246   /// vector, to a type that is legal. Unless there is no such type and then
247   /// instead it should be legalized towards the widest vector that's still
248   /// legal. E.g.
249   ///   setAction({G_ADD, LLT::vector(8, 8)}, Legal);
250   ///   setAction({G_ADD, LLT::vector(16, 8)}, Legal);
251   ///   setAction({G_ADD, LLT::vector(2, 32)}, Legal);
252   ///   setAction({G_ADD, LLT::vector(4, 32)}, Legal);
253   ///   setLegalizeVectorElementToDifferentSizeStrategy(
254   ///     G_ADD, 0, moreToWiderTypesAndLessToWidest);
255   /// will result in the following getAction results:
256   ///   * getAction({G_ADD, LLT::vector(8,8)}) returns
257   ///       (Legal, vector(8,8)).
258   ///   * getAction({G_ADD, LLT::vector(9,8)}) returns
259   ///       (MoreElements, vector(16,8)).
260   ///   * getAction({G_ADD, LLT::vector(8,32)}) returns
261   ///       (FewerElements, vector(4,32)).
262   static SizeAndActionsVec
263   moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) {
264     using namespace LegacyLegalizeActions;
265     return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements,
266                                                      FewerElements);
267   }
268 
269   /// Helper function to implement many typical SizeChangeStrategy functions.
270   static SizeAndActionsVec increaseToLargerTypesAndDecreaseToLargest(
271       const SizeAndActionsVec &v,
272       LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction,
273       LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction);
274   /// Helper function to implement many typical SizeChangeStrategy functions.
275   static SizeAndActionsVec decreaseToSmallerTypesAndIncreaseToSmallest(
276       const SizeAndActionsVec &v,
277       LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction,
278       LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction);
279 
280   LegacyLegalizeActionStep getAction(const LegalityQuery &Query) const;
281 
282   unsigned getOpcodeIdxForOpcode(unsigned Opcode) const;
283 
284 private:
285   /// Determine what action should be taken to legalize the given generic
286   /// instruction opcode, type-index and type. Requires computeTables to have
287   /// been called.
288   ///
289   /// \returns a pair consisting of the kind of legalization that should be
290   /// performed and the destination type.
291   std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
292   getAspectAction(const InstrAspect &Aspect) const;
293 
294   /// The SizeAndActionsVec is a representation mapping between all natural
295   /// numbers and an Action. The natural number represents the bit size of
296   /// the InstrAspect. For example, for a target with native support for 32-bit
297   /// and 64-bit additions, you'd express that as:
298   /// setScalarAction(G_ADD, 0,
299   ///           {{1, WidenScalar},  // bit sizes [ 1, 31[
300   ///            {32, Legal},       // bit sizes [32, 33[
301   ///            {33, WidenScalar}, // bit sizes [33, 64[
302   ///            {64, Legal},       // bit sizes [64, 65[
303   ///            {65, NarrowScalar} // bit sizes [65, +inf[
304   ///           });
305   /// It may be that only 64-bit pointers are supported on your target:
306   /// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1),
307   ///           {{1, Unsupported},  // bit sizes [ 1, 63[
308   ///            {64, Legal},       // bit sizes [64, 65[
309   ///            {65, Unsupported}, // bit sizes [65, +inf[
310   ///           });
311   void setScalarAction(const unsigned Opcode, const unsigned TypeIndex,
312                        const SizeAndActionsVec &SizeAndActions) {
313     const unsigned OpcodeIdx = Opcode - FirstOp;
314     SmallVector<SizeAndActionsVec, 1> &Actions = ScalarActions[OpcodeIdx];
315     setActions(TypeIndex, Actions, SizeAndActions);
316   }
317   void setPointerAction(const unsigned Opcode, const unsigned TypeIndex,
318                         const unsigned AddressSpace,
319                         const SizeAndActionsVec &SizeAndActions) {
320     const unsigned OpcodeIdx = Opcode - FirstOp;
321     if (AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace) ==
322         AddrSpace2PointerActions[OpcodeIdx].end())
323       AddrSpace2PointerActions[OpcodeIdx][AddressSpace] = {{}};
324     SmallVector<SizeAndActionsVec, 1> &Actions =
325         AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second;
326     setActions(TypeIndex, Actions, SizeAndActions);
327   }
328 
329   /// If an operation on a given vector type (say <M x iN>) isn't explicitly
330   /// specified, we proceed in 2 stages. First we legalize the underlying scalar
331   /// (so that there's at least one legal vector with that scalar), then we
332   /// adjust the number of elements in the vector so that it is legal. The
333   /// desired action in the first step is controlled by this function.
334   void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex,
335                                const SizeAndActionsVec &SizeAndActions) {
336     unsigned OpcodeIdx = Opcode - FirstOp;
337     SmallVector<SizeAndActionsVec, 1> &Actions =
338         ScalarInVectorActions[OpcodeIdx];
339     setActions(TypeIndex, Actions, SizeAndActions);
340   }
341 
342   /// See also setScalarInVectorAction.
343   /// This function let's you specify the number of elements in a vector that
344   /// are legal for a legal element size.
345   void setVectorNumElementAction(const unsigned Opcode,
346                                  const unsigned TypeIndex,
347                                  const unsigned ElementSize,
348                                  const SizeAndActionsVec &SizeAndActions) {
349     const unsigned OpcodeIdx = Opcode - FirstOp;
350     if (NumElements2Actions[OpcodeIdx].find(ElementSize) ==
351         NumElements2Actions[OpcodeIdx].end())
352       NumElements2Actions[OpcodeIdx][ElementSize] = {{}};
353     SmallVector<SizeAndActionsVec, 1> &Actions =
354         NumElements2Actions[OpcodeIdx].find(ElementSize)->second;
355     setActions(TypeIndex, Actions, SizeAndActions);
356   }
357 
358   /// A partial SizeAndActionsVec potentially doesn't cover all bit sizes,
359   /// i.e. it's OK if it doesn't start from size 1.
360   static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) {
361     using namespace LegacyLegalizeActions;
362 #ifndef NDEBUG
363     // The sizes should be in increasing order
364     int prev_size = -1;
365     for(auto SizeAndAction: v) {
366       assert(SizeAndAction.first > prev_size);
367       prev_size = SizeAndAction.first;
368     }
369     // - for every Widen action, there should be a larger bitsize that
370     //   can be legalized towards (e.g. Legal, Lower, Libcall or Custom
371     //   action).
372     // - for every Narrow action, there should be a smaller bitsize that
373     //   can be legalized towards.
374     int SmallestNarrowIdx = -1;
375     int LargestWidenIdx = -1;
376     int SmallestLegalizableToSameSizeIdx = -1;
377     int LargestLegalizableToSameSizeIdx = -1;
378     for(size_t i=0; i<v.size(); ++i) {
379       switch (v[i].second) {
380         case FewerElements:
381         case NarrowScalar:
382           if (SmallestNarrowIdx == -1)
383             SmallestNarrowIdx = i;
384           break;
385         case WidenScalar:
386         case MoreElements:
387           LargestWidenIdx = i;
388           break;
389         case Unsupported:
390           break;
391         default:
392           if (SmallestLegalizableToSameSizeIdx == -1)
393             SmallestLegalizableToSameSizeIdx = i;
394           LargestLegalizableToSameSizeIdx = i;
395       }
396     }
397     if (SmallestNarrowIdx != -1) {
398       assert(SmallestLegalizableToSameSizeIdx != -1);
399       assert(SmallestNarrowIdx > SmallestLegalizableToSameSizeIdx);
400     }
401     if (LargestWidenIdx != -1)
402       assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx);
403 #endif
404   }
405 
406   /// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with
407   /// from size 1.
408   static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) {
409 #ifndef NDEBUG
410     // Data structure invariant: The first bit size must be size 1.
411     assert(v.size() >= 1);
412     assert(v[0].first == 1);
413     checkPartialSizeAndActionsVector(v);
414 #endif
415   }
416 
417   /// Sets actions for all bit sizes on a particular generic opcode, type
418   /// index and scalar or pointer type.
419   void setActions(unsigned TypeIndex,
420                   SmallVector<SizeAndActionsVec, 1> &Actions,
421                   const SizeAndActionsVec &SizeAndActions) {
422     checkFullSizeAndActionsVector(SizeAndActions);
423     if (Actions.size() <= TypeIndex)
424       Actions.resize(TypeIndex + 1);
425     Actions[TypeIndex] = SizeAndActions;
426   }
427 
428   static SizeAndAction findAction(const SizeAndActionsVec &Vec,
429                                   const uint32_t Size);
430 
431   /// Returns the next action needed to get the scalar or pointer type closer
432   /// to being legal
433   /// E.g. findLegalAction({G_REM, 13}) should return
434   /// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will
435   /// probably be called, which should return (Lower, 32).
436   /// This is assuming the setScalarAction on G_REM was something like:
437   /// setScalarAction(G_REM, 0,
438   ///           {{1, WidenScalar},  // bit sizes [ 1, 31[
439   ///            {32, Lower},       // bit sizes [32, 33[
440   ///            {33, NarrowScalar} // bit sizes [65, +inf[
441   ///           });
442   std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
443   findScalarLegalAction(const InstrAspect &Aspect) const;
444 
445   /// Returns the next action needed towards legalizing the vector type.
446   std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
447   findVectorLegalAction(const InstrAspect &Aspect) const;
448 
449   static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
450   static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
451 
452   // Data structures used temporarily during construction of legality data:
453   using TypeMap = DenseMap<LLT, LegacyLegalizeActions::LegacyLegalizeAction>;
454   SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];
455   SmallVector<SizeChangeStrategy, 1>
456       ScalarSizeChangeStrategies[LastOp - FirstOp + 1];
457   SmallVector<SizeChangeStrategy, 1>
458       VectorElementSizeChangeStrategies[LastOp - FirstOp + 1];
459   bool TablesInitialized = false;
460 
461   // Data structures used by getAction:
462   SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
463   SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
464   std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
465       AddrSpace2PointerActions[LastOp - FirstOp + 1];
466   std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
467       NumElements2Actions[LastOp - FirstOp + 1];
468 };
469 
470 } // end namespace llvm
471 
472 #endif // LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
473