1*0fca6ea1SDimitry Andric //===- GlobalISelMatchTableExecutorEmitter.cpp ----------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric 
9*0fca6ea1SDimitry Andric #include "GlobalISelMatchTableExecutorEmitter.h"
10*0fca6ea1SDimitry Andric #include "GlobalISelMatchTable.h"
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric using namespace llvm;
13*0fca6ea1SDimitry Andric using namespace llvm::gi;
14*0fca6ea1SDimitry Andric 
15*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitSubtargetFeatureBitsetImpl(
16*0fca6ea1SDimitry Andric     raw_ostream &OS, ArrayRef<RuleMatcher> Rules) {
17*0fca6ea1SDimitry Andric   SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
18*0fca6ea1SDimitry Andric                                                            OS, &HwModes);
19*0fca6ea1SDimitry Andric 
20*0fca6ea1SDimitry Andric   // Separate subtarget features by how often they must be recomputed.
21*0fca6ea1SDimitry Andric   SubtargetFeatureInfoMap ModuleFeatures;
22*0fca6ea1SDimitry Andric   std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
23*0fca6ea1SDimitry Andric                std::inserter(ModuleFeatures, ModuleFeatures.end()),
24*0fca6ea1SDimitry Andric                [](const SubtargetFeatureInfoMap::value_type &X) {
25*0fca6ea1SDimitry Andric                  return !X.second.mustRecomputePerFunction();
26*0fca6ea1SDimitry Andric                });
27*0fca6ea1SDimitry Andric   SubtargetFeatureInfoMap FunctionFeatures;
28*0fca6ea1SDimitry Andric   std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
29*0fca6ea1SDimitry Andric                std::inserter(FunctionFeatures, FunctionFeatures.end()),
30*0fca6ea1SDimitry Andric                [](const SubtargetFeatureInfoMap::value_type &X) {
31*0fca6ea1SDimitry Andric                  return X.second.mustRecomputePerFunction();
32*0fca6ea1SDimitry Andric                });
33*0fca6ea1SDimitry Andric 
34*0fca6ea1SDimitry Andric   SubtargetFeatureInfo::emitComputeAvailableFeatures(
35*0fca6ea1SDimitry Andric       getTarget().getName(), getClassName(), "computeAvailableModuleFeatures",
36*0fca6ea1SDimitry Andric       ModuleFeatures, OS, "", &HwModes);
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric   OS << "void " << getClassName()
39*0fca6ea1SDimitry Andric      << "::setupGeneratedPerFunctionState(MachineFunction &MF) {\n"
40*0fca6ea1SDimitry Andric         "  AvailableFunctionFeatures = computeAvailableFunctionFeatures("
41*0fca6ea1SDimitry Andric         "(const "
42*0fca6ea1SDimitry Andric      << getTarget().getName()
43*0fca6ea1SDimitry Andric      << "Subtarget *)&MF.getSubtarget(), &MF);\n"
44*0fca6ea1SDimitry Andric         "}\n";
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric   SubtargetFeatureInfo::emitComputeAvailableFeatures(
47*0fca6ea1SDimitry Andric       getTarget().getName(), getClassName(), "computeAvailableFunctionFeatures",
48*0fca6ea1SDimitry Andric       FunctionFeatures, OS, "const MachineFunction *MF");
49*0fca6ea1SDimitry Andric 
50*0fca6ea1SDimitry Andric   // Emit a table containing the PredicateBitsets objects needed by the matcher
51*0fca6ea1SDimitry Andric   // and an enum for the matcher to reference them with.
52*0fca6ea1SDimitry Andric   std::vector<std::pair<std::vector<Record *>, int>> FeatureBitsets;
53*0fca6ea1SDimitry Andric   FeatureBitsets.reserve(Rules.size());
54*0fca6ea1SDimitry Andric   for (auto &Rule : Rules)
55*0fca6ea1SDimitry Andric     FeatureBitsets.emplace_back(Rule.getRequiredFeatures(),
56*0fca6ea1SDimitry Andric                                 Rule.getHwModeIdx());
57*0fca6ea1SDimitry Andric   llvm::sort(FeatureBitsets,
58*0fca6ea1SDimitry Andric              [&](const std::pair<std::vector<Record *>, int> &A,
59*0fca6ea1SDimitry Andric                  const std::pair<std::vector<Record *>, int> &B) {
60*0fca6ea1SDimitry Andric                if (A.first.size() < B.first.size())
61*0fca6ea1SDimitry Andric                  return true;
62*0fca6ea1SDimitry Andric                if (A.first.size() > B.first.size())
63*0fca6ea1SDimitry Andric                  return false;
64*0fca6ea1SDimitry Andric                for (auto [First, Second] : zip(A.first, B.first)) {
65*0fca6ea1SDimitry Andric                  if (First->getName() < Second->getName())
66*0fca6ea1SDimitry Andric                    return true;
67*0fca6ea1SDimitry Andric                  if (First->getName() > Second->getName())
68*0fca6ea1SDimitry Andric                    return false;
69*0fca6ea1SDimitry Andric                }
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric                return (A.second < B.second);
72*0fca6ea1SDimitry Andric              });
73*0fca6ea1SDimitry Andric   FeatureBitsets.erase(llvm::unique(FeatureBitsets), FeatureBitsets.end());
74*0fca6ea1SDimitry Andric   OS << "// Feature bitsets.\n"
75*0fca6ea1SDimitry Andric      << "enum {\n"
76*0fca6ea1SDimitry Andric      << "  GIFBS_Invalid,\n";
77*0fca6ea1SDimitry Andric   for (const auto &FeatureBitset : FeatureBitsets) {
78*0fca6ea1SDimitry Andric     if (FeatureBitset.first.empty() && FeatureBitset.second < 0)
79*0fca6ea1SDimitry Andric       continue;
80*0fca6ea1SDimitry Andric     OS << "  "
81*0fca6ea1SDimitry Andric        << getNameForFeatureBitset(FeatureBitset.first, FeatureBitset.second)
82*0fca6ea1SDimitry Andric        << ",\n";
83*0fca6ea1SDimitry Andric   }
84*0fca6ea1SDimitry Andric   OS << "};\n"
85*0fca6ea1SDimitry Andric      << "constexpr static PredicateBitset FeatureBitsets[] {\n"
86*0fca6ea1SDimitry Andric      << "  {}, // GIFBS_Invalid\n";
87*0fca6ea1SDimitry Andric   for (const auto &FeatureBitset : FeatureBitsets) {
88*0fca6ea1SDimitry Andric     if (FeatureBitset.first.empty() && FeatureBitset.second < 0)
89*0fca6ea1SDimitry Andric       continue;
90*0fca6ea1SDimitry Andric     OS << "  {";
91*0fca6ea1SDimitry Andric     for (const auto &Feature : FeatureBitset.first) {
92*0fca6ea1SDimitry Andric       const auto &I = SubtargetFeatures.find(Feature);
93*0fca6ea1SDimitry Andric       assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
94*0fca6ea1SDimitry Andric       OS << I->second.getEnumBitName() << ", ";
95*0fca6ea1SDimitry Andric     }
96*0fca6ea1SDimitry Andric     // HwModeIdx
97*0fca6ea1SDimitry Andric     if (FeatureBitset.second >= 0) {
98*0fca6ea1SDimitry Andric       OS << "Feature_HwMode" << FeatureBitset.second << "Bit, ";
99*0fca6ea1SDimitry Andric     }
100*0fca6ea1SDimitry Andric     OS << "},\n";
101*0fca6ea1SDimitry Andric   }
102*0fca6ea1SDimitry Andric   OS << "};\n\n";
103*0fca6ea1SDimitry Andric }
104*0fca6ea1SDimitry Andric 
105*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitComplexPredicates(
106*0fca6ea1SDimitry Andric     raw_ostream &OS, ArrayRef<Record *> ComplexOperandMatchers) {
107*0fca6ea1SDimitry Andric   // Emit complex predicate table and an enum to reference them with.
108*0fca6ea1SDimitry Andric   OS << "// ComplexPattern predicates.\n"
109*0fca6ea1SDimitry Andric      << "enum {\n"
110*0fca6ea1SDimitry Andric      << "  GICP_Invalid,\n";
111*0fca6ea1SDimitry Andric   for (const auto &Record : ComplexOperandMatchers)
112*0fca6ea1SDimitry Andric     OS << "  GICP_" << Record->getName() << ",\n";
113*0fca6ea1SDimitry Andric   OS << "};\n"
114*0fca6ea1SDimitry Andric      << "// See constructor for table contents\n\n";
115*0fca6ea1SDimitry Andric 
116*0fca6ea1SDimitry Andric   OS << getClassName() << "::ComplexMatcherMemFn\n"
117*0fca6ea1SDimitry Andric      << getClassName() << "::ComplexPredicateFns[] = {\n"
118*0fca6ea1SDimitry Andric      << "  nullptr, // GICP_Invalid\n";
119*0fca6ea1SDimitry Andric   for (const auto &Record : ComplexOperandMatchers)
120*0fca6ea1SDimitry Andric     OS << "  &" << getClassName()
121*0fca6ea1SDimitry Andric        << "::" << Record->getValueAsString("MatcherFn") << ", // "
122*0fca6ea1SDimitry Andric        << Record->getName() << "\n";
123*0fca6ea1SDimitry Andric   OS << "};\n\n";
124*0fca6ea1SDimitry Andric }
125*0fca6ea1SDimitry Andric 
126*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitCustomOperandRenderers(
127*0fca6ea1SDimitry Andric     raw_ostream &OS, ArrayRef<StringRef> CustomOperandRenderers) {
128*0fca6ea1SDimitry Andric   OS << "// Custom renderers.\n"
129*0fca6ea1SDimitry Andric      << "enum {\n"
130*0fca6ea1SDimitry Andric      << "  GICR_Invalid,\n";
131*0fca6ea1SDimitry Andric   for (const auto &Fn : CustomOperandRenderers)
132*0fca6ea1SDimitry Andric     OS << "  GICR_" << Fn << ",\n";
133*0fca6ea1SDimitry Andric   OS << "};\n";
134*0fca6ea1SDimitry Andric 
135*0fca6ea1SDimitry Andric   OS << getClassName() << "::CustomRendererFn\n"
136*0fca6ea1SDimitry Andric      << getClassName() << "::CustomRenderers[] = {\n"
137*0fca6ea1SDimitry Andric      << "  nullptr, // GICR_Invalid\n";
138*0fca6ea1SDimitry Andric   for (const auto &Fn : CustomOperandRenderers)
139*0fca6ea1SDimitry Andric     OS << "  &" << getClassName() << "::" << Fn << ",\n";
140*0fca6ea1SDimitry Andric   OS << "};\n\n";
141*0fca6ea1SDimitry Andric }
142*0fca6ea1SDimitry Andric 
143*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitTypeObjects(
144*0fca6ea1SDimitry Andric     raw_ostream &OS, ArrayRef<LLTCodeGen> TypeObjects) {
145*0fca6ea1SDimitry Andric   OS << "// LLT Objects.\n"
146*0fca6ea1SDimitry Andric      << "enum {\n";
147*0fca6ea1SDimitry Andric   for (const auto &TypeObject : TypeObjects) {
148*0fca6ea1SDimitry Andric     OS << "  ";
149*0fca6ea1SDimitry Andric     TypeObject.emitCxxEnumValue(OS);
150*0fca6ea1SDimitry Andric     OS << ",\n";
151*0fca6ea1SDimitry Andric   }
152*0fca6ea1SDimitry Andric   OS << "};\n"
153*0fca6ea1SDimitry Andric      << "const static size_t NumTypeObjects = " << TypeObjects.size() << ";\n"
154*0fca6ea1SDimitry Andric      << "const static LLT TypeObjects[] = {\n";
155*0fca6ea1SDimitry Andric   for (const auto &TypeObject : TypeObjects) {
156*0fca6ea1SDimitry Andric     OS << "  ";
157*0fca6ea1SDimitry Andric     TypeObject.emitCxxConstructorCall(OS);
158*0fca6ea1SDimitry Andric     OS << ",\n";
159*0fca6ea1SDimitry Andric   }
160*0fca6ea1SDimitry Andric   OS << "};\n\n";
161*0fca6ea1SDimitry Andric }
162*0fca6ea1SDimitry Andric 
163*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitMatchTable(
164*0fca6ea1SDimitry Andric     raw_ostream &OS, const MatchTable &Table) {
165*0fca6ea1SDimitry Andric   emitEncodingMacrosDef(OS);
166*0fca6ea1SDimitry Andric   OS << "const uint8_t *" << getClassName() << "::getMatchTable() const {\n";
167*0fca6ea1SDimitry Andric   Table.emitDeclaration(OS);
168*0fca6ea1SDimitry Andric   OS << "  return ";
169*0fca6ea1SDimitry Andric   Table.emitUse(OS);
170*0fca6ea1SDimitry Andric   OS << ";\n}\n";
171*0fca6ea1SDimitry Andric   emitEncodingMacrosUndef(OS);
172*0fca6ea1SDimitry Andric   OS << "\n";
173*0fca6ea1SDimitry Andric }
174*0fca6ea1SDimitry Andric 
175*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitExecutorImpl(
176*0fca6ea1SDimitry Andric     raw_ostream &OS, const MatchTable &Table, ArrayRef<LLTCodeGen> TypeObjects,
177*0fca6ea1SDimitry Andric     ArrayRef<RuleMatcher> Rules, ArrayRef<Record *> ComplexOperandMatchers,
178*0fca6ea1SDimitry Andric     ArrayRef<StringRef> CustomOperandRenderers, StringRef IfDefName) {
179*0fca6ea1SDimitry Andric   OS << "#ifdef " << IfDefName << "\n";
180*0fca6ea1SDimitry Andric   emitTypeObjects(OS, TypeObjects);
181*0fca6ea1SDimitry Andric   emitSubtargetFeatureBitsetImpl(OS, Rules);
182*0fca6ea1SDimitry Andric   emitComplexPredicates(OS, ComplexOperandMatchers);
183*0fca6ea1SDimitry Andric   emitMIPredicateFns(OS);
184*0fca6ea1SDimitry Andric   emitI64ImmPredicateFns(OS);
185*0fca6ea1SDimitry Andric   emitAPFloatImmPredicateFns(OS);
186*0fca6ea1SDimitry Andric   emitAPIntImmPredicateFns(OS);
187*0fca6ea1SDimitry Andric   emitTestSimplePredicate(OS);
188*0fca6ea1SDimitry Andric   emitCustomOperandRenderers(OS, CustomOperandRenderers);
189*0fca6ea1SDimitry Andric   emitAdditionalImpl(OS);
190*0fca6ea1SDimitry Andric   emitRunCustomAction(OS);
191*0fca6ea1SDimitry Andric 
192*0fca6ea1SDimitry Andric   emitMatchTable(OS, Table);
193*0fca6ea1SDimitry Andric 
194*0fca6ea1SDimitry Andric   OS << "#endif // ifdef " << IfDefName << "\n\n";
195*0fca6ea1SDimitry Andric }
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitPredicateBitset(
198*0fca6ea1SDimitry Andric     raw_ostream &OS, StringRef IfDefName) {
199*0fca6ea1SDimitry Andric   unsigned Size = SubtargetFeatures.size() + HwModes.size();
200*0fca6ea1SDimitry Andric   OS << "#ifdef " << IfDefName << "\n"
201*0fca6ea1SDimitry Andric      << "const unsigned MAX_SUBTARGET_PREDICATES = " << Size << ";\n"
202*0fca6ea1SDimitry Andric      << "using PredicateBitset = "
203*0fca6ea1SDimitry Andric         "llvm::Bitset<MAX_SUBTARGET_PREDICATES>;\n"
204*0fca6ea1SDimitry Andric      << "#endif // ifdef " << IfDefName << "\n\n";
205*0fca6ea1SDimitry Andric }
206*0fca6ea1SDimitry Andric 
207*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitTemporariesDecl(
208*0fca6ea1SDimitry Andric     raw_ostream &OS, StringRef IfDefName) {
209*0fca6ea1SDimitry Andric   OS << "#ifdef " << IfDefName << "\n"
210*0fca6ea1SDimitry Andric      << "  mutable MatcherState State;\n"
211*0fca6ea1SDimitry Andric      << "  typedef "
212*0fca6ea1SDimitry Andric         "ComplexRendererFns("
213*0fca6ea1SDimitry Andric      << getClassName() << "::*ComplexMatcherMemFn)(MachineOperand &) const;\n"
214*0fca6ea1SDimitry Andric 
215*0fca6ea1SDimitry Andric      << "  typedef void(" << getClassName()
216*0fca6ea1SDimitry Andric      << "::*CustomRendererFn)(MachineInstrBuilder &, const "
217*0fca6ea1SDimitry Andric         "MachineInstr &, int) "
218*0fca6ea1SDimitry Andric         "const;\n"
219*0fca6ea1SDimitry Andric      << "  const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, "
220*0fca6ea1SDimitry Andric         "CustomRendererFn> "
221*0fca6ea1SDimitry Andric         "ExecInfo;\n"
222*0fca6ea1SDimitry Andric      << "  static " << getClassName()
223*0fca6ea1SDimitry Andric      << "::ComplexMatcherMemFn ComplexPredicateFns[];\n"
224*0fca6ea1SDimitry Andric      << "  static " << getClassName()
225*0fca6ea1SDimitry Andric      << "::CustomRendererFn CustomRenderers[];\n"
226*0fca6ea1SDimitry Andric      << "  bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const "
227*0fca6ea1SDimitry Andric         "override;\n"
228*0fca6ea1SDimitry Andric      << "  bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) "
229*0fca6ea1SDimitry Andric         "const override;\n"
230*0fca6ea1SDimitry Andric      << "  bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat "
231*0fca6ea1SDimitry Andric         "&Imm) const override;\n"
232*0fca6ea1SDimitry Andric      << "  const uint8_t *getMatchTable() const override;\n"
233*0fca6ea1SDimitry Andric      << "  bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI"
234*0fca6ea1SDimitry Andric         ", const MatcherState &State) "
235*0fca6ea1SDimitry Andric         "const override;\n"
236*0fca6ea1SDimitry Andric      << "  bool testSimplePredicate(unsigned PredicateID) const override;\n"
237*0fca6ea1SDimitry Andric      << "  bool runCustomAction(unsigned FnID, const MatcherState &State, "
238*0fca6ea1SDimitry Andric         "NewMIVector &OutMIs) "
239*0fca6ea1SDimitry Andric         "const override;\n"
240*0fca6ea1SDimitry Andric      << "#endif // ifdef " << IfDefName << "\n\n";
241*0fca6ea1SDimitry Andric }
242*0fca6ea1SDimitry Andric 
243*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitTemporariesInit(
244*0fca6ea1SDimitry Andric     raw_ostream &OS, unsigned MaxTemporaries, StringRef IfDefName) {
245*0fca6ea1SDimitry Andric   OS << "#ifdef " << IfDefName << "\n"
246*0fca6ea1SDimitry Andric      << ", State(" << MaxTemporaries << "),\n"
247*0fca6ea1SDimitry Andric      << "ExecInfo(TypeObjects, NumTypeObjects, FeatureBitsets"
248*0fca6ea1SDimitry Andric      << ", ComplexPredicateFns, CustomRenderers)\n"
249*0fca6ea1SDimitry Andric      << "#endif // ifdef " << IfDefName << "\n\n";
250*0fca6ea1SDimitry Andric 
251*0fca6ea1SDimitry Andric   emitAdditionalTemporariesInit(OS);
252*0fca6ea1SDimitry Andric }
253*0fca6ea1SDimitry Andric 
254*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitPredicatesDecl(
255*0fca6ea1SDimitry Andric     raw_ostream &OS, StringRef IfDefName) {
256*0fca6ea1SDimitry Andric   OS << "#ifdef " << IfDefName << "\n"
257*0fca6ea1SDimitry Andric      << "PredicateBitset AvailableModuleFeatures;\n"
258*0fca6ea1SDimitry Andric      << "mutable PredicateBitset AvailableFunctionFeatures;\n"
259*0fca6ea1SDimitry Andric      << "PredicateBitset getAvailableFeatures() const {\n"
260*0fca6ea1SDimitry Andric      << "  return AvailableModuleFeatures | AvailableFunctionFeatures;\n"
261*0fca6ea1SDimitry Andric      << "}\n"
262*0fca6ea1SDimitry Andric      << "PredicateBitset\n"
263*0fca6ea1SDimitry Andric      << "computeAvailableModuleFeatures(const " << getTarget().getName()
264*0fca6ea1SDimitry Andric      << "Subtarget *Subtarget) const;\n"
265*0fca6ea1SDimitry Andric      << "PredicateBitset\n"
266*0fca6ea1SDimitry Andric      << "computeAvailableFunctionFeatures(const " << getTarget().getName()
267*0fca6ea1SDimitry Andric      << "Subtarget *Subtarget,\n"
268*0fca6ea1SDimitry Andric      << "                                 const MachineFunction *MF) const;\n"
269*0fca6ea1SDimitry Andric      << "void setupGeneratedPerFunctionState(MachineFunction &MF) override;\n"
270*0fca6ea1SDimitry Andric      << "#endif // ifdef " << IfDefName << "\n";
271*0fca6ea1SDimitry Andric }
272*0fca6ea1SDimitry Andric 
273*0fca6ea1SDimitry Andric void GlobalISelMatchTableExecutorEmitter::emitPredicatesInit(
274*0fca6ea1SDimitry Andric     raw_ostream &OS, StringRef IfDefName) {
275*0fca6ea1SDimitry Andric   OS << "#ifdef " << IfDefName << "\n"
276*0fca6ea1SDimitry Andric      << "AvailableModuleFeatures(computeAvailableModuleFeatures(&STI)),\n"
277*0fca6ea1SDimitry Andric      << "AvailableFunctionFeatures()\n"
278*0fca6ea1SDimitry Andric      << "#endif // ifdef " << IfDefName << "\n";
279*0fca6ea1SDimitry Andric }
280