xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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("Predicates");
105     bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
106 
107     OS << "bool is" << Fusion->getName() << "(\n";
108     OS.indent(4) << "const TargetInstrInfo &TII,\n";
109     OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
110     OS.indent(4) << "const MachineInstr *FirstMI,\n";
111     OS.indent(4) << "const MachineInstr &SecondMI) {\n";
112     OS.indent(2)
113         << "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n";
114 
115     emitPredicates(Predicates, IsCommutable, PE, OS);
116 
117     OS.indent(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("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 
142 void MacroFusionPredicatorEmitter::emitFirstPredicate(const 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("FirstInstHasSameReg")) {
159     int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
160     int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
161 
162     OS.indent(2) << "if (!FirstMI->getOperand(" << FirstOpIdx
163                  << ").getReg().isVirtual()) {\n";
164     OS.indent(4) << "if (FirstMI->getOperand(" << FirstOpIdx
165                  << ").getReg() != FirstMI->getOperand(" << SecondOpIdx
166                  << ").getReg())";
167 
168     if (IsCommutable) {
169       OS << " {\n";
170       OS.indent(6) << "if (!FirstMI->getDesc().isCommutable())\n";
171       OS.indent(6) << "  return false;\n";
172 
173       OS.indent(6)
174           << "unsigned SrcOpIdx1 = " << SecondOpIdx
175           << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
176       OS.indent(6)
177           << "if (TII.findCommutedOpIndices(FirstMI, SrcOpIdx1, SrcOpIdx2))\n";
178       OS.indent(6)
179           << "  if (FirstMI->getOperand(" << FirstOpIdx
180           << ").getReg() != FirstMI->getOperand(SrcOpIdx2).getReg())\n";
181       OS.indent(6) << "    return false;\n";
182       OS.indent(4) << "}\n";
183     } else {
184       OS << "\n";
185       OS.indent(4) << "  return false;\n";
186     }
187     OS.indent(2) << "}\n";
188   } else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
189     OS.indent(2) << "{\n";
190     OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
191     OS.indent(4) << "if (";
192     PE.setNegatePredicate(true);
193     PE.getIndent() = 3;
194     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
195     OS << ")\n";
196     OS.indent(4) << "  return false;\n";
197     OS.indent(2) << "}\n";
198   } else {
199     PrintFatalError(Predicate->getLoc(),
200                     "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("FusionPredicateWithMCInstPredicate")) {
210     OS.indent(2) << "{\n";
211     OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
212     OS.indent(4) << "if (";
213     PE.setNegatePredicate(true);
214     PE.getIndent() = 3;
215     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
216     OS << ")\n";
217     OS.indent(4) << "  return false;\n";
218     OS.indent(2) << "}\n";
219   } else if (Predicate->isSubClassOf("SecondInstHasSameReg")) {
220     int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
221     int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
222 
223     OS.indent(2) << "if (!SecondMI.getOperand(" << FirstOpIdx
224                  << ").getReg().isVirtual()) {\n";
225     OS.indent(4) << "if (SecondMI.getOperand(" << FirstOpIdx
226                  << ").getReg() != SecondMI.getOperand(" << SecondOpIdx
227                  << ").getReg())";
228 
229     if (IsCommutable) {
230       OS << " {\n";
231       OS.indent(6) << "if (!SecondMI.getDesc().isCommutable())\n";
232       OS.indent(6) << "  return false;\n";
233 
234       OS.indent(6)
235           << "unsigned SrcOpIdx1 = " << SecondOpIdx
236           << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
237       OS.indent(6)
238           << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
239       OS.indent(6)
240           << "  if (SecondMI.getOperand(" << FirstOpIdx
241           << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
242       OS.indent(6) << "    return false;\n";
243       OS.indent(4) << "}\n";
244     } else {
245       OS << "\n";
246       OS.indent(4) << "  return false;\n";
247     }
248     OS.indent(2) << "}\n";
249   } else {
250     PrintFatalError(Predicate->getLoc(),
251                     "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("FusionPredicateWithCode"))
261     OS << Predicate->getValueAsString("Predicate");
262   else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
263     emitFirstPredicate(Predicate, IsCommutable, PE, OS);
264     emitSecondPredicate(Predicate, IsCommutable, PE, OS);
265   } else if (Predicate->isSubClassOf("TieReg")) {
266     int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
267     int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
268     OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
269                  << ").isReg() &&\n";
270     OS.indent(2) << "      SecondMI.getOperand(" << SecondOpIdx
271                  << ").isReg() &&\n";
272     OS.indent(2) << "      FirstMI->getOperand(" << FirstOpIdx
273                  << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
274                  << ").getReg()))";
275 
276     if (IsCommutable) {
277       OS << " {\n";
278       OS.indent(4) << "if (!SecondMI.getDesc().isCommutable())\n";
279       OS.indent(4) << "  return false;\n";
280 
281       OS.indent(4)
282           << "unsigned SrcOpIdx1 = " << SecondOpIdx
283           << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
284       OS.indent(4)
285           << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
286       OS.indent(4)
287           << "  if (FirstMI->getOperand(" << FirstOpIdx
288           << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
289       OS.indent(4) << "    return false;\n";
290       OS.indent(2) << "}";
291     } else {
292       OS << "\n";
293       OS.indent(2) << "  return false;";
294     }
295     OS << "\n";
296   } else {
297     PrintFatalError(Predicate->getLoc(),
298                     "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("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("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