xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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