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 | RecordKeeper &Records; |
56 | CodeGenTarget Target; |
57 | |
58 | void emitMacroFusionDecl(ArrayRef<Record *> Fusions, PredicateExpander &PE, |
59 | raw_ostream &OS); |
60 | void emitMacroFusionImpl(ArrayRef<Record *> Fusions, PredicateExpander &PE, |
61 | raw_ostream &OS); |
62 | void emitPredicates(ArrayRef<Record *> FirstPredicate, bool IsCommutable, |
63 | PredicateExpander &PE, raw_ostream &OS); |
64 | void emitFirstPredicate(Record *SecondPredicate, bool IsCommutable, |
65 | PredicateExpander &PE, raw_ostream &OS); |
66 | void emitSecondPredicate(Record *SecondPredicate, bool IsCommutable, |
67 | PredicateExpander &PE, raw_ostream &OS); |
68 | void emitBothPredicate(Record *Predicates, bool IsCommutable, |
69 | PredicateExpander &PE, raw_ostream &OS); |
70 | |
71 | public: |
72 | MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {} |
73 | |
74 | void run(raw_ostream &OS); |
75 | }; |
76 | } // End anonymous namespace. |
77 | |
78 | void MacroFusionPredicatorEmitter::emitMacroFusionDecl( |
79 | ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { |
80 | OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n" ; |
81 | OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n" ; |
82 | OS << "namespace llvm {\n" ; |
83 | |
84 | for (Record *Fusion : Fusions) { |
85 | OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, " |
86 | << "const TargetSubtargetInfo &, " |
87 | << "const MachineInstr *, " |
88 | << "const MachineInstr &);\n" ; |
89 | } |
90 | |
91 | OS << "} // end namespace llvm\n" ; |
92 | OS << "\n#endif\n" ; |
93 | } |
94 | |
95 | void MacroFusionPredicatorEmitter::emitMacroFusionImpl( |
96 | ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { |
97 | OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n" ; |
98 | OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n" ; |
99 | OS << "namespace llvm {\n" ; |
100 | |
101 | for (Record *Fusion : Fusions) { |
102 | std::vector<Record *> Predicates = |
103 | Fusion->getValueAsListOfDefs(FieldName: "Predicates" ); |
104 | bool IsCommutable = Fusion->getValueAsBit(FieldName: "IsCommutable" ); |
105 | |
106 | OS << "bool is" << Fusion->getName() << "(\n" ; |
107 | OS.indent(NumSpaces: 4) << "const TargetInstrInfo &TII,\n" ; |
108 | OS.indent(NumSpaces: 4) << "const TargetSubtargetInfo &STI,\n" ; |
109 | OS.indent(NumSpaces: 4) << "const MachineInstr *FirstMI,\n" ; |
110 | OS.indent(NumSpaces: 4) << "const MachineInstr &SecondMI) {\n" ; |
111 | OS.indent(NumSpaces: 2) |
112 | << "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n" ; |
113 | |
114 | emitPredicates(FirstPredicate: Predicates, IsCommutable, PE, OS); |
115 | |
116 | OS.indent(NumSpaces: 2) << "return true;\n" ; |
117 | OS << "}\n" ; |
118 | } |
119 | |
120 | OS << "} // end namespace llvm\n" ; |
121 | OS << "\n#endif\n" ; |
122 | } |
123 | |
124 | void MacroFusionPredicatorEmitter::emitPredicates(ArrayRef<Record *> Predicates, |
125 | bool IsCommutable, |
126 | PredicateExpander &PE, |
127 | raw_ostream &OS) { |
128 | for (Record *Predicate : Predicates) { |
129 | 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(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: "FusionPredicateWithMCInstPredicate" )) { |
159 | OS.indent(NumSpaces: 2) << "{\n" ; |
160 | OS.indent(NumSpaces: 4) << "const MachineInstr *MI = FirstMI;\n" ; |
161 | OS.indent(NumSpaces: 4) << "if (" ; |
162 | PE.setNegatePredicate(true); |
163 | PE.setIndentLevel(3); |
164 | PE.expandPredicate(OS, Rec: Predicate->getValueAsDef(FieldName: "Predicate" )); |
165 | OS << ")\n" ; |
166 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
167 | OS.indent(NumSpaces: 2) << "}\n" ; |
168 | } else { |
169 | PrintFatalError(ErrorLoc: Predicate->getLoc(), |
170 | Msg: "Unsupported predicate for first instruction: " + |
171 | Predicate->getType()->getAsString()); |
172 | } |
173 | } |
174 | |
175 | void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate, |
176 | bool IsCommutable, |
177 | PredicateExpander &PE, |
178 | raw_ostream &OS) { |
179 | if (Predicate->isSubClassOf(Name: "FusionPredicateWithMCInstPredicate" )) { |
180 | OS.indent(NumSpaces: 2) << "{\n" ; |
181 | OS.indent(NumSpaces: 4) << "const MachineInstr *MI = &SecondMI;\n" ; |
182 | OS.indent(NumSpaces: 4) << "if (" ; |
183 | PE.setNegatePredicate(true); |
184 | PE.setIndentLevel(3); |
185 | PE.expandPredicate(OS, Rec: Predicate->getValueAsDef(FieldName: "Predicate" )); |
186 | OS << ")\n" ; |
187 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
188 | OS.indent(NumSpaces: 2) << "}\n" ; |
189 | } else if (Predicate->isSubClassOf(Name: "SameReg" )) { |
190 | int FirstOpIdx = Predicate->getValueAsInt(FieldName: "FirstOpIdx" ); |
191 | int SecondOpIdx = Predicate->getValueAsInt(FieldName: "SecondOpIdx" ); |
192 | |
193 | OS.indent(NumSpaces: 2) << "if (!SecondMI.getOperand(" << FirstOpIdx |
194 | << ").getReg().isVirtual()) {\n" ; |
195 | OS.indent(NumSpaces: 4) << "if (SecondMI.getOperand(" << FirstOpIdx |
196 | << ").getReg() != SecondMI.getOperand(" << SecondOpIdx |
197 | << ").getReg())" ; |
198 | |
199 | if (IsCommutable) { |
200 | OS << " {\n" ; |
201 | OS.indent(NumSpaces: 6) << "if (!SecondMI.getDesc().isCommutable())\n" ; |
202 | OS.indent(NumSpaces: 6) << " return false;\n" ; |
203 | |
204 | OS.indent(NumSpaces: 6) |
205 | << "unsigned SrcOpIdx1 = " << SecondOpIdx |
206 | << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n" ; |
207 | OS.indent(NumSpaces: 6) |
208 | << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n" ; |
209 | OS.indent(NumSpaces: 6) |
210 | << " if (SecondMI.getOperand(" << FirstOpIdx |
211 | << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n" ; |
212 | OS.indent(NumSpaces: 6) << " return false;\n" ; |
213 | OS.indent(NumSpaces: 4) << "}\n" ; |
214 | } else { |
215 | OS << "\n" ; |
216 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
217 | } |
218 | OS.indent(NumSpaces: 2) << "}\n" ; |
219 | } else { |
220 | PrintFatalError(ErrorLoc: Predicate->getLoc(), |
221 | Msg: "Unsupported predicate for second instruction: " + |
222 | Predicate->getType()->getAsString()); |
223 | } |
224 | } |
225 | |
226 | void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate, |
227 | bool IsCommutable, |
228 | PredicateExpander &PE, |
229 | raw_ostream &OS) { |
230 | if (Predicate->isSubClassOf(Name: "FusionPredicateWithCode" )) |
231 | OS << Predicate->getValueAsString(FieldName: "Predicate" ); |
232 | else if (Predicate->isSubClassOf(Name: "BothFusionPredicateWithMCInstPredicate" )) { |
233 | emitFirstPredicate(Predicate, IsCommutable, PE, OS); |
234 | emitSecondPredicate(Predicate, IsCommutable, PE, OS); |
235 | } else if (Predicate->isSubClassOf(Name: "TieReg" )) { |
236 | int FirstOpIdx = Predicate->getValueAsInt(FieldName: "FirstOpIdx" ); |
237 | int SecondOpIdx = Predicate->getValueAsInt(FieldName: "SecondOpIdx" ); |
238 | OS.indent(NumSpaces: 2) << "if (!(FirstMI->getOperand(" << FirstOpIdx |
239 | << ").isReg() &&\n" ; |
240 | OS.indent(NumSpaces: 2) << " SecondMI.getOperand(" << SecondOpIdx |
241 | << ").isReg() &&\n" ; |
242 | OS.indent(NumSpaces: 2) << " FirstMI->getOperand(" << FirstOpIdx |
243 | << ").getReg() == SecondMI.getOperand(" << SecondOpIdx |
244 | << ").getReg()))" ; |
245 | |
246 | if (IsCommutable) { |
247 | OS << " {\n" ; |
248 | OS.indent(NumSpaces: 4) << "if (!SecondMI.getDesc().isCommutable())\n" ; |
249 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
250 | |
251 | OS.indent(NumSpaces: 4) |
252 | << "unsigned SrcOpIdx1 = " << SecondOpIdx |
253 | << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n" ; |
254 | OS.indent(NumSpaces: 4) |
255 | << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n" ; |
256 | OS.indent(NumSpaces: 4) |
257 | << " if (FirstMI->getOperand(" << FirstOpIdx |
258 | << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n" ; |
259 | OS.indent(NumSpaces: 4) << " return false;\n" ; |
260 | OS.indent(NumSpaces: 2) << "}" ; |
261 | } else { |
262 | OS << "\n" ; |
263 | OS.indent(NumSpaces: 2) << " return false;" ; |
264 | } |
265 | OS << "\n" ; |
266 | } else |
267 | PrintFatalError(ErrorLoc: Predicate->getLoc(), |
268 | Msg: "Unsupported predicate for both instruction: " + |
269 | Predicate->getType()->getAsString()); |
270 | } |
271 | |
272 | void MacroFusionPredicatorEmitter::run(raw_ostream &OS) { |
273 | // Emit file header. |
274 | emitSourceFileHeader(Desc: "Macro Fusion Predicators" , OS); |
275 | |
276 | PredicateExpander PE(Target.getName()); |
277 | PE.setByRef(false); |
278 | PE.setExpandForMC(false); |
279 | |
280 | std::vector<Record *> Fusions = Records.getAllDerivedDefinitions(ClassName: "Fusion" ); |
281 | // Sort macro fusions by name. |
282 | sort(C&: Fusions, Comp: LessRecord()); |
283 | emitMacroFusionDecl(Fusions, PE, OS); |
284 | OS << "\n" ; |
285 | emitMacroFusionImpl(Fusions, PE, OS); |
286 | } |
287 | |
288 | static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter> |
289 | X("gen-macro-fusion-pred" , "Generate macro fusion predicators." ); |
290 | |