1 | //===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===// |
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 | // MacroFusionPredicatorEmitter implements a TableGen-driven predicators |
10 | // generator for macro-op fusions. |
11 | // |
12 | // This TableGen backend processes `Fusion` definitions and generates |
13 | // predicators for checking if input instructions can be fused. These |
14 | // predicators can used in `MacroFusion` DAG mutation. |
15 | // |
16 | // The generated header file contains two parts: one for predicator |
17 | // declarations and one for predicator implementations. The user can get them |
18 | // by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or |
19 | // `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated |
20 | // header file. |
21 | // |
22 | // The generated predicator will be like: |
23 | // |
24 | // ``` |
25 | // bool isNAME(const TargetInstrInfo &TII, |
26 | // const TargetSubtargetInfo &STI, |
27 | // const MachineInstr *FirstMI, |
28 | // const MachineInstr &SecondMI) { |
29 | // auto &MRI = SecondMI.getMF()->getRegInfo(); |
30 | // /* Predicates */ |
31 | // return true; |
32 | // } |
33 | // ``` |
34 | // |
35 | // The `Predicates` part is generated from a list of `FusionPredicate`, which |
36 | // can be predefined predicates, a raw code string or `MCInstPredicate` defined |
37 | // in TargetInstrPredicate.td. |
38 | // |
39 | //===---------------------------------------------------------------------===// |
40 | |
41 | #include "Common/CodeGenTarget.h" |
42 | #include "Common/PredicateExpander.h" |
43 | #include "llvm/Support/Debug.h" |
44 | #include "llvm/TableGen/Error.h" |
45 | #include "llvm/TableGen/Record.h" |
46 | #include "llvm/TableGen/TableGenBackend.h" |
47 | #include <vector> |
48 | |
49 | using namespace llvm; |
50 | |
51 | #define DEBUG_TYPE "macro-fusion-predicator" |
52 | |
53 | namespace { |
54 | class MacroFusionPredicatorEmitter { |
55 | const RecordKeeper &Records; |
56 | const CodeGenTarget Target; |
57 | |
58 | void emitMacroFusionDecl(ArrayRef<const Record *> Fusions, |
59 | PredicateExpander &PE, raw_ostream &OS); |
60 | void emitMacroFusionImpl(ArrayRef<const Record *> Fusions, |
61 | PredicateExpander &PE, raw_ostream &OS); |
62 | void emitPredicates(ArrayRef<const Record *> FirstPredicate, |
63 | bool IsCommutable, PredicateExpander &PE, |
64 | raw_ostream &OS); |
65 | void emitFirstPredicate(const Record *SecondPredicate, bool IsCommutable, |
66 | PredicateExpander &PE, raw_ostream &OS); |
67 | void emitSecondPredicate(const Record *SecondPredicate, bool IsCommutable, |
68 | PredicateExpander &PE, raw_ostream &OS); |
69 | void emitBothPredicate(const Record *Predicates, bool IsCommutable, |
70 | PredicateExpander &PE, raw_ostream &OS); |
71 | |
72 | public: |
73 | MacroFusionPredicatorEmitter(const RecordKeeper &R) : Records(R), Target(R) {} |
74 | |
75 | void run(raw_ostream &OS); |
76 | }; |
77 | } // End anonymous namespace. |
78 | |
79 | void MacroFusionPredicatorEmitter::emitMacroFusionDecl( |
80 | ArrayRef<const Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { |
81 | OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n" ; |
82 | OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n" ; |
83 | OS << "namespace llvm {\n" ; |
84 | |
85 | for (const Record *Fusion : Fusions) { |
86 | OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, " |
87 | << "const TargetSubtargetInfo &, " |
88 | << "const MachineInstr *, " |
89 | << "const MachineInstr &);\n" ; |
90 | } |
91 | |
92 | OS << "} // end namespace llvm\n" ; |
93 | OS << "\n#endif\n" ; |
94 | } |
95 | |
96 | void MacroFusionPredicatorEmitter::emitMacroFusionImpl( |
97 | ArrayRef<const Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { |
98 | OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n" ; |
99 | OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n" ; |
100 | OS << "namespace llvm {\n" ; |
101 | |
102 | for (const Record *Fusion : Fusions) { |
103 | std::vector<const Record *> Predicates = |
104 | Fusion->getValueAsListOfDefs(FieldName: "Predicates" ); |
105 | bool IsCommutable = Fusion->getValueAsBit(FieldName: "IsCommutable" ); |
106 | |
107 | OS << "bool is" << Fusion->getName() << "(\n" ; |
108 | OS.indent(NumSpaces: 4) << "const TargetInstrInfo &TII,\n" ; |
109 | OS.indent(NumSpaces: 4) << "const TargetSubtargetInfo &STI,\n" ; |
110 | OS.indent(NumSpaces: 4) << "const MachineInstr *FirstMI,\n" ; |
111 | OS.indent(NumSpaces: 4) << "const MachineInstr &SecondMI) {\n" ; |
112 | OS.indent(NumSpaces: 2) |
113 | << "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n" ; |
114 | |
115 | emitPredicates(FirstPredicate: Predicates, IsCommutable, PE, OS); |
116 | |
117 | OS.indent(NumSpaces: 2) << "return true;\n" ; |
118 | OS << "}\n" ; |
119 | } |
120 | |
121 | OS << "} // end namespace llvm\n" ; |
122 | OS << "\n#endif\n" ; |
123 | } |
124 | |
125 | void MacroFusionPredicatorEmitter::emitPredicates( |
126 | ArrayRef<const Record *> Predicates, bool IsCommutable, |
127 | PredicateExpander &PE, raw_ostream &OS) { |
128 | for (const Record *Predicate : Predicates) { |
129 | const Record *Target = Predicate->getValueAsDef(FieldName: "Target" ); |
130 | if (Target->getName() == "first_fusion_target" ) |
131 | emitFirstPredicate(SecondPredicate: Predicate, IsCommutable, PE, OS); |
132 | else if (Target->getName() == "second_fusion_target" ) |
133 | emitSecondPredicate(SecondPredicate: Predicate, IsCommutable, PE, OS); |
134 | else if (Target->getName() == "both_fusion_target" ) |
135 | emitBothPredicate(Predicates: Predicate, IsCommutable, PE, OS); |
136 | else |
137 | PrintFatalError(ErrorLoc: Target->getLoc(), |
138 | Msg: "Unsupported 'FusionTarget': " + Target->getName()); |
139 | } |
140 | } |
141 | |
142 | void MacroFusionPredicatorEmitter::emitFirstPredicate(const Record *Predicate, |
143 | bool IsCommutable, |
144 | PredicateExpander &PE, |
145 | raw_ostream &OS) { |
146 | if (Predicate->isSubClassOf(Name: "WildcardPred" )) { |
147 | OS.indent(NumSpaces: 2) << "if (!FirstMI)\n" ; |
148 | OS.indent(NumSpaces: 2) << " return " |
149 | << (Predicate->getValueAsBit(FieldName: "ReturnValue" ) ? "true" : "false" ) |
150 | << ";\n" ; |
151 | } else if (Predicate->isSubClassOf(Name: "OneUsePred" )) { |
152 | OS.indent(NumSpaces: 2) << "{\n" ; |
153 | OS.indent(NumSpaces: 4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n" ; |
154 | OS.indent(NumSpaces: 4) |
155 | << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n" ; |
156 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
157 | OS.indent(NumSpaces: 2) << "}\n" ; |
158 | } else if (Predicate->isSubClassOf(Name: "FirstInstHasSameReg" )) { |
159 | int FirstOpIdx = Predicate->getValueAsInt(FieldName: "FirstOpIdx" ); |
160 | int SecondOpIdx = Predicate->getValueAsInt(FieldName: "SecondOpIdx" ); |
161 | |
162 | OS.indent(NumSpaces: 2) << "if (!FirstMI->getOperand(" << FirstOpIdx |
163 | << ").getReg().isVirtual()) {\n" ; |
164 | OS.indent(NumSpaces: 4) << "if (FirstMI->getOperand(" << FirstOpIdx |
165 | << ").getReg() != FirstMI->getOperand(" << SecondOpIdx |
166 | << ").getReg())" ; |
167 | |
168 | if (IsCommutable) { |
169 | OS << " {\n" ; |
170 | OS.indent(NumSpaces: 6) << "if (!FirstMI->getDesc().isCommutable())\n" ; |
171 | OS.indent(NumSpaces: 6) << " return false;\n" ; |
172 | |
173 | OS.indent(NumSpaces: 6) |
174 | << "unsigned SrcOpIdx1 = " << SecondOpIdx |
175 | << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n" ; |
176 | OS.indent(NumSpaces: 6) |
177 | << "if (TII.findCommutedOpIndices(FirstMI, SrcOpIdx1, SrcOpIdx2))\n" ; |
178 | OS.indent(NumSpaces: 6) |
179 | << " if (FirstMI->getOperand(" << FirstOpIdx |
180 | << ").getReg() != FirstMI->getOperand(SrcOpIdx2).getReg())\n" ; |
181 | OS.indent(NumSpaces: 6) << " return false;\n" ; |
182 | OS.indent(NumSpaces: 4) << "}\n" ; |
183 | } else { |
184 | OS << "\n" ; |
185 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
186 | } |
187 | OS.indent(NumSpaces: 2) << "}\n" ; |
188 | } else if (Predicate->isSubClassOf(Name: "FusionPredicateWithMCInstPredicate" )) { |
189 | OS.indent(NumSpaces: 2) << "{\n" ; |
190 | OS.indent(NumSpaces: 4) << "const MachineInstr *MI = FirstMI;\n" ; |
191 | OS.indent(NumSpaces: 4) << "if (" ; |
192 | PE.setNegatePredicate(true); |
193 | PE.getIndent() = 3; |
194 | PE.expandPredicate(OS, Rec: Predicate->getValueAsDef(FieldName: "Predicate" )); |
195 | OS << ")\n" ; |
196 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
197 | OS.indent(NumSpaces: 2) << "}\n" ; |
198 | } else { |
199 | PrintFatalError(ErrorLoc: Predicate->getLoc(), |
200 | Msg: "Unsupported predicate for first instruction: " + |
201 | Predicate->getType()->getAsString()); |
202 | } |
203 | } |
204 | |
205 | void MacroFusionPredicatorEmitter::emitSecondPredicate(const Record *Predicate, |
206 | bool IsCommutable, |
207 | PredicateExpander &PE, |
208 | raw_ostream &OS) { |
209 | if (Predicate->isSubClassOf(Name: "FusionPredicateWithMCInstPredicate" )) { |
210 | OS.indent(NumSpaces: 2) << "{\n" ; |
211 | OS.indent(NumSpaces: 4) << "const MachineInstr *MI = &SecondMI;\n" ; |
212 | OS.indent(NumSpaces: 4) << "if (" ; |
213 | PE.setNegatePredicate(true); |
214 | PE.getIndent() = 3; |
215 | PE.expandPredicate(OS, Rec: Predicate->getValueAsDef(FieldName: "Predicate" )); |
216 | OS << ")\n" ; |
217 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
218 | OS.indent(NumSpaces: 2) << "}\n" ; |
219 | } else if (Predicate->isSubClassOf(Name: "SecondInstHasSameReg" )) { |
220 | int FirstOpIdx = Predicate->getValueAsInt(FieldName: "FirstOpIdx" ); |
221 | int SecondOpIdx = Predicate->getValueAsInt(FieldName: "SecondOpIdx" ); |
222 | |
223 | OS.indent(NumSpaces: 2) << "if (!SecondMI.getOperand(" << FirstOpIdx |
224 | << ").getReg().isVirtual()) {\n" ; |
225 | OS.indent(NumSpaces: 4) << "if (SecondMI.getOperand(" << FirstOpIdx |
226 | << ").getReg() != SecondMI.getOperand(" << SecondOpIdx |
227 | << ").getReg())" ; |
228 | |
229 | if (IsCommutable) { |
230 | OS << " {\n" ; |
231 | OS.indent(NumSpaces: 6) << "if (!SecondMI.getDesc().isCommutable())\n" ; |
232 | OS.indent(NumSpaces: 6) << " return false;\n" ; |
233 | |
234 | OS.indent(NumSpaces: 6) |
235 | << "unsigned SrcOpIdx1 = " << SecondOpIdx |
236 | << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n" ; |
237 | OS.indent(NumSpaces: 6) |
238 | << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n" ; |
239 | OS.indent(NumSpaces: 6) |
240 | << " if (SecondMI.getOperand(" << FirstOpIdx |
241 | << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n" ; |
242 | OS.indent(NumSpaces: 6) << " return false;\n" ; |
243 | OS.indent(NumSpaces: 4) << "}\n" ; |
244 | } else { |
245 | OS << "\n" ; |
246 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
247 | } |
248 | OS.indent(NumSpaces: 2) << "}\n" ; |
249 | } else { |
250 | PrintFatalError(ErrorLoc: Predicate->getLoc(), |
251 | Msg: "Unsupported predicate for second instruction: " + |
252 | Predicate->getType()->getAsString()); |
253 | } |
254 | } |
255 | |
256 | void MacroFusionPredicatorEmitter::emitBothPredicate(const Record *Predicate, |
257 | bool IsCommutable, |
258 | PredicateExpander &PE, |
259 | raw_ostream &OS) { |
260 | if (Predicate->isSubClassOf(Name: "FusionPredicateWithCode" )) |
261 | OS << Predicate->getValueAsString(FieldName: "Predicate" ); |
262 | else if (Predicate->isSubClassOf(Name: "BothFusionPredicateWithMCInstPredicate" )) { |
263 | emitFirstPredicate(Predicate, IsCommutable, PE, OS); |
264 | emitSecondPredicate(Predicate, IsCommutable, PE, OS); |
265 | } else if (Predicate->isSubClassOf(Name: "TieReg" )) { |
266 | int FirstOpIdx = Predicate->getValueAsInt(FieldName: "FirstOpIdx" ); |
267 | int SecondOpIdx = Predicate->getValueAsInt(FieldName: "SecondOpIdx" ); |
268 | OS.indent(NumSpaces: 2) << "if (!(FirstMI->getOperand(" << FirstOpIdx |
269 | << ").isReg() &&\n" ; |
270 | OS.indent(NumSpaces: 2) << " SecondMI.getOperand(" << SecondOpIdx |
271 | << ").isReg() &&\n" ; |
272 | OS.indent(NumSpaces: 2) << " FirstMI->getOperand(" << FirstOpIdx |
273 | << ").getReg() == SecondMI.getOperand(" << SecondOpIdx |
274 | << ").getReg()))" ; |
275 | |
276 | if (IsCommutable) { |
277 | OS << " {\n" ; |
278 | OS.indent(NumSpaces: 4) << "if (!SecondMI.getDesc().isCommutable())\n" ; |
279 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
280 | |
281 | OS.indent(NumSpaces: 4) |
282 | << "unsigned SrcOpIdx1 = " << SecondOpIdx |
283 | << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n" ; |
284 | OS.indent(NumSpaces: 4) |
285 | << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n" ; |
286 | OS.indent(NumSpaces: 4) |
287 | << " if (FirstMI->getOperand(" << FirstOpIdx |
288 | << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n" ; |
289 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
290 | OS.indent(NumSpaces: 2) << "}" ; |
291 | } else { |
292 | OS << "\n" ; |
293 | OS.indent(NumSpaces: 2) << " return false;" ; |
294 | } |
295 | OS << "\n" ; |
296 | } else { |
297 | PrintFatalError(ErrorLoc: Predicate->getLoc(), |
298 | Msg: "Unsupported predicate for both instruction: " + |
299 | Predicate->getType()->getAsString()); |
300 | } |
301 | } |
302 | |
303 | void MacroFusionPredicatorEmitter::run(raw_ostream &OS) { |
304 | // Emit file header. |
305 | emitSourceFileHeader(Desc: "Macro Fusion Predicators" , OS); |
306 | |
307 | PredicateExpander PE(Target.getName()); |
308 | PE.setByRef(false); |
309 | PE.setExpandForMC(false); |
310 | |
311 | ArrayRef<const Record *> Fusions = Records.getAllDerivedDefinitions(ClassName: "Fusion" ); |
312 | emitMacroFusionDecl(Fusions, PE, OS); |
313 | OS << "\n" ; |
314 | emitMacroFusionImpl(Fusions, PE, OS); |
315 | } |
316 | |
317 | static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter> |
318 | X("gen-macro-fusion-pred" , "Generate macro fusion predicators." ); |
319 | |