xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
1*fe6060f1SDimitry Andric //===- lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp - Legalizer ---------===//
2*fe6060f1SDimitry Andric //
3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fe6060f1SDimitry Andric //
7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric //
9*fe6060f1SDimitry Andric // Implement an interface to specify and query how an illegal operation on a
10*fe6060f1SDimitry Andric // given type should be expanded.
11*fe6060f1SDimitry Andric //
12*fe6060f1SDimitry Andric // Issues to be resolved:
13*fe6060f1SDimitry Andric //   + Make it fast.
14*fe6060f1SDimitry Andric //   + Support weird types like i3, <7 x i3>, ...
15*fe6060f1SDimitry Andric //   + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
16*fe6060f1SDimitry Andric //
17*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
18*fe6060f1SDimitry Andric 
19*fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h"
20*fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
21*fe6060f1SDimitry Andric #include <map>
22*fe6060f1SDimitry Andric 
23*fe6060f1SDimitry Andric using namespace llvm;
24*fe6060f1SDimitry Andric using namespace LegacyLegalizeActions;
25*fe6060f1SDimitry Andric 
26*fe6060f1SDimitry Andric #define DEBUG_TYPE "legalizer-info"
27*fe6060f1SDimitry Andric 
28*fe6060f1SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, LegacyLegalizeAction Action) {
29*fe6060f1SDimitry Andric   switch (Action) {
30*fe6060f1SDimitry Andric   case Legal:
31*fe6060f1SDimitry Andric     OS << "Legal";
32*fe6060f1SDimitry Andric     break;
33*fe6060f1SDimitry Andric   case NarrowScalar:
34*fe6060f1SDimitry Andric     OS << "NarrowScalar";
35*fe6060f1SDimitry Andric     break;
36*fe6060f1SDimitry Andric   case WidenScalar:
37*fe6060f1SDimitry Andric     OS << "WidenScalar";
38*fe6060f1SDimitry Andric     break;
39*fe6060f1SDimitry Andric   case FewerElements:
40*fe6060f1SDimitry Andric     OS << "FewerElements";
41*fe6060f1SDimitry Andric     break;
42*fe6060f1SDimitry Andric   case MoreElements:
43*fe6060f1SDimitry Andric     OS << "MoreElements";
44*fe6060f1SDimitry Andric     break;
45*fe6060f1SDimitry Andric   case Bitcast:
46*fe6060f1SDimitry Andric     OS << "Bitcast";
47*fe6060f1SDimitry Andric     break;
48*fe6060f1SDimitry Andric   case Lower:
49*fe6060f1SDimitry Andric     OS << "Lower";
50*fe6060f1SDimitry Andric     break;
51*fe6060f1SDimitry Andric   case Libcall:
52*fe6060f1SDimitry Andric     OS << "Libcall";
53*fe6060f1SDimitry Andric     break;
54*fe6060f1SDimitry Andric   case Custom:
55*fe6060f1SDimitry Andric     OS << "Custom";
56*fe6060f1SDimitry Andric     break;
57*fe6060f1SDimitry Andric   case Unsupported:
58*fe6060f1SDimitry Andric     OS << "Unsupported";
59*fe6060f1SDimitry Andric     break;
60*fe6060f1SDimitry Andric   case NotFound:
61*fe6060f1SDimitry Andric     OS << "NotFound";
62*fe6060f1SDimitry Andric     break;
63*fe6060f1SDimitry Andric   }
64*fe6060f1SDimitry Andric   return OS;
65*fe6060f1SDimitry Andric }
66*fe6060f1SDimitry Andric 
67*fe6060f1SDimitry Andric LegacyLegalizerInfo::LegacyLegalizerInfo() : TablesInitialized(false) {
68*fe6060f1SDimitry Andric   // Set defaults.
69*fe6060f1SDimitry Andric   // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the
70*fe6060f1SDimitry Andric   // fundamental load/store Jakob proposed. Once loads & stores are supported.
71*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}});
72*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}});
73*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}});
74*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}});
75*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}});
76*fe6060f1SDimitry Andric 
77*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}});
78*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}});
79*fe6060f1SDimitry Andric 
80*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
81*fe6060f1SDimitry Andric       TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall);
82*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
83*fe6060f1SDimitry Andric       TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
84*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
85*fe6060f1SDimitry Andric       TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest);
86*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
87*fe6060f1SDimitry Andric       TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall);
88*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
89*fe6060f1SDimitry Andric       TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall);
90*fe6060f1SDimitry Andric 
91*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
92*fe6060f1SDimitry Andric       TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise);
93*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
94*fe6060f1SDimitry Andric       TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall);
95*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
96*fe6060f1SDimitry Andric       TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall);
97*fe6060f1SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
98*fe6060f1SDimitry Andric       TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall);
99*fe6060f1SDimitry Andric   setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}});
100*fe6060f1SDimitry Andric }
101*fe6060f1SDimitry Andric 
102*fe6060f1SDimitry Andric void LegacyLegalizerInfo::computeTables() {
103*fe6060f1SDimitry Andric   assert(TablesInitialized == false);
104*fe6060f1SDimitry Andric 
105*fe6060f1SDimitry Andric   for (unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) {
106*fe6060f1SDimitry Andric     const unsigned Opcode = FirstOp + OpcodeIdx;
107*fe6060f1SDimitry Andric     for (unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size();
108*fe6060f1SDimitry Andric          ++TypeIdx) {
109*fe6060f1SDimitry Andric       // 0. Collect information specified through the setAction API, i.e.
110*fe6060f1SDimitry Andric       // for specific bit sizes.
111*fe6060f1SDimitry Andric       // For scalar types:
112*fe6060f1SDimitry Andric       SizeAndActionsVec ScalarSpecifiedActions;
113*fe6060f1SDimitry Andric       // For pointer types:
114*fe6060f1SDimitry Andric       std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions;
115*fe6060f1SDimitry Andric       // For vector types:
116*fe6060f1SDimitry Andric       std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions;
117*fe6060f1SDimitry Andric       for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) {
118*fe6060f1SDimitry Andric         const LLT Type = LLT2Action.first;
119*fe6060f1SDimitry Andric         const LegacyLegalizeAction Action = LLT2Action.second;
120*fe6060f1SDimitry Andric 
121*fe6060f1SDimitry Andric         auto SizeAction = std::make_pair(Type.getSizeInBits(), Action);
122*fe6060f1SDimitry Andric         if (Type.isPointer())
123*fe6060f1SDimitry Andric           AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back(
124*fe6060f1SDimitry Andric               SizeAction);
125*fe6060f1SDimitry Andric         else if (Type.isVector())
126*fe6060f1SDimitry Andric           ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()]
127*fe6060f1SDimitry Andric               .push_back(SizeAction);
128*fe6060f1SDimitry Andric         else
129*fe6060f1SDimitry Andric           ScalarSpecifiedActions.push_back(SizeAction);
130*fe6060f1SDimitry Andric       }
131*fe6060f1SDimitry Andric 
132*fe6060f1SDimitry Andric       // 1. Handle scalar types
133*fe6060f1SDimitry Andric       {
134*fe6060f1SDimitry Andric         // Decide how to handle bit sizes for which no explicit specification
135*fe6060f1SDimitry Andric         // was given.
136*fe6060f1SDimitry Andric         SizeChangeStrategy S = &unsupportedForDifferentSizes;
137*fe6060f1SDimitry Andric         if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() &&
138*fe6060f1SDimitry Andric             ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
139*fe6060f1SDimitry Andric           S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx];
140*fe6060f1SDimitry Andric         llvm::sort(ScalarSpecifiedActions);
141*fe6060f1SDimitry Andric         checkPartialSizeAndActionsVector(ScalarSpecifiedActions);
142*fe6060f1SDimitry Andric         setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions));
143*fe6060f1SDimitry Andric       }
144*fe6060f1SDimitry Andric 
145*fe6060f1SDimitry Andric       // 2. Handle pointer types
146*fe6060f1SDimitry Andric       for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) {
147*fe6060f1SDimitry Andric         llvm::sort(PointerSpecifiedActions.second);
148*fe6060f1SDimitry Andric         checkPartialSizeAndActionsVector(PointerSpecifiedActions.second);
149*fe6060f1SDimitry Andric         // For pointer types, we assume that there isn't a meaningfull way
150*fe6060f1SDimitry Andric         // to change the number of bits used in the pointer.
151*fe6060f1SDimitry Andric         setPointerAction(
152*fe6060f1SDimitry Andric             Opcode, TypeIdx, PointerSpecifiedActions.first,
153*fe6060f1SDimitry Andric             unsupportedForDifferentSizes(PointerSpecifiedActions.second));
154*fe6060f1SDimitry Andric       }
155*fe6060f1SDimitry Andric 
156*fe6060f1SDimitry Andric       // 3. Handle vector types
157*fe6060f1SDimitry Andric       SizeAndActionsVec ElementSizesSeen;
158*fe6060f1SDimitry Andric       for (auto VectorSpecifiedActions : ElemSize2SpecifiedActions) {
159*fe6060f1SDimitry Andric         llvm::sort(VectorSpecifiedActions.second);
160*fe6060f1SDimitry Andric         const uint16_t ElementSize = VectorSpecifiedActions.first;
161*fe6060f1SDimitry Andric         ElementSizesSeen.push_back({ElementSize, Legal});
162*fe6060f1SDimitry Andric         checkPartialSizeAndActionsVector(VectorSpecifiedActions.second);
163*fe6060f1SDimitry Andric         // For vector types, we assume that the best way to adapt the number
164*fe6060f1SDimitry Andric         // of elements is to the next larger number of elements type for which
165*fe6060f1SDimitry Andric         // the vector type is legal, unless there is no such type. In that case,
166*fe6060f1SDimitry Andric         // legalize towards a vector type with a smaller number of elements.
167*fe6060f1SDimitry Andric         SizeAndActionsVec NumElementsActions;
168*fe6060f1SDimitry Andric         for (SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) {
169*fe6060f1SDimitry Andric           assert(BitsizeAndAction.first % ElementSize == 0);
170*fe6060f1SDimitry Andric           const uint16_t NumElements = BitsizeAndAction.first / ElementSize;
171*fe6060f1SDimitry Andric           NumElementsActions.push_back({NumElements, BitsizeAndAction.second});
172*fe6060f1SDimitry Andric         }
173*fe6060f1SDimitry Andric         setVectorNumElementAction(
174*fe6060f1SDimitry Andric             Opcode, TypeIdx, ElementSize,
175*fe6060f1SDimitry Andric             moreToWiderTypesAndLessToWidest(NumElementsActions));
176*fe6060f1SDimitry Andric       }
177*fe6060f1SDimitry Andric       llvm::sort(ElementSizesSeen);
178*fe6060f1SDimitry Andric       SizeChangeStrategy VectorElementSizeChangeStrategy =
179*fe6060f1SDimitry Andric           &unsupportedForDifferentSizes;
180*fe6060f1SDimitry Andric       if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() &&
181*fe6060f1SDimitry Andric           VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
182*fe6060f1SDimitry Andric         VectorElementSizeChangeStrategy =
183*fe6060f1SDimitry Andric             VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx];
184*fe6060f1SDimitry Andric       setScalarInVectorAction(
185*fe6060f1SDimitry Andric           Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen));
186*fe6060f1SDimitry Andric     }
187*fe6060f1SDimitry Andric   }
188*fe6060f1SDimitry Andric 
189*fe6060f1SDimitry Andric   TablesInitialized = true;
190*fe6060f1SDimitry Andric }
191*fe6060f1SDimitry Andric 
192*fe6060f1SDimitry Andric // FIXME: inefficient implementation for now. Without ComputeValueVTs we're
193*fe6060f1SDimitry Andric // probably going to need specialized lookup structures for various types before
194*fe6060f1SDimitry Andric // we have any hope of doing well with something like <13 x i3>. Even the common
195*fe6060f1SDimitry Andric // cases should do better than what we have now.
196*fe6060f1SDimitry Andric std::pair<LegacyLegalizeAction, LLT>
197*fe6060f1SDimitry Andric LegacyLegalizerInfo::getAspectAction(const InstrAspect &Aspect) const {
198*fe6060f1SDimitry Andric   assert(TablesInitialized && "backend forgot to call computeTables");
199*fe6060f1SDimitry Andric   // These *have* to be implemented for now, they're the fundamental basis of
200*fe6060f1SDimitry Andric   // how everything else is transformed.
201*fe6060f1SDimitry Andric   if (Aspect.Type.isScalar() || Aspect.Type.isPointer())
202*fe6060f1SDimitry Andric     return findScalarLegalAction(Aspect);
203*fe6060f1SDimitry Andric   assert(Aspect.Type.isVector());
204*fe6060f1SDimitry Andric   return findVectorLegalAction(Aspect);
205*fe6060f1SDimitry Andric }
206*fe6060f1SDimitry Andric 
207*fe6060f1SDimitry Andric LegacyLegalizerInfo::SizeAndActionsVec
208*fe6060f1SDimitry Andric LegacyLegalizerInfo::increaseToLargerTypesAndDecreaseToLargest(
209*fe6060f1SDimitry Andric     const SizeAndActionsVec &v, LegacyLegalizeAction IncreaseAction,
210*fe6060f1SDimitry Andric     LegacyLegalizeAction DecreaseAction) {
211*fe6060f1SDimitry Andric   SizeAndActionsVec result;
212*fe6060f1SDimitry Andric   unsigned LargestSizeSoFar = 0;
213*fe6060f1SDimitry Andric   if (v.size() >= 1 && v[0].first != 1)
214*fe6060f1SDimitry Andric     result.push_back({1, IncreaseAction});
215*fe6060f1SDimitry Andric   for (size_t i = 0; i < v.size(); ++i) {
216*fe6060f1SDimitry Andric     result.push_back(v[i]);
217*fe6060f1SDimitry Andric     LargestSizeSoFar = v[i].first;
218*fe6060f1SDimitry Andric     if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) {
219*fe6060f1SDimitry Andric       result.push_back({LargestSizeSoFar + 1, IncreaseAction});
220*fe6060f1SDimitry Andric       LargestSizeSoFar = v[i].first + 1;
221*fe6060f1SDimitry Andric     }
222*fe6060f1SDimitry Andric   }
223*fe6060f1SDimitry Andric   result.push_back({LargestSizeSoFar + 1, DecreaseAction});
224*fe6060f1SDimitry Andric   return result;
225*fe6060f1SDimitry Andric }
226*fe6060f1SDimitry Andric 
227*fe6060f1SDimitry Andric LegacyLegalizerInfo::SizeAndActionsVec
228*fe6060f1SDimitry Andric LegacyLegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest(
229*fe6060f1SDimitry Andric     const SizeAndActionsVec &v, LegacyLegalizeAction DecreaseAction,
230*fe6060f1SDimitry Andric     LegacyLegalizeAction IncreaseAction) {
231*fe6060f1SDimitry Andric   SizeAndActionsVec result;
232*fe6060f1SDimitry Andric   if (v.size() == 0 || v[0].first != 1)
233*fe6060f1SDimitry Andric     result.push_back({1, IncreaseAction});
234*fe6060f1SDimitry Andric   for (size_t i = 0; i < v.size(); ++i) {
235*fe6060f1SDimitry Andric     result.push_back(v[i]);
236*fe6060f1SDimitry Andric     if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) {
237*fe6060f1SDimitry Andric       result.push_back({v[i].first + 1, DecreaseAction});
238*fe6060f1SDimitry Andric     }
239*fe6060f1SDimitry Andric   }
240*fe6060f1SDimitry Andric   return result;
241*fe6060f1SDimitry Andric }
242*fe6060f1SDimitry Andric 
243*fe6060f1SDimitry Andric LegacyLegalizerInfo::SizeAndAction
244*fe6060f1SDimitry Andric LegacyLegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) {
245*fe6060f1SDimitry Andric   assert(Size >= 1);
246*fe6060f1SDimitry Andric   // Find the last element in Vec that has a bitsize equal to or smaller than
247*fe6060f1SDimitry Andric   // the requested bit size.
248*fe6060f1SDimitry Andric   // That is the element just before the first element that is bigger than Size.
249*fe6060f1SDimitry Andric   auto It = partition_point(
250*fe6060f1SDimitry Andric       Vec, [=](const SizeAndAction &A) { return A.first <= Size; });
251*fe6060f1SDimitry Andric   assert(It != Vec.begin() && "Does Vec not start with size 1?");
252*fe6060f1SDimitry Andric   int VecIdx = It - Vec.begin() - 1;
253*fe6060f1SDimitry Andric 
254*fe6060f1SDimitry Andric   LegacyLegalizeAction Action = Vec[VecIdx].second;
255*fe6060f1SDimitry Andric   switch (Action) {
256*fe6060f1SDimitry Andric   case Legal:
257*fe6060f1SDimitry Andric   case Bitcast:
258*fe6060f1SDimitry Andric   case Lower:
259*fe6060f1SDimitry Andric   case Libcall:
260*fe6060f1SDimitry Andric   case Custom:
261*fe6060f1SDimitry Andric     return {Size, Action};
262*fe6060f1SDimitry Andric   case FewerElements:
263*fe6060f1SDimitry Andric     // FIXME: is this special case still needed and correct?
264*fe6060f1SDimitry Andric     // Special case for scalarization:
265*fe6060f1SDimitry Andric     if (Vec == SizeAndActionsVec({{1, FewerElements}}))
266*fe6060f1SDimitry Andric       return {1, FewerElements};
267*fe6060f1SDimitry Andric     LLVM_FALLTHROUGH;
268*fe6060f1SDimitry Andric   case NarrowScalar: {
269*fe6060f1SDimitry Andric     // The following needs to be a loop, as for now, we do allow needing to
270*fe6060f1SDimitry Andric     // go over "Unsupported" bit sizes before finding a legalizable bit size.
271*fe6060f1SDimitry Andric     // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8,
272*fe6060f1SDimitry Andric     // we need to iterate over s9, and then to s32 to return (s32, Legal).
273*fe6060f1SDimitry Andric     // If we want to get rid of the below loop, we should have stronger asserts
274*fe6060f1SDimitry Andric     // when building the SizeAndActionsVecs, probably not allowing
275*fe6060f1SDimitry Andric     // "Unsupported" unless at the ends of the vector.
276*fe6060f1SDimitry Andric     for (int i = VecIdx - 1; i >= 0; --i)
277*fe6060f1SDimitry Andric       if (!needsLegalizingToDifferentSize(Vec[i].second) &&
278*fe6060f1SDimitry Andric           Vec[i].second != Unsupported)
279*fe6060f1SDimitry Andric         return {Vec[i].first, Action};
280*fe6060f1SDimitry Andric     llvm_unreachable("");
281*fe6060f1SDimitry Andric   }
282*fe6060f1SDimitry Andric   case WidenScalar:
283*fe6060f1SDimitry Andric   case MoreElements: {
284*fe6060f1SDimitry Andric     // See above, the following needs to be a loop, at least for now.
285*fe6060f1SDimitry Andric     for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i)
286*fe6060f1SDimitry Andric       if (!needsLegalizingToDifferentSize(Vec[i].second) &&
287*fe6060f1SDimitry Andric           Vec[i].second != Unsupported)
288*fe6060f1SDimitry Andric         return {Vec[i].first, Action};
289*fe6060f1SDimitry Andric     llvm_unreachable("");
290*fe6060f1SDimitry Andric   }
291*fe6060f1SDimitry Andric   case Unsupported:
292*fe6060f1SDimitry Andric     return {Size, Unsupported};
293*fe6060f1SDimitry Andric   case NotFound:
294*fe6060f1SDimitry Andric     llvm_unreachable("NotFound");
295*fe6060f1SDimitry Andric   }
296*fe6060f1SDimitry Andric   llvm_unreachable("Action has an unknown enum value");
297*fe6060f1SDimitry Andric }
298*fe6060f1SDimitry Andric 
299*fe6060f1SDimitry Andric std::pair<LegacyLegalizeAction, LLT>
300*fe6060f1SDimitry Andric LegacyLegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const {
301*fe6060f1SDimitry Andric   assert(Aspect.Type.isScalar() || Aspect.Type.isPointer());
302*fe6060f1SDimitry Andric   if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
303*fe6060f1SDimitry Andric     return {NotFound, LLT()};
304*fe6060f1SDimitry Andric   const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode);
305*fe6060f1SDimitry Andric   if (Aspect.Type.isPointer() &&
306*fe6060f1SDimitry Andric       AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) ==
307*fe6060f1SDimitry Andric           AddrSpace2PointerActions[OpcodeIdx].end()) {
308*fe6060f1SDimitry Andric     return {NotFound, LLT()};
309*fe6060f1SDimitry Andric   }
310*fe6060f1SDimitry Andric   const SmallVector<SizeAndActionsVec, 1> &Actions =
311*fe6060f1SDimitry Andric       Aspect.Type.isPointer()
312*fe6060f1SDimitry Andric           ? AddrSpace2PointerActions[OpcodeIdx]
313*fe6060f1SDimitry Andric                 .find(Aspect.Type.getAddressSpace())
314*fe6060f1SDimitry Andric                 ->second
315*fe6060f1SDimitry Andric           : ScalarActions[OpcodeIdx];
316*fe6060f1SDimitry Andric   if (Aspect.Idx >= Actions.size())
317*fe6060f1SDimitry Andric     return {NotFound, LLT()};
318*fe6060f1SDimitry Andric   const SizeAndActionsVec &Vec = Actions[Aspect.Idx];
319*fe6060f1SDimitry Andric   // FIXME: speed up this search, e.g. by using a results cache for repeated
320*fe6060f1SDimitry Andric   // queries?
321*fe6060f1SDimitry Andric   auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits());
322*fe6060f1SDimitry Andric   return {SizeAndAction.second,
323*fe6060f1SDimitry Andric           Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first)
324*fe6060f1SDimitry Andric                                  : LLT::pointer(Aspect.Type.getAddressSpace(),
325*fe6060f1SDimitry Andric                                                 SizeAndAction.first)};
326*fe6060f1SDimitry Andric }
327*fe6060f1SDimitry Andric 
328*fe6060f1SDimitry Andric std::pair<LegacyLegalizeAction, LLT>
329*fe6060f1SDimitry Andric LegacyLegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const {
330*fe6060f1SDimitry Andric   assert(Aspect.Type.isVector());
331*fe6060f1SDimitry Andric   // First legalize the vector element size, then legalize the number of
332*fe6060f1SDimitry Andric   // lanes in the vector.
333*fe6060f1SDimitry Andric   if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
334*fe6060f1SDimitry Andric     return {NotFound, Aspect.Type};
335*fe6060f1SDimitry Andric   const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode);
336*fe6060f1SDimitry Andric   const unsigned TypeIdx = Aspect.Idx;
337*fe6060f1SDimitry Andric   if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size())
338*fe6060f1SDimitry Andric     return {NotFound, Aspect.Type};
339*fe6060f1SDimitry Andric   const SizeAndActionsVec &ElemSizeVec =
340*fe6060f1SDimitry Andric       ScalarInVectorActions[OpcodeIdx][TypeIdx];
341*fe6060f1SDimitry Andric 
342*fe6060f1SDimitry Andric   LLT IntermediateType;
343*fe6060f1SDimitry Andric   auto ElementSizeAndAction =
344*fe6060f1SDimitry Andric       findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits());
345*fe6060f1SDimitry Andric   IntermediateType = LLT::fixed_vector(Aspect.Type.getNumElements(),
346*fe6060f1SDimitry Andric                                        ElementSizeAndAction.first);
347*fe6060f1SDimitry Andric   if (ElementSizeAndAction.second != Legal)
348*fe6060f1SDimitry Andric     return {ElementSizeAndAction.second, IntermediateType};
349*fe6060f1SDimitry Andric 
350*fe6060f1SDimitry Andric   auto i = NumElements2Actions[OpcodeIdx].find(
351*fe6060f1SDimitry Andric       IntermediateType.getScalarSizeInBits());
352*fe6060f1SDimitry Andric   if (i == NumElements2Actions[OpcodeIdx].end()) {
353*fe6060f1SDimitry Andric     return {NotFound, IntermediateType};
354*fe6060f1SDimitry Andric   }
355*fe6060f1SDimitry Andric   const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx];
356*fe6060f1SDimitry Andric   auto NumElementsAndAction =
357*fe6060f1SDimitry Andric       findAction(NumElementsVec, IntermediateType.getNumElements());
358*fe6060f1SDimitry Andric   return {NumElementsAndAction.second,
359*fe6060f1SDimitry Andric           LLT::fixed_vector(NumElementsAndAction.first,
360*fe6060f1SDimitry Andric                             IntermediateType.getScalarSizeInBits())};
361*fe6060f1SDimitry Andric }
362*fe6060f1SDimitry Andric 
363*fe6060f1SDimitry Andric unsigned LegacyLegalizerInfo::getOpcodeIdxForOpcode(unsigned Opcode) const {
364*fe6060f1SDimitry Andric   assert(Opcode >= FirstOp && Opcode <= LastOp && "Unsupported opcode");
365*fe6060f1SDimitry Andric   return Opcode - FirstOp;
366*fe6060f1SDimitry Andric }
367*fe6060f1SDimitry Andric 
368*fe6060f1SDimitry Andric 
369*fe6060f1SDimitry Andric LegacyLegalizeActionStep
370*fe6060f1SDimitry Andric LegacyLegalizerInfo::getAction(const LegalityQuery &Query) const {
371*fe6060f1SDimitry Andric   for (unsigned i = 0; i < Query.Types.size(); ++i) {
372*fe6060f1SDimitry Andric     auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]});
373*fe6060f1SDimitry Andric     if (Action.first != Legal) {
374*fe6060f1SDimitry Andric       LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Action="
375*fe6060f1SDimitry Andric                         << Action.first << ", " << Action.second << "\n");
376*fe6060f1SDimitry Andric       return {Action.first, i, Action.second};
377*fe6060f1SDimitry Andric     } else
378*fe6060f1SDimitry Andric       LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Legal\n");
379*fe6060f1SDimitry Andric   }
380*fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << ".. (legacy) Legal\n");
381*fe6060f1SDimitry Andric   return {Legal, 0, LLT{}};
382*fe6060f1SDimitry Andric }
383*fe6060f1SDimitry Andric 
384