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 "CodeGenTarget.h"
42 #include "PredicateExpander.h"
43 #include "llvm/ADT/SmallVector.h"
44 #include "llvm/Support/Debug.h"
45 #include "llvm/TableGen/Error.h"
46 #include "llvm/TableGen/Record.h"
47 #include "llvm/TableGen/TableGenBackend.h"
48 #include <set>
49 #include <vector>
50 
51 using namespace llvm;
52 
53 #define DEBUG_TYPE "macro-fusion-predicator"
54 
55 namespace {
56 class MacroFusionPredicatorEmitter {
57   RecordKeeper &Records;
58   CodeGenTarget Target;
59 
60   void emitMacroFusionDecl(std::vector<Record *> Fusions, PredicateExpander &PE,
61                            raw_ostream &OS);
62   void emitMacroFusionImpl(std::vector<Record *> Fusions, PredicateExpander &PE,
63                            raw_ostream &OS);
64   void emitPredicates(std::vector<Record *> &FirstPredicate,
65                       PredicateExpander &PE, raw_ostream &OS);
66   void emitFirstPredicate(Record *SecondPredicate, PredicateExpander &PE,
67                           raw_ostream &OS);
68   void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE,
69                            raw_ostream &OS);
70   void emitBothPredicate(Record *Predicates, PredicateExpander &PE,
71                          raw_ostream &OS);
72 
73 public:
MacroFusionPredicatorEmitter(RecordKeeper & R)74   MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
75 
76   void run(raw_ostream &OS);
77 };
78 } // End anonymous namespace.
79 
emitMacroFusionDecl(std::vector<Record * > Fusions,PredicateExpander & PE,raw_ostream & OS)80 void MacroFusionPredicatorEmitter::emitMacroFusionDecl(
81     std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
82   OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";
83   OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";
84   OS << "namespace llvm {\n";
85 
86   for (Record *Fusion : Fusions) {
87     OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "
88        << "const TargetSubtargetInfo &, "
89        << "const MachineInstr *, "
90        << "const MachineInstr &);\n";
91   }
92 
93   OS << "} // end namespace llvm\n";
94   OS << "\n#endif\n";
95 }
96 
emitMacroFusionImpl(std::vector<Record * > Fusions,PredicateExpander & PE,raw_ostream & OS)97 void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
98     std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
99   OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n";
100   OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
101   OS << "namespace llvm {\n";
102 
103   for (Record *Fusion : Fusions) {
104     std::vector<Record *> Predicates =
105         Fusion->getValueAsListOfDefs("Predicates");
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) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n";
113 
114     emitPredicates(Predicates, 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(std::vector<Record * > & Predicates,PredicateExpander & PE,raw_ostream & OS)124 void MacroFusionPredicatorEmitter::emitPredicates(
125     std::vector<Record *> &Predicates, PredicateExpander &PE, raw_ostream &OS) {
126   for (Record *Predicate : Predicates) {
127     Record *Target = Predicate->getValueAsDef("Target");
128     if (Target->getName() == "first_fusion_target")
129       emitFirstPredicate(Predicate, PE, OS);
130     else if (Target->getName() == "second_fusion_target")
131       emitSecondPredicate(Predicate, PE, OS);
132     else if (Target->getName() == "both_fusion_target")
133       emitBothPredicate(Predicate, PE, OS);
134     else
135       PrintFatalError(Target->getLoc(),
136                       "Unsupported 'FusionTarget': " + Target->getName());
137   }
138 }
139 
emitFirstPredicate(Record * Predicate,PredicateExpander & PE,raw_ostream & OS)140 void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
141                                                       PredicateExpander &PE,
142                                                       raw_ostream &OS) {
143   if (Predicate->isSubClassOf("WildcardPred")) {
144     OS.indent(2) << "if (!FirstMI)\n";
145     OS.indent(2) << "  return "
146                  << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
147                  << ";\n";
148   } else if (Predicate->isSubClassOf("OneUsePred")) {
149     OS.indent(2) << "{\n";
150     OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
151     OS.indent(4)
152         << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
153     OS.indent(4) << "  return false;\n";
154     OS.indent(2) << "}\n";
155   } else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
156     OS.indent(2) << "{\n";
157     OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
158     OS.indent(4) << "if (";
159     PE.setNegatePredicate(true);
160     PE.setIndentLevel(3);
161     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
162     OS << ")\n";
163     OS.indent(4) << "  return false;\n";
164     OS.indent(2) << "}\n";
165   } else {
166     PrintFatalError(Predicate->getLoc(),
167                     "Unsupported predicate for first instruction: " +
168                         Predicate->getType()->getAsString());
169   }
170 }
171 
emitSecondPredicate(Record * Predicate,PredicateExpander & PE,raw_ostream & OS)172 void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
173                                                        PredicateExpander &PE,
174                                                        raw_ostream &OS) {
175   if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
176     OS.indent(2) << "{\n";
177     OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
178     OS.indent(4) << "if (";
179     PE.setNegatePredicate(true);
180     PE.setIndentLevel(3);
181     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
182     OS << ")\n";
183     OS.indent(4) << "  return false;\n";
184     OS.indent(2) << "}\n";
185   } else {
186     PrintFatalError(Predicate->getLoc(),
187                     "Unsupported predicate for second instruction: " +
188                         Predicate->getType()->getAsString());
189   }
190 }
191 
emitBothPredicate(Record * Predicate,PredicateExpander & PE,raw_ostream & OS)192 void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
193                                                      PredicateExpander &PE,
194                                                      raw_ostream &OS) {
195   if (Predicate->isSubClassOf("FusionPredicateWithCode"))
196     OS << Predicate->getValueAsString("Predicate");
197   else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
198     emitFirstPredicate(Predicate, PE, OS);
199     emitSecondPredicate(Predicate, PE, OS);
200   } else if (Predicate->isSubClassOf("TieReg")) {
201     int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
202     int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
203     OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
204                  << ").isReg() &&\n";
205     OS.indent(2) << "      SecondMI.getOperand(" << SecondOpIdx
206                  << ").isReg() &&\n";
207     OS.indent(2) << "      FirstMI->getOperand(" << FirstOpIdx
208                  << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
209                  << ").getReg()))\n";
210     OS.indent(2) << "  return false;\n";
211   } else
212     PrintFatalError(Predicate->getLoc(),
213                     "Unsupported predicate for both instruction: " +
214                         Predicate->getType()->getAsString());
215 }
216 
run(raw_ostream & OS)217 void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
218   // Emit file header.
219   emitSourceFileHeader("Macro Fusion Predicators", OS);
220 
221   PredicateExpander PE(Target.getName());
222   PE.setByRef(false);
223   PE.setExpandForMC(false);
224 
225   std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
226   // Sort macro fusions by name.
227   sort(Fusions, LessRecord());
228   emitMacroFusionDecl(Fusions, PE, OS);
229   OS << "\n";
230   emitMacroFusionImpl(Fusions, PE, OS);
231 }
232 
233 static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
234     X("gen-macro-fusion-pred", "Generate macro fusion predicators.");
235