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