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:
MacroFusionPredicatorEmitter(RecordKeeper & R)72 MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
73
74 void run(raw_ostream &OS);
75 };
76 } // End anonymous namespace.
77
emitMacroFusionDecl(ArrayRef<Record * > Fusions,PredicateExpander & PE,raw_ostream & OS)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
emitMacroFusionImpl(ArrayRef<Record * > Fusions,PredicateExpander & PE,raw_ostream & OS)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("Predicates");
104 bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
105
106 OS << "bool is" << Fusion->getName() << "(\n";
107 OS.indent(4) << "const TargetInstrInfo &TII,\n";
108 OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
109 OS.indent(4) << "const MachineInstr *FirstMI,\n";
110 OS.indent(4) << "const MachineInstr &SecondMI) {\n";
111 OS.indent(2)
112 << "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n";
113
114 emitPredicates(Predicates, IsCommutable, PE, OS);
115
116 OS.indent(2) << "return true;\n";
117 OS << "}\n";
118 }
119
120 OS << "} // end namespace llvm\n";
121 OS << "\n#endif\n";
122 }
123
emitPredicates(ArrayRef<Record * > Predicates,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)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("Target");
130 if (Target->getName() == "first_fusion_target")
131 emitFirstPredicate(Predicate, IsCommutable, PE, OS);
132 else if (Target->getName() == "second_fusion_target")
133 emitSecondPredicate(Predicate, IsCommutable, PE, OS);
134 else if (Target->getName() == "both_fusion_target")
135 emitBothPredicate(Predicate, IsCommutable, PE, OS);
136 else
137 PrintFatalError(Target->getLoc(),
138 "Unsupported 'FusionTarget': " + Target->getName());
139 }
140 }
141
emitFirstPredicate(Record * Predicate,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)142 void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
143 bool IsCommutable,
144 PredicateExpander &PE,
145 raw_ostream &OS) {
146 if (Predicate->isSubClassOf("WildcardPred")) {
147 OS.indent(2) << "if (!FirstMI)\n";
148 OS.indent(2) << " return "
149 << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
150 << ";\n";
151 } else if (Predicate->isSubClassOf("OneUsePred")) {
152 OS.indent(2) << "{\n";
153 OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
154 OS.indent(4)
155 << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
156 OS.indent(4) << " return false;\n";
157 OS.indent(2) << "}\n";
158 } else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
159 OS.indent(2) << "{\n";
160 OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
161 OS.indent(4) << "if (";
162 PE.setNegatePredicate(true);
163 PE.setIndentLevel(3);
164 PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
165 OS << ")\n";
166 OS.indent(4) << " return false;\n";
167 OS.indent(2) << "}\n";
168 } else {
169 PrintFatalError(Predicate->getLoc(),
170 "Unsupported predicate for first instruction: " +
171 Predicate->getType()->getAsString());
172 }
173 }
174
emitSecondPredicate(Record * Predicate,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)175 void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
176 bool IsCommutable,
177 PredicateExpander &PE,
178 raw_ostream &OS) {
179 if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
180 OS.indent(2) << "{\n";
181 OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
182 OS.indent(4) << "if (";
183 PE.setNegatePredicate(true);
184 PE.setIndentLevel(3);
185 PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
186 OS << ")\n";
187 OS.indent(4) << " return false;\n";
188 OS.indent(2) << "}\n";
189 } else if (Predicate->isSubClassOf("SameReg")) {
190 int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
191 int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
192
193 OS.indent(2) << "if (!SecondMI.getOperand(" << FirstOpIdx
194 << ").getReg().isVirtual()) {\n";
195 OS.indent(4) << "if (SecondMI.getOperand(" << FirstOpIdx
196 << ").getReg() != SecondMI.getOperand(" << SecondOpIdx
197 << ").getReg())";
198
199 if (IsCommutable) {
200 OS << " {\n";
201 OS.indent(6) << "if (!SecondMI.getDesc().isCommutable())\n";
202 OS.indent(6) << " return false;\n";
203
204 OS.indent(6)
205 << "unsigned SrcOpIdx1 = " << SecondOpIdx
206 << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
207 OS.indent(6)
208 << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
209 OS.indent(6)
210 << " if (SecondMI.getOperand(" << FirstOpIdx
211 << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
212 OS.indent(6) << " return false;\n";
213 OS.indent(4) << "}\n";
214 } else {
215 OS << "\n";
216 OS.indent(4) << " return false;\n";
217 }
218 OS.indent(2) << "}\n";
219 } else {
220 PrintFatalError(Predicate->getLoc(),
221 "Unsupported predicate for second instruction: " +
222 Predicate->getType()->getAsString());
223 }
224 }
225
emitBothPredicate(Record * Predicate,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)226 void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
227 bool IsCommutable,
228 PredicateExpander &PE,
229 raw_ostream &OS) {
230 if (Predicate->isSubClassOf("FusionPredicateWithCode"))
231 OS << Predicate->getValueAsString("Predicate");
232 else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
233 emitFirstPredicate(Predicate, IsCommutable, PE, OS);
234 emitSecondPredicate(Predicate, IsCommutable, PE, OS);
235 } else if (Predicate->isSubClassOf("TieReg")) {
236 int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
237 int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
238 OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
239 << ").isReg() &&\n";
240 OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx
241 << ").isReg() &&\n";
242 OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx
243 << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
244 << ").getReg()))";
245
246 if (IsCommutable) {
247 OS << " {\n";
248 OS.indent(4) << "if (!SecondMI.getDesc().isCommutable())\n";
249 OS.indent(4) << " return false;\n";
250
251 OS.indent(4)
252 << "unsigned SrcOpIdx1 = " << SecondOpIdx
253 << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
254 OS.indent(4)
255 << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
256 OS.indent(4)
257 << " if (FirstMI->getOperand(" << FirstOpIdx
258 << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
259 OS.indent(4) << " return false;\n";
260 OS.indent(2) << "}";
261 } else {
262 OS << "\n";
263 OS.indent(2) << " return false;";
264 }
265 OS << "\n";
266 } else
267 PrintFatalError(Predicate->getLoc(),
268 "Unsupported predicate for both instruction: " +
269 Predicate->getType()->getAsString());
270 }
271
run(raw_ostream & OS)272 void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
273 // Emit file header.
274 emitSourceFileHeader("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("Fusion");
281 // Sort macro fusions by name.
282 sort(Fusions, 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