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