xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- lib/CodeGen/GlobalISel/LegalizerInfo.cpp - Legalizer ---------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // Implement an interface to specify and query how an illegal operation on a
10*0b57cec5SDimitry Andric // given type should be expanded.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric // Issues to be resolved:
13*0b57cec5SDimitry Andric //   + Make it fast.
14*0b57cec5SDimitry Andric //   + Support weird types like i3, <7 x i3>, ...
15*0b57cec5SDimitry Andric //   + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
16*0b57cec5SDimitry Andric //
17*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
20*0b57cec5SDimitry Andric #include "llvm/ADT/SmallBitVector.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
25*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
26*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
27*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
29*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
30*0b57cec5SDimitry Andric #include "llvm/Support/LowLevelTypeImpl.h"
31*0b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
32*0b57cec5SDimitry Andric #include <algorithm>
33*0b57cec5SDimitry Andric #include <map>
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric using namespace llvm;
36*0b57cec5SDimitry Andric using namespace LegalizeActions;
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric #define DEBUG_TYPE "legalizer-info"
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric cl::opt<bool> llvm::DisableGISelLegalityCheck(
41*0b57cec5SDimitry Andric     "disable-gisel-legality-check",
42*0b57cec5SDimitry Andric     cl::desc("Don't verify that MIR is fully legal between GlobalISel passes"),
43*0b57cec5SDimitry Andric     cl::Hidden);
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, LegalizeAction Action) {
46*0b57cec5SDimitry Andric   switch (Action) {
47*0b57cec5SDimitry Andric   case Legal:
48*0b57cec5SDimitry Andric     OS << "Legal";
49*0b57cec5SDimitry Andric     break;
50*0b57cec5SDimitry Andric   case NarrowScalar:
51*0b57cec5SDimitry Andric     OS << "NarrowScalar";
52*0b57cec5SDimitry Andric     break;
53*0b57cec5SDimitry Andric   case WidenScalar:
54*0b57cec5SDimitry Andric     OS << "WidenScalar";
55*0b57cec5SDimitry Andric     break;
56*0b57cec5SDimitry Andric   case FewerElements:
57*0b57cec5SDimitry Andric     OS << "FewerElements";
58*0b57cec5SDimitry Andric     break;
59*0b57cec5SDimitry Andric   case MoreElements:
60*0b57cec5SDimitry Andric     OS << "MoreElements";
61*0b57cec5SDimitry Andric     break;
62*0b57cec5SDimitry Andric   case Lower:
63*0b57cec5SDimitry Andric     OS << "Lower";
64*0b57cec5SDimitry Andric     break;
65*0b57cec5SDimitry Andric   case Libcall:
66*0b57cec5SDimitry Andric     OS << "Libcall";
67*0b57cec5SDimitry Andric     break;
68*0b57cec5SDimitry Andric   case Custom:
69*0b57cec5SDimitry Andric     OS << "Custom";
70*0b57cec5SDimitry Andric     break;
71*0b57cec5SDimitry Andric   case Unsupported:
72*0b57cec5SDimitry Andric     OS << "Unsupported";
73*0b57cec5SDimitry Andric     break;
74*0b57cec5SDimitry Andric   case NotFound:
75*0b57cec5SDimitry Andric     OS << "NotFound";
76*0b57cec5SDimitry Andric     break;
77*0b57cec5SDimitry Andric   case UseLegacyRules:
78*0b57cec5SDimitry Andric     OS << "UseLegacyRules";
79*0b57cec5SDimitry Andric     break;
80*0b57cec5SDimitry Andric   }
81*0b57cec5SDimitry Andric   return OS;
82*0b57cec5SDimitry Andric }
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric raw_ostream &LegalityQuery::print(raw_ostream &OS) const {
85*0b57cec5SDimitry Andric   OS << Opcode << ", Tys={";
86*0b57cec5SDimitry Andric   for (const auto &Type : Types) {
87*0b57cec5SDimitry Andric     OS << Type << ", ";
88*0b57cec5SDimitry Andric   }
89*0b57cec5SDimitry Andric   OS << "}, Opcode=";
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric   OS << Opcode << ", MMOs={";
92*0b57cec5SDimitry Andric   for (const auto &MMODescr : MMODescrs) {
93*0b57cec5SDimitry Andric     OS << MMODescr.SizeInBits << ", ";
94*0b57cec5SDimitry Andric   }
95*0b57cec5SDimitry Andric   OS << "}";
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric   return OS;
98*0b57cec5SDimitry Andric }
99*0b57cec5SDimitry Andric 
100*0b57cec5SDimitry Andric #ifndef NDEBUG
101*0b57cec5SDimitry Andric // Make sure the rule won't (trivially) loop forever.
102*0b57cec5SDimitry Andric static bool hasNoSimpleLoops(const LegalizeRule &Rule, const LegalityQuery &Q,
103*0b57cec5SDimitry Andric                              const std::pair<unsigned, LLT> &Mutation) {
104*0b57cec5SDimitry Andric   switch (Rule.getAction()) {
105*0b57cec5SDimitry Andric   case Custom:
106*0b57cec5SDimitry Andric   case Lower:
107*0b57cec5SDimitry Andric   case MoreElements:
108*0b57cec5SDimitry Andric   case FewerElements:
109*0b57cec5SDimitry Andric     break;
110*0b57cec5SDimitry Andric   default:
111*0b57cec5SDimitry Andric     return Q.Types[Mutation.first] != Mutation.second;
112*0b57cec5SDimitry Andric   }
113*0b57cec5SDimitry Andric   return true;
114*0b57cec5SDimitry Andric }
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric // Make sure the returned mutation makes sense for the match type.
117*0b57cec5SDimitry Andric static bool mutationIsSane(const LegalizeRule &Rule,
118*0b57cec5SDimitry Andric                            const LegalityQuery &Q,
119*0b57cec5SDimitry Andric                            std::pair<unsigned, LLT> Mutation) {
120*0b57cec5SDimitry Andric   // If the user wants a custom mutation, then we can't really say much about
121*0b57cec5SDimitry Andric   // it. Return true, and trust that they're doing the right thing.
122*0b57cec5SDimitry Andric   if (Rule.getAction() == Custom)
123*0b57cec5SDimitry Andric     return true;
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric   const unsigned TypeIdx = Mutation.first;
126*0b57cec5SDimitry Andric   const LLT OldTy = Q.Types[TypeIdx];
127*0b57cec5SDimitry Andric   const LLT NewTy = Mutation.second;
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric   switch (Rule.getAction()) {
130*0b57cec5SDimitry Andric   case FewerElements:
131*0b57cec5SDimitry Andric   case MoreElements: {
132*0b57cec5SDimitry Andric     if (!OldTy.isVector())
133*0b57cec5SDimitry Andric       return false;
134*0b57cec5SDimitry Andric 
135*0b57cec5SDimitry Andric     if (NewTy.isVector()) {
136*0b57cec5SDimitry Andric       if (Rule.getAction() == FewerElements) {
137*0b57cec5SDimitry Andric         // Make sure the element count really decreased.
138*0b57cec5SDimitry Andric         if (NewTy.getNumElements() >= OldTy.getNumElements())
139*0b57cec5SDimitry Andric           return false;
140*0b57cec5SDimitry Andric       } else {
141*0b57cec5SDimitry Andric         // Make sure the element count really increased.
142*0b57cec5SDimitry Andric         if (NewTy.getNumElements() <= OldTy.getNumElements())
143*0b57cec5SDimitry Andric           return false;
144*0b57cec5SDimitry Andric       }
145*0b57cec5SDimitry Andric     }
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric     // Make sure the element type didn't change.
148*0b57cec5SDimitry Andric     return NewTy.getScalarType() == OldTy.getElementType();
149*0b57cec5SDimitry Andric   }
150*0b57cec5SDimitry Andric   case NarrowScalar:
151*0b57cec5SDimitry Andric   case WidenScalar: {
152*0b57cec5SDimitry Andric     if (OldTy.isVector()) {
153*0b57cec5SDimitry Andric       // Number of elements should not change.
154*0b57cec5SDimitry Andric       if (!NewTy.isVector() || OldTy.getNumElements() != NewTy.getNumElements())
155*0b57cec5SDimitry Andric         return false;
156*0b57cec5SDimitry Andric     } else {
157*0b57cec5SDimitry Andric       // Both types must be vectors
158*0b57cec5SDimitry Andric       if (NewTy.isVector())
159*0b57cec5SDimitry Andric         return false;
160*0b57cec5SDimitry Andric     }
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric     if (Rule.getAction() == NarrowScalar)  {
163*0b57cec5SDimitry Andric       // Make sure the size really decreased.
164*0b57cec5SDimitry Andric       if (NewTy.getScalarSizeInBits() >= OldTy.getScalarSizeInBits())
165*0b57cec5SDimitry Andric         return false;
166*0b57cec5SDimitry Andric     } else {
167*0b57cec5SDimitry Andric       // Make sure the size really increased.
168*0b57cec5SDimitry Andric       if (NewTy.getScalarSizeInBits() <= OldTy.getScalarSizeInBits())
169*0b57cec5SDimitry Andric         return false;
170*0b57cec5SDimitry Andric     }
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric     return true;
173*0b57cec5SDimitry Andric   }
174*0b57cec5SDimitry Andric   default:
175*0b57cec5SDimitry Andric     return true;
176*0b57cec5SDimitry Andric   }
177*0b57cec5SDimitry Andric }
178*0b57cec5SDimitry Andric #endif
179*0b57cec5SDimitry Andric 
180*0b57cec5SDimitry Andric LegalizeActionStep LegalizeRuleSet::apply(const LegalityQuery &Query) const {
181*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Applying legalizer ruleset to: "; Query.print(dbgs());
182*0b57cec5SDimitry Andric              dbgs() << "\n");
183*0b57cec5SDimitry Andric   if (Rules.empty()) {
184*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. fallback to legacy rules (no rules defined)\n");
185*0b57cec5SDimitry Andric     return {LegalizeAction::UseLegacyRules, 0, LLT{}};
186*0b57cec5SDimitry Andric   }
187*0b57cec5SDimitry Andric   for (const LegalizeRule &Rule : Rules) {
188*0b57cec5SDimitry Andric     if (Rule.match(Query)) {
189*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << ".. match\n");
190*0b57cec5SDimitry Andric       std::pair<unsigned, LLT> Mutation = Rule.determineMutation(Query);
191*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << ".. .. " << Rule.getAction() << ", "
192*0b57cec5SDimitry Andric                         << Mutation.first << ", " << Mutation.second << "\n");
193*0b57cec5SDimitry Andric       assert(mutationIsSane(Rule, Query, Mutation) &&
194*0b57cec5SDimitry Andric              "legality mutation invalid for match");
195*0b57cec5SDimitry Andric       assert(hasNoSimpleLoops(Rule, Query, Mutation) && "Simple loop detected");
196*0b57cec5SDimitry Andric       return {Rule.getAction(), Mutation.first, Mutation.second};
197*0b57cec5SDimitry Andric     } else
198*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << ".. no match\n");
199*0b57cec5SDimitry Andric   }
200*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << ".. unsupported\n");
201*0b57cec5SDimitry Andric   return {LegalizeAction::Unsupported, 0, LLT{}};
202*0b57cec5SDimitry Andric }
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric bool LegalizeRuleSet::verifyTypeIdxsCoverage(unsigned NumTypeIdxs) const {
205*0b57cec5SDimitry Andric #ifndef NDEBUG
206*0b57cec5SDimitry Andric   if (Rules.empty()) {
207*0b57cec5SDimitry Andric     LLVM_DEBUG(
208*0b57cec5SDimitry Andric         dbgs() << ".. type index coverage check SKIPPED: no rules defined\n");
209*0b57cec5SDimitry Andric     return true;
210*0b57cec5SDimitry Andric   }
211*0b57cec5SDimitry Andric   const int64_t FirstUncovered = TypeIdxsCovered.find_first_unset();
212*0b57cec5SDimitry Andric   if (FirstUncovered < 0) {
213*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. type index coverage check SKIPPED:"
214*0b57cec5SDimitry Andric                          " user-defined predicate detected\n");
215*0b57cec5SDimitry Andric     return true;
216*0b57cec5SDimitry Andric   }
217*0b57cec5SDimitry Andric   const bool AllCovered = (FirstUncovered >= NumTypeIdxs);
218*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << ".. the first uncovered type index: " << FirstUncovered
219*0b57cec5SDimitry Andric                     << ", " << (AllCovered ? "OK" : "FAIL") << "\n");
220*0b57cec5SDimitry Andric   return AllCovered;
221*0b57cec5SDimitry Andric #else
222*0b57cec5SDimitry Andric   return true;
223*0b57cec5SDimitry Andric #endif
224*0b57cec5SDimitry Andric }
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric LegalizerInfo::LegalizerInfo() : TablesInitialized(false) {
227*0b57cec5SDimitry Andric   // Set defaults.
228*0b57cec5SDimitry Andric   // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the
229*0b57cec5SDimitry Andric   // fundamental load/store Jakob proposed. Once loads & stores are supported.
230*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}});
231*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}});
232*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}});
233*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}});
234*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}});
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}});
237*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}});
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
240*0b57cec5SDimitry Andric       TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall);
241*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
242*0b57cec5SDimitry Andric       TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
243*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
244*0b57cec5SDimitry Andric       TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest);
245*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
246*0b57cec5SDimitry Andric       TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall);
247*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
248*0b57cec5SDimitry Andric       TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall);
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
251*0b57cec5SDimitry Andric       TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise);
252*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
253*0b57cec5SDimitry Andric       TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall);
254*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
255*0b57cec5SDimitry Andric       TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall);
256*0b57cec5SDimitry Andric   setLegalizeScalarToDifferentSizeStrategy(
257*0b57cec5SDimitry Andric       TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall);
258*0b57cec5SDimitry Andric   setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}});
259*0b57cec5SDimitry Andric }
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric void LegalizerInfo::computeTables() {
262*0b57cec5SDimitry Andric   assert(TablesInitialized == false);
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric   for (unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) {
265*0b57cec5SDimitry Andric     const unsigned Opcode = FirstOp + OpcodeIdx;
266*0b57cec5SDimitry Andric     for (unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size();
267*0b57cec5SDimitry Andric          ++TypeIdx) {
268*0b57cec5SDimitry Andric       // 0. Collect information specified through the setAction API, i.e.
269*0b57cec5SDimitry Andric       // for specific bit sizes.
270*0b57cec5SDimitry Andric       // For scalar types:
271*0b57cec5SDimitry Andric       SizeAndActionsVec ScalarSpecifiedActions;
272*0b57cec5SDimitry Andric       // For pointer types:
273*0b57cec5SDimitry Andric       std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions;
274*0b57cec5SDimitry Andric       // For vector types:
275*0b57cec5SDimitry Andric       std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions;
276*0b57cec5SDimitry Andric       for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) {
277*0b57cec5SDimitry Andric         const LLT Type = LLT2Action.first;
278*0b57cec5SDimitry Andric         const LegalizeAction Action = LLT2Action.second;
279*0b57cec5SDimitry Andric 
280*0b57cec5SDimitry Andric         auto SizeAction = std::make_pair(Type.getSizeInBits(), Action);
281*0b57cec5SDimitry Andric         if (Type.isPointer())
282*0b57cec5SDimitry Andric           AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back(
283*0b57cec5SDimitry Andric               SizeAction);
284*0b57cec5SDimitry Andric         else if (Type.isVector())
285*0b57cec5SDimitry Andric           ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()]
286*0b57cec5SDimitry Andric               .push_back(SizeAction);
287*0b57cec5SDimitry Andric         else
288*0b57cec5SDimitry Andric           ScalarSpecifiedActions.push_back(SizeAction);
289*0b57cec5SDimitry Andric       }
290*0b57cec5SDimitry Andric 
291*0b57cec5SDimitry Andric       // 1. Handle scalar types
292*0b57cec5SDimitry Andric       {
293*0b57cec5SDimitry Andric         // Decide how to handle bit sizes for which no explicit specification
294*0b57cec5SDimitry Andric         // was given.
295*0b57cec5SDimitry Andric         SizeChangeStrategy S = &unsupportedForDifferentSizes;
296*0b57cec5SDimitry Andric         if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() &&
297*0b57cec5SDimitry Andric             ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
298*0b57cec5SDimitry Andric           S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx];
299*0b57cec5SDimitry Andric         llvm::sort(ScalarSpecifiedActions);
300*0b57cec5SDimitry Andric         checkPartialSizeAndActionsVector(ScalarSpecifiedActions);
301*0b57cec5SDimitry Andric         setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions));
302*0b57cec5SDimitry Andric       }
303*0b57cec5SDimitry Andric 
304*0b57cec5SDimitry Andric       // 2. Handle pointer types
305*0b57cec5SDimitry Andric       for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) {
306*0b57cec5SDimitry Andric         llvm::sort(PointerSpecifiedActions.second);
307*0b57cec5SDimitry Andric         checkPartialSizeAndActionsVector(PointerSpecifiedActions.second);
308*0b57cec5SDimitry Andric         // For pointer types, we assume that there isn't a meaningfull way
309*0b57cec5SDimitry Andric         // to change the number of bits used in the pointer.
310*0b57cec5SDimitry Andric         setPointerAction(
311*0b57cec5SDimitry Andric             Opcode, TypeIdx, PointerSpecifiedActions.first,
312*0b57cec5SDimitry Andric             unsupportedForDifferentSizes(PointerSpecifiedActions.second));
313*0b57cec5SDimitry Andric       }
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric       // 3. Handle vector types
316*0b57cec5SDimitry Andric       SizeAndActionsVec ElementSizesSeen;
317*0b57cec5SDimitry Andric       for (auto VectorSpecifiedActions : ElemSize2SpecifiedActions) {
318*0b57cec5SDimitry Andric         llvm::sort(VectorSpecifiedActions.second);
319*0b57cec5SDimitry Andric         const uint16_t ElementSize = VectorSpecifiedActions.first;
320*0b57cec5SDimitry Andric         ElementSizesSeen.push_back({ElementSize, Legal});
321*0b57cec5SDimitry Andric         checkPartialSizeAndActionsVector(VectorSpecifiedActions.second);
322*0b57cec5SDimitry Andric         // For vector types, we assume that the best way to adapt the number
323*0b57cec5SDimitry Andric         // of elements is to the next larger number of elements type for which
324*0b57cec5SDimitry Andric         // the vector type is legal, unless there is no such type. In that case,
325*0b57cec5SDimitry Andric         // legalize towards a vector type with a smaller number of elements.
326*0b57cec5SDimitry Andric         SizeAndActionsVec NumElementsActions;
327*0b57cec5SDimitry Andric         for (SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) {
328*0b57cec5SDimitry Andric           assert(BitsizeAndAction.first % ElementSize == 0);
329*0b57cec5SDimitry Andric           const uint16_t NumElements = BitsizeAndAction.first / ElementSize;
330*0b57cec5SDimitry Andric           NumElementsActions.push_back({NumElements, BitsizeAndAction.second});
331*0b57cec5SDimitry Andric         }
332*0b57cec5SDimitry Andric         setVectorNumElementAction(
333*0b57cec5SDimitry Andric             Opcode, TypeIdx, ElementSize,
334*0b57cec5SDimitry Andric             moreToWiderTypesAndLessToWidest(NumElementsActions));
335*0b57cec5SDimitry Andric       }
336*0b57cec5SDimitry Andric       llvm::sort(ElementSizesSeen);
337*0b57cec5SDimitry Andric       SizeChangeStrategy VectorElementSizeChangeStrategy =
338*0b57cec5SDimitry Andric           &unsupportedForDifferentSizes;
339*0b57cec5SDimitry Andric       if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() &&
340*0b57cec5SDimitry Andric           VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
341*0b57cec5SDimitry Andric         VectorElementSizeChangeStrategy =
342*0b57cec5SDimitry Andric             VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx];
343*0b57cec5SDimitry Andric       setScalarInVectorAction(
344*0b57cec5SDimitry Andric           Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen));
345*0b57cec5SDimitry Andric     }
346*0b57cec5SDimitry Andric   }
347*0b57cec5SDimitry Andric 
348*0b57cec5SDimitry Andric   TablesInitialized = true;
349*0b57cec5SDimitry Andric }
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric // FIXME: inefficient implementation for now. Without ComputeValueVTs we're
352*0b57cec5SDimitry Andric // probably going to need specialized lookup structures for various types before
353*0b57cec5SDimitry Andric // we have any hope of doing well with something like <13 x i3>. Even the common
354*0b57cec5SDimitry Andric // cases should do better than what we have now.
355*0b57cec5SDimitry Andric std::pair<LegalizeAction, LLT>
356*0b57cec5SDimitry Andric LegalizerInfo::getAspectAction(const InstrAspect &Aspect) const {
357*0b57cec5SDimitry Andric   assert(TablesInitialized && "backend forgot to call computeTables");
358*0b57cec5SDimitry Andric   // These *have* to be implemented for now, they're the fundamental basis of
359*0b57cec5SDimitry Andric   // how everything else is transformed.
360*0b57cec5SDimitry Andric   if (Aspect.Type.isScalar() || Aspect.Type.isPointer())
361*0b57cec5SDimitry Andric     return findScalarLegalAction(Aspect);
362*0b57cec5SDimitry Andric   assert(Aspect.Type.isVector());
363*0b57cec5SDimitry Andric   return findVectorLegalAction(Aspect);
364*0b57cec5SDimitry Andric }
365*0b57cec5SDimitry Andric 
366*0b57cec5SDimitry Andric /// Helper function to get LLT for the given type index.
367*0b57cec5SDimitry Andric static LLT getTypeFromTypeIdx(const MachineInstr &MI,
368*0b57cec5SDimitry Andric                               const MachineRegisterInfo &MRI, unsigned OpIdx,
369*0b57cec5SDimitry Andric                               unsigned TypeIdx) {
370*0b57cec5SDimitry Andric   assert(TypeIdx < MI.getNumOperands() && "Unexpected TypeIdx");
371*0b57cec5SDimitry Andric   // G_UNMERGE_VALUES has variable number of operands, but there is only
372*0b57cec5SDimitry Andric   // one source type and one destination type as all destinations must be the
373*0b57cec5SDimitry Andric   // same type. So, get the last operand if TypeIdx == 1.
374*0b57cec5SDimitry Andric   if (MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES && TypeIdx == 1)
375*0b57cec5SDimitry Andric     return MRI.getType(MI.getOperand(MI.getNumOperands() - 1).getReg());
376*0b57cec5SDimitry Andric   return MRI.getType(MI.getOperand(OpIdx).getReg());
377*0b57cec5SDimitry Andric }
378*0b57cec5SDimitry Andric 
379*0b57cec5SDimitry Andric unsigned LegalizerInfo::getOpcodeIdxForOpcode(unsigned Opcode) const {
380*0b57cec5SDimitry Andric   assert(Opcode >= FirstOp && Opcode <= LastOp && "Unsupported opcode");
381*0b57cec5SDimitry Andric   return Opcode - FirstOp;
382*0b57cec5SDimitry Andric }
383*0b57cec5SDimitry Andric 
384*0b57cec5SDimitry Andric unsigned LegalizerInfo::getActionDefinitionsIdx(unsigned Opcode) const {
385*0b57cec5SDimitry Andric   unsigned OpcodeIdx = getOpcodeIdxForOpcode(Opcode);
386*0b57cec5SDimitry Andric   if (unsigned Alias = RulesForOpcode[OpcodeIdx].getAlias()) {
387*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. opcode " << Opcode << " is aliased to " << Alias
388*0b57cec5SDimitry Andric                       << "\n");
389*0b57cec5SDimitry Andric     OpcodeIdx = getOpcodeIdxForOpcode(Alias);
390*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. opcode " << Alias << " is aliased to "
391*0b57cec5SDimitry Andric                       << RulesForOpcode[OpcodeIdx].getAlias() << "\n");
392*0b57cec5SDimitry Andric     assert(RulesForOpcode[OpcodeIdx].getAlias() == 0 && "Cannot chain aliases");
393*0b57cec5SDimitry Andric   }
394*0b57cec5SDimitry Andric 
395*0b57cec5SDimitry Andric   return OpcodeIdx;
396*0b57cec5SDimitry Andric }
397*0b57cec5SDimitry Andric 
398*0b57cec5SDimitry Andric const LegalizeRuleSet &
399*0b57cec5SDimitry Andric LegalizerInfo::getActionDefinitions(unsigned Opcode) const {
400*0b57cec5SDimitry Andric   unsigned OpcodeIdx = getActionDefinitionsIdx(Opcode);
401*0b57cec5SDimitry Andric   return RulesForOpcode[OpcodeIdx];
402*0b57cec5SDimitry Andric }
403*0b57cec5SDimitry Andric 
404*0b57cec5SDimitry Andric LegalizeRuleSet &LegalizerInfo::getActionDefinitionsBuilder(unsigned Opcode) {
405*0b57cec5SDimitry Andric   unsigned OpcodeIdx = getActionDefinitionsIdx(Opcode);
406*0b57cec5SDimitry Andric   auto &Result = RulesForOpcode[OpcodeIdx];
407*0b57cec5SDimitry Andric   assert(!Result.isAliasedByAnother() && "Modifying this opcode will modify aliases");
408*0b57cec5SDimitry Andric   return Result;
409*0b57cec5SDimitry Andric }
410*0b57cec5SDimitry Andric 
411*0b57cec5SDimitry Andric LegalizeRuleSet &LegalizerInfo::getActionDefinitionsBuilder(
412*0b57cec5SDimitry Andric     std::initializer_list<unsigned> Opcodes) {
413*0b57cec5SDimitry Andric   unsigned Representative = *Opcodes.begin();
414*0b57cec5SDimitry Andric 
415*0b57cec5SDimitry Andric   assert(!empty(Opcodes) && Opcodes.begin() + 1 != Opcodes.end() &&
416*0b57cec5SDimitry Andric          "Initializer list must have at least two opcodes");
417*0b57cec5SDimitry Andric 
418*0b57cec5SDimitry Andric   for (auto I = Opcodes.begin() + 1, E = Opcodes.end(); I != E; ++I)
419*0b57cec5SDimitry Andric     aliasActionDefinitions(Representative, *I);
420*0b57cec5SDimitry Andric 
421*0b57cec5SDimitry Andric   auto &Return = getActionDefinitionsBuilder(Representative);
422*0b57cec5SDimitry Andric   Return.setIsAliasedByAnother();
423*0b57cec5SDimitry Andric   return Return;
424*0b57cec5SDimitry Andric }
425*0b57cec5SDimitry Andric 
426*0b57cec5SDimitry Andric void LegalizerInfo::aliasActionDefinitions(unsigned OpcodeTo,
427*0b57cec5SDimitry Andric                                            unsigned OpcodeFrom) {
428*0b57cec5SDimitry Andric   assert(OpcodeTo != OpcodeFrom && "Cannot alias to self");
429*0b57cec5SDimitry Andric   assert(OpcodeTo >= FirstOp && OpcodeTo <= LastOp && "Unsupported opcode");
430*0b57cec5SDimitry Andric   const unsigned OpcodeFromIdx = getOpcodeIdxForOpcode(OpcodeFrom);
431*0b57cec5SDimitry Andric   RulesForOpcode[OpcodeFromIdx].aliasTo(OpcodeTo);
432*0b57cec5SDimitry Andric }
433*0b57cec5SDimitry Andric 
434*0b57cec5SDimitry Andric LegalizeActionStep
435*0b57cec5SDimitry Andric LegalizerInfo::getAction(const LegalityQuery &Query) const {
436*0b57cec5SDimitry Andric   LegalizeActionStep Step = getActionDefinitions(Query.Opcode).apply(Query);
437*0b57cec5SDimitry Andric   if (Step.Action != LegalizeAction::UseLegacyRules) {
438*0b57cec5SDimitry Andric     return Step;
439*0b57cec5SDimitry Andric   }
440*0b57cec5SDimitry Andric 
441*0b57cec5SDimitry Andric   for (unsigned i = 0; i < Query.Types.size(); ++i) {
442*0b57cec5SDimitry Andric     auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]});
443*0b57cec5SDimitry Andric     if (Action.first != Legal) {
444*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Action="
445*0b57cec5SDimitry Andric                         << Action.first << ", " << Action.second << "\n");
446*0b57cec5SDimitry Andric       return {Action.first, i, Action.second};
447*0b57cec5SDimitry Andric     } else
448*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Legal\n");
449*0b57cec5SDimitry Andric   }
450*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << ".. (legacy) Legal\n");
451*0b57cec5SDimitry Andric   return {Legal, 0, LLT{}};
452*0b57cec5SDimitry Andric }
453*0b57cec5SDimitry Andric 
454*0b57cec5SDimitry Andric LegalizeActionStep
455*0b57cec5SDimitry Andric LegalizerInfo::getAction(const MachineInstr &MI,
456*0b57cec5SDimitry Andric                          const MachineRegisterInfo &MRI) const {
457*0b57cec5SDimitry Andric   SmallVector<LLT, 2> Types;
458*0b57cec5SDimitry Andric   SmallBitVector SeenTypes(8);
459*0b57cec5SDimitry Andric   const MCOperandInfo *OpInfo = MI.getDesc().OpInfo;
460*0b57cec5SDimitry Andric   // FIXME: probably we'll need to cache the results here somehow?
461*0b57cec5SDimitry Andric   for (unsigned i = 0; i < MI.getDesc().getNumOperands(); ++i) {
462*0b57cec5SDimitry Andric     if (!OpInfo[i].isGenericType())
463*0b57cec5SDimitry Andric       continue;
464*0b57cec5SDimitry Andric 
465*0b57cec5SDimitry Andric     // We must only record actions once for each TypeIdx; otherwise we'd
466*0b57cec5SDimitry Andric     // try to legalize operands multiple times down the line.
467*0b57cec5SDimitry Andric     unsigned TypeIdx = OpInfo[i].getGenericTypeIndex();
468*0b57cec5SDimitry Andric     if (SeenTypes[TypeIdx])
469*0b57cec5SDimitry Andric       continue;
470*0b57cec5SDimitry Andric 
471*0b57cec5SDimitry Andric     SeenTypes.set(TypeIdx);
472*0b57cec5SDimitry Andric 
473*0b57cec5SDimitry Andric     LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx);
474*0b57cec5SDimitry Andric     Types.push_back(Ty);
475*0b57cec5SDimitry Andric   }
476*0b57cec5SDimitry Andric 
477*0b57cec5SDimitry Andric   SmallVector<LegalityQuery::MemDesc, 2> MemDescrs;
478*0b57cec5SDimitry Andric   for (const auto &MMO : MI.memoperands())
479*0b57cec5SDimitry Andric     MemDescrs.push_back({8 * MMO->getSize() /* in bits */,
480*0b57cec5SDimitry Andric                          8 * MMO->getAlignment(),
481*0b57cec5SDimitry Andric                          MMO->getOrdering()});
482*0b57cec5SDimitry Andric 
483*0b57cec5SDimitry Andric   return getAction({MI.getOpcode(), Types, MemDescrs});
484*0b57cec5SDimitry Andric }
485*0b57cec5SDimitry Andric 
486*0b57cec5SDimitry Andric bool LegalizerInfo::isLegal(const MachineInstr &MI,
487*0b57cec5SDimitry Andric                             const MachineRegisterInfo &MRI) const {
488*0b57cec5SDimitry Andric   return getAction(MI, MRI).Action == Legal;
489*0b57cec5SDimitry Andric }
490*0b57cec5SDimitry Andric 
491*0b57cec5SDimitry Andric bool LegalizerInfo::isLegalOrCustom(const MachineInstr &MI,
492*0b57cec5SDimitry Andric                                     const MachineRegisterInfo &MRI) const {
493*0b57cec5SDimitry Andric   auto Action = getAction(MI, MRI).Action;
494*0b57cec5SDimitry Andric   // If the action is custom, it may not necessarily modify the instruction,
495*0b57cec5SDimitry Andric   // so we have to assume it's legal.
496*0b57cec5SDimitry Andric   return Action == Legal || Action == Custom;
497*0b57cec5SDimitry Andric }
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric bool LegalizerInfo::legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI,
500*0b57cec5SDimitry Andric                                    MachineIRBuilder &MIRBuilder,
501*0b57cec5SDimitry Andric                                    GISelChangeObserver &Observer) const {
502*0b57cec5SDimitry Andric   return false;
503*0b57cec5SDimitry Andric }
504*0b57cec5SDimitry Andric 
505*0b57cec5SDimitry Andric LegalizerInfo::SizeAndActionsVec
506*0b57cec5SDimitry Andric LegalizerInfo::increaseToLargerTypesAndDecreaseToLargest(
507*0b57cec5SDimitry Andric     const SizeAndActionsVec &v, LegalizeAction IncreaseAction,
508*0b57cec5SDimitry Andric     LegalizeAction DecreaseAction) {
509*0b57cec5SDimitry Andric   SizeAndActionsVec result;
510*0b57cec5SDimitry Andric   unsigned LargestSizeSoFar = 0;
511*0b57cec5SDimitry Andric   if (v.size() >= 1 && v[0].first != 1)
512*0b57cec5SDimitry Andric     result.push_back({1, IncreaseAction});
513*0b57cec5SDimitry Andric   for (size_t i = 0; i < v.size(); ++i) {
514*0b57cec5SDimitry Andric     result.push_back(v[i]);
515*0b57cec5SDimitry Andric     LargestSizeSoFar = v[i].first;
516*0b57cec5SDimitry Andric     if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) {
517*0b57cec5SDimitry Andric       result.push_back({LargestSizeSoFar + 1, IncreaseAction});
518*0b57cec5SDimitry Andric       LargestSizeSoFar = v[i].first + 1;
519*0b57cec5SDimitry Andric     }
520*0b57cec5SDimitry Andric   }
521*0b57cec5SDimitry Andric   result.push_back({LargestSizeSoFar + 1, DecreaseAction});
522*0b57cec5SDimitry Andric   return result;
523*0b57cec5SDimitry Andric }
524*0b57cec5SDimitry Andric 
525*0b57cec5SDimitry Andric LegalizerInfo::SizeAndActionsVec
526*0b57cec5SDimitry Andric LegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest(
527*0b57cec5SDimitry Andric     const SizeAndActionsVec &v, LegalizeAction DecreaseAction,
528*0b57cec5SDimitry Andric     LegalizeAction IncreaseAction) {
529*0b57cec5SDimitry Andric   SizeAndActionsVec result;
530*0b57cec5SDimitry Andric   if (v.size() == 0 || v[0].first != 1)
531*0b57cec5SDimitry Andric     result.push_back({1, IncreaseAction});
532*0b57cec5SDimitry Andric   for (size_t i = 0; i < v.size(); ++i) {
533*0b57cec5SDimitry Andric     result.push_back(v[i]);
534*0b57cec5SDimitry Andric     if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) {
535*0b57cec5SDimitry Andric       result.push_back({v[i].first + 1, DecreaseAction});
536*0b57cec5SDimitry Andric     }
537*0b57cec5SDimitry Andric   }
538*0b57cec5SDimitry Andric   return result;
539*0b57cec5SDimitry Andric }
540*0b57cec5SDimitry Andric 
541*0b57cec5SDimitry Andric LegalizerInfo::SizeAndAction
542*0b57cec5SDimitry Andric LegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) {
543*0b57cec5SDimitry Andric   assert(Size >= 1);
544*0b57cec5SDimitry Andric   // Find the last element in Vec that has a bitsize equal to or smaller than
545*0b57cec5SDimitry Andric   // the requested bit size.
546*0b57cec5SDimitry Andric   // That is the element just before the first element that is bigger than Size.
547*0b57cec5SDimitry Andric   auto It = partition_point(
548*0b57cec5SDimitry Andric       Vec, [=](const SizeAndAction &A) { return A.first <= Size; });
549*0b57cec5SDimitry Andric   assert(It != Vec.begin() && "Does Vec not start with size 1?");
550*0b57cec5SDimitry Andric   int VecIdx = It - Vec.begin() - 1;
551*0b57cec5SDimitry Andric 
552*0b57cec5SDimitry Andric   LegalizeAction Action = Vec[VecIdx].second;
553*0b57cec5SDimitry Andric   switch (Action) {
554*0b57cec5SDimitry Andric   case Legal:
555*0b57cec5SDimitry Andric   case Lower:
556*0b57cec5SDimitry Andric   case Libcall:
557*0b57cec5SDimitry Andric   case Custom:
558*0b57cec5SDimitry Andric     return {Size, Action};
559*0b57cec5SDimitry Andric   case FewerElements:
560*0b57cec5SDimitry Andric     // FIXME: is this special case still needed and correct?
561*0b57cec5SDimitry Andric     // Special case for scalarization:
562*0b57cec5SDimitry Andric     if (Vec == SizeAndActionsVec({{1, FewerElements}}))
563*0b57cec5SDimitry Andric       return {1, FewerElements};
564*0b57cec5SDimitry Andric     LLVM_FALLTHROUGH;
565*0b57cec5SDimitry Andric   case NarrowScalar: {
566*0b57cec5SDimitry Andric     // The following needs to be a loop, as for now, we do allow needing to
567*0b57cec5SDimitry Andric     // go over "Unsupported" bit sizes before finding a legalizable bit size.
568*0b57cec5SDimitry Andric     // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8,
569*0b57cec5SDimitry Andric     // we need to iterate over s9, and then to s32 to return (s32, Legal).
570*0b57cec5SDimitry Andric     // If we want to get rid of the below loop, we should have stronger asserts
571*0b57cec5SDimitry Andric     // when building the SizeAndActionsVecs, probably not allowing
572*0b57cec5SDimitry Andric     // "Unsupported" unless at the ends of the vector.
573*0b57cec5SDimitry Andric     for (int i = VecIdx - 1; i >= 0; --i)
574*0b57cec5SDimitry Andric       if (!needsLegalizingToDifferentSize(Vec[i].second) &&
575*0b57cec5SDimitry Andric           Vec[i].second != Unsupported)
576*0b57cec5SDimitry Andric         return {Vec[i].first, Action};
577*0b57cec5SDimitry Andric     llvm_unreachable("");
578*0b57cec5SDimitry Andric   }
579*0b57cec5SDimitry Andric   case WidenScalar:
580*0b57cec5SDimitry Andric   case MoreElements: {
581*0b57cec5SDimitry Andric     // See above, the following needs to be a loop, at least for now.
582*0b57cec5SDimitry Andric     for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i)
583*0b57cec5SDimitry Andric       if (!needsLegalizingToDifferentSize(Vec[i].second) &&
584*0b57cec5SDimitry Andric           Vec[i].second != Unsupported)
585*0b57cec5SDimitry Andric         return {Vec[i].first, Action};
586*0b57cec5SDimitry Andric     llvm_unreachable("");
587*0b57cec5SDimitry Andric   }
588*0b57cec5SDimitry Andric   case Unsupported:
589*0b57cec5SDimitry Andric     return {Size, Unsupported};
590*0b57cec5SDimitry Andric   case NotFound:
591*0b57cec5SDimitry Andric   case UseLegacyRules:
592*0b57cec5SDimitry Andric     llvm_unreachable("NotFound");
593*0b57cec5SDimitry Andric   }
594*0b57cec5SDimitry Andric   llvm_unreachable("Action has an unknown enum value");
595*0b57cec5SDimitry Andric }
596*0b57cec5SDimitry Andric 
597*0b57cec5SDimitry Andric std::pair<LegalizeAction, LLT>
598*0b57cec5SDimitry Andric LegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const {
599*0b57cec5SDimitry Andric   assert(Aspect.Type.isScalar() || Aspect.Type.isPointer());
600*0b57cec5SDimitry Andric   if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
601*0b57cec5SDimitry Andric     return {NotFound, LLT()};
602*0b57cec5SDimitry Andric   const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode);
603*0b57cec5SDimitry Andric   if (Aspect.Type.isPointer() &&
604*0b57cec5SDimitry Andric       AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) ==
605*0b57cec5SDimitry Andric           AddrSpace2PointerActions[OpcodeIdx].end()) {
606*0b57cec5SDimitry Andric     return {NotFound, LLT()};
607*0b57cec5SDimitry Andric   }
608*0b57cec5SDimitry Andric   const SmallVector<SizeAndActionsVec, 1> &Actions =
609*0b57cec5SDimitry Andric       Aspect.Type.isPointer()
610*0b57cec5SDimitry Andric           ? AddrSpace2PointerActions[OpcodeIdx]
611*0b57cec5SDimitry Andric                 .find(Aspect.Type.getAddressSpace())
612*0b57cec5SDimitry Andric                 ->second
613*0b57cec5SDimitry Andric           : ScalarActions[OpcodeIdx];
614*0b57cec5SDimitry Andric   if (Aspect.Idx >= Actions.size())
615*0b57cec5SDimitry Andric     return {NotFound, LLT()};
616*0b57cec5SDimitry Andric   const SizeAndActionsVec &Vec = Actions[Aspect.Idx];
617*0b57cec5SDimitry Andric   // FIXME: speed up this search, e.g. by using a results cache for repeated
618*0b57cec5SDimitry Andric   // queries?
619*0b57cec5SDimitry Andric   auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits());
620*0b57cec5SDimitry Andric   return {SizeAndAction.second,
621*0b57cec5SDimitry Andric           Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first)
622*0b57cec5SDimitry Andric                                  : LLT::pointer(Aspect.Type.getAddressSpace(),
623*0b57cec5SDimitry Andric                                                 SizeAndAction.first)};
624*0b57cec5SDimitry Andric }
625*0b57cec5SDimitry Andric 
626*0b57cec5SDimitry Andric std::pair<LegalizeAction, LLT>
627*0b57cec5SDimitry Andric LegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const {
628*0b57cec5SDimitry Andric   assert(Aspect.Type.isVector());
629*0b57cec5SDimitry Andric   // First legalize the vector element size, then legalize the number of
630*0b57cec5SDimitry Andric   // lanes in the vector.
631*0b57cec5SDimitry Andric   if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
632*0b57cec5SDimitry Andric     return {NotFound, Aspect.Type};
633*0b57cec5SDimitry Andric   const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode);
634*0b57cec5SDimitry Andric   const unsigned TypeIdx = Aspect.Idx;
635*0b57cec5SDimitry Andric   if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size())
636*0b57cec5SDimitry Andric     return {NotFound, Aspect.Type};
637*0b57cec5SDimitry Andric   const SizeAndActionsVec &ElemSizeVec =
638*0b57cec5SDimitry Andric       ScalarInVectorActions[OpcodeIdx][TypeIdx];
639*0b57cec5SDimitry Andric 
640*0b57cec5SDimitry Andric   LLT IntermediateType;
641*0b57cec5SDimitry Andric   auto ElementSizeAndAction =
642*0b57cec5SDimitry Andric       findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits());
643*0b57cec5SDimitry Andric   IntermediateType =
644*0b57cec5SDimitry Andric       LLT::vector(Aspect.Type.getNumElements(), ElementSizeAndAction.first);
645*0b57cec5SDimitry Andric   if (ElementSizeAndAction.second != Legal)
646*0b57cec5SDimitry Andric     return {ElementSizeAndAction.second, IntermediateType};
647*0b57cec5SDimitry Andric 
648*0b57cec5SDimitry Andric   auto i = NumElements2Actions[OpcodeIdx].find(
649*0b57cec5SDimitry Andric       IntermediateType.getScalarSizeInBits());
650*0b57cec5SDimitry Andric   if (i == NumElements2Actions[OpcodeIdx].end()) {
651*0b57cec5SDimitry Andric     return {NotFound, IntermediateType};
652*0b57cec5SDimitry Andric   }
653*0b57cec5SDimitry Andric   const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx];
654*0b57cec5SDimitry Andric   auto NumElementsAndAction =
655*0b57cec5SDimitry Andric       findAction(NumElementsVec, IntermediateType.getNumElements());
656*0b57cec5SDimitry Andric   return {NumElementsAndAction.second,
657*0b57cec5SDimitry Andric           LLT::vector(NumElementsAndAction.first,
658*0b57cec5SDimitry Andric                       IntermediateType.getScalarSizeInBits())};
659*0b57cec5SDimitry Andric }
660*0b57cec5SDimitry Andric 
661*0b57cec5SDimitry Andric bool LegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
662*0b57cec5SDimitry Andric                                       MachineRegisterInfo &MRI,
663*0b57cec5SDimitry Andric                                       MachineIRBuilder &MIRBuilder) const {
664*0b57cec5SDimitry Andric   return true;
665*0b57cec5SDimitry Andric }
666*0b57cec5SDimitry Andric 
667*0b57cec5SDimitry Andric /// \pre Type indices of every opcode form a dense set starting from 0.
668*0b57cec5SDimitry Andric void LegalizerInfo::verify(const MCInstrInfo &MII) const {
669*0b57cec5SDimitry Andric #ifndef NDEBUG
670*0b57cec5SDimitry Andric   std::vector<unsigned> FailedOpcodes;
671*0b57cec5SDimitry Andric   for (unsigned Opcode = FirstOp; Opcode <= LastOp; ++Opcode) {
672*0b57cec5SDimitry Andric     const MCInstrDesc &MCID = MII.get(Opcode);
673*0b57cec5SDimitry Andric     const unsigned NumTypeIdxs = std::accumulate(
674*0b57cec5SDimitry Andric         MCID.opInfo_begin(), MCID.opInfo_end(), 0U,
675*0b57cec5SDimitry Andric         [](unsigned Acc, const MCOperandInfo &OpInfo) {
676*0b57cec5SDimitry Andric           return OpInfo.isGenericType()
677*0b57cec5SDimitry Andric                      ? std::max(OpInfo.getGenericTypeIndex() + 1U, Acc)
678*0b57cec5SDimitry Andric                      : Acc;
679*0b57cec5SDimitry Andric         });
680*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << MII.getName(Opcode) << " (opcode " << Opcode
681*0b57cec5SDimitry Andric                       << "): " << NumTypeIdxs << " type ind"
682*0b57cec5SDimitry Andric                       << (NumTypeIdxs == 1 ? "ex" : "ices") << "\n");
683*0b57cec5SDimitry Andric     const LegalizeRuleSet &RuleSet = getActionDefinitions(Opcode);
684*0b57cec5SDimitry Andric     if (!RuleSet.verifyTypeIdxsCoverage(NumTypeIdxs))
685*0b57cec5SDimitry Andric       FailedOpcodes.push_back(Opcode);
686*0b57cec5SDimitry Andric   }
687*0b57cec5SDimitry Andric   if (!FailedOpcodes.empty()) {
688*0b57cec5SDimitry Andric     errs() << "The following opcodes have ill-defined legalization rules:";
689*0b57cec5SDimitry Andric     for (unsigned Opcode : FailedOpcodes)
690*0b57cec5SDimitry Andric       errs() << " " << MII.getName(Opcode);
691*0b57cec5SDimitry Andric     errs() << "\n";
692*0b57cec5SDimitry Andric 
693*0b57cec5SDimitry Andric     report_fatal_error("ill-defined LegalizerInfo"
694*0b57cec5SDimitry Andric                        ", try -debug-only=legalizer-info for details");
695*0b57cec5SDimitry Andric   }
696*0b57cec5SDimitry Andric #endif
697*0b57cec5SDimitry Andric }
698*0b57cec5SDimitry Andric 
699*0b57cec5SDimitry Andric #ifndef NDEBUG
700*0b57cec5SDimitry Andric // FIXME: This should be in the MachineVerifier, but it can't use the
701*0b57cec5SDimitry Andric // LegalizerInfo as it's currently in the separate GlobalISel library.
702*0b57cec5SDimitry Andric // Note that RegBankSelected property already checked in the verifier
703*0b57cec5SDimitry Andric // has the same layering problem, but we only use inline methods so
704*0b57cec5SDimitry Andric // end up not needing to link against the GlobalISel library.
705*0b57cec5SDimitry Andric const MachineInstr *llvm::machineFunctionIsIllegal(const MachineFunction &MF) {
706*0b57cec5SDimitry Andric   if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo()) {
707*0b57cec5SDimitry Andric     const MachineRegisterInfo &MRI = MF.getRegInfo();
708*0b57cec5SDimitry Andric     for (const MachineBasicBlock &MBB : MF)
709*0b57cec5SDimitry Andric       for (const MachineInstr &MI : MBB)
710*0b57cec5SDimitry Andric         if (isPreISelGenericOpcode(MI.getOpcode()) &&
711*0b57cec5SDimitry Andric             !MLI->isLegalOrCustom(MI, MRI))
712*0b57cec5SDimitry Andric           return &MI;
713*0b57cec5SDimitry Andric   }
714*0b57cec5SDimitry Andric   return nullptr;
715*0b57cec5SDimitry Andric }
716*0b57cec5SDimitry Andric #endif
717