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