xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
1*1db9f3b2SDimitry Andric //===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===//
2*1db9f3b2SDimitry Andric //
3*1db9f3b2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*1db9f3b2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*1db9f3b2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*1db9f3b2SDimitry Andric //
7*1db9f3b2SDimitry Andric //===---------------------------------------------------------------------===//
8*1db9f3b2SDimitry Andric //
9*1db9f3b2SDimitry Andric // MacroFusionPredicatorEmitter implements a TableGen-driven predicators
10*1db9f3b2SDimitry Andric // generator for macro-op fusions.
11*1db9f3b2SDimitry Andric //
12*1db9f3b2SDimitry Andric // This TableGen backend processes `Fusion` definitions and generates
13*1db9f3b2SDimitry Andric // predicators for checking if input instructions can be fused. These
14*1db9f3b2SDimitry Andric // predicators can used in `MacroFusion` DAG mutation.
15*1db9f3b2SDimitry Andric //
16*1db9f3b2SDimitry Andric // The generated header file contains two parts: one for predicator
17*1db9f3b2SDimitry Andric // declarations and one for predicator implementations. The user can get them
18*1db9f3b2SDimitry Andric // by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or
19*1db9f3b2SDimitry Andric // `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated
20*1db9f3b2SDimitry Andric // header file.
21*1db9f3b2SDimitry Andric //
22*1db9f3b2SDimitry Andric // The generated predicator will be like:
23*1db9f3b2SDimitry Andric //
24*1db9f3b2SDimitry Andric // ```
25*1db9f3b2SDimitry Andric // bool isNAME(const TargetInstrInfo &TII,
26*1db9f3b2SDimitry Andric //             const TargetSubtargetInfo &STI,
27*1db9f3b2SDimitry Andric //             const MachineInstr *FirstMI,
28*1db9f3b2SDimitry Andric //             const MachineInstr &SecondMI) {
29*1db9f3b2SDimitry Andric //   auto &MRI = SecondMI.getMF()->getRegInfo();
30*1db9f3b2SDimitry Andric //   /* Predicates */
31*1db9f3b2SDimitry Andric //   return true;
32*1db9f3b2SDimitry Andric // }
33*1db9f3b2SDimitry Andric // ```
34*1db9f3b2SDimitry Andric //
35*1db9f3b2SDimitry Andric // The `Predicates` part is generated from a list of `FusionPredicate`, which
36*1db9f3b2SDimitry Andric // can be predefined predicates, a raw code string or `MCInstPredicate` defined
37*1db9f3b2SDimitry Andric // in TargetInstrPredicate.td.
38*1db9f3b2SDimitry Andric //
39*1db9f3b2SDimitry Andric //===---------------------------------------------------------------------===//
40*1db9f3b2SDimitry Andric 
41*1db9f3b2SDimitry Andric #include "CodeGenTarget.h"
42*1db9f3b2SDimitry Andric #include "PredicateExpander.h"
43*1db9f3b2SDimitry Andric #include "llvm/ADT/SmallVector.h"
44*1db9f3b2SDimitry Andric #include "llvm/Support/Debug.h"
45*1db9f3b2SDimitry Andric #include "llvm/TableGen/Error.h"
46*1db9f3b2SDimitry Andric #include "llvm/TableGen/Record.h"
47*1db9f3b2SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
48*1db9f3b2SDimitry Andric #include <set>
49*1db9f3b2SDimitry Andric #include <vector>
50*1db9f3b2SDimitry Andric 
51*1db9f3b2SDimitry Andric using namespace llvm;
52*1db9f3b2SDimitry Andric 
53*1db9f3b2SDimitry Andric #define DEBUG_TYPE "macro-fusion-predicator"
54*1db9f3b2SDimitry Andric 
55*1db9f3b2SDimitry Andric namespace {
56*1db9f3b2SDimitry Andric class MacroFusionPredicatorEmitter {
57*1db9f3b2SDimitry Andric   RecordKeeper &Records;
58*1db9f3b2SDimitry Andric   CodeGenTarget Target;
59*1db9f3b2SDimitry Andric 
60*1db9f3b2SDimitry Andric   void emitMacroFusionDecl(std::vector<Record *> Fusions, PredicateExpander &PE,
61*1db9f3b2SDimitry Andric                            raw_ostream &OS);
62*1db9f3b2SDimitry Andric   void emitMacroFusionImpl(std::vector<Record *> Fusions, PredicateExpander &PE,
63*1db9f3b2SDimitry Andric                            raw_ostream &OS);
64*1db9f3b2SDimitry Andric   void emitPredicates(std::vector<Record *> &FirstPredicate,
65*1db9f3b2SDimitry Andric                       PredicateExpander &PE, raw_ostream &OS);
66*1db9f3b2SDimitry Andric   void emitFirstPredicate(Record *SecondPredicate, PredicateExpander &PE,
67*1db9f3b2SDimitry Andric                           raw_ostream &OS);
68*1db9f3b2SDimitry Andric   void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE,
69*1db9f3b2SDimitry Andric                            raw_ostream &OS);
70*1db9f3b2SDimitry Andric   void emitBothPredicate(Record *Predicates, PredicateExpander &PE,
71*1db9f3b2SDimitry Andric                          raw_ostream &OS);
72*1db9f3b2SDimitry Andric 
73*1db9f3b2SDimitry Andric public:
74*1db9f3b2SDimitry Andric   MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
75*1db9f3b2SDimitry Andric 
76*1db9f3b2SDimitry Andric   void run(raw_ostream &OS);
77*1db9f3b2SDimitry Andric };
78*1db9f3b2SDimitry Andric } // End anonymous namespace.
79*1db9f3b2SDimitry Andric 
80*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionDecl(
81*1db9f3b2SDimitry Andric     std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
82*1db9f3b2SDimitry Andric   OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";
83*1db9f3b2SDimitry Andric   OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";
84*1db9f3b2SDimitry Andric   OS << "namespace llvm {\n";
85*1db9f3b2SDimitry Andric 
86*1db9f3b2SDimitry Andric   for (Record *Fusion : Fusions) {
87*1db9f3b2SDimitry Andric     OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "
88*1db9f3b2SDimitry Andric        << "const TargetSubtargetInfo &, "
89*1db9f3b2SDimitry Andric        << "const MachineInstr *, "
90*1db9f3b2SDimitry Andric        << "const MachineInstr &);\n";
91*1db9f3b2SDimitry Andric   }
92*1db9f3b2SDimitry Andric 
93*1db9f3b2SDimitry Andric   OS << "} // end namespace llvm\n";
94*1db9f3b2SDimitry Andric   OS << "\n#endif\n";
95*1db9f3b2SDimitry Andric }
96*1db9f3b2SDimitry Andric 
97*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
98*1db9f3b2SDimitry Andric     std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
99*1db9f3b2SDimitry Andric   OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n";
100*1db9f3b2SDimitry Andric   OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
101*1db9f3b2SDimitry Andric   OS << "namespace llvm {\n";
102*1db9f3b2SDimitry Andric 
103*1db9f3b2SDimitry Andric   for (Record *Fusion : Fusions) {
104*1db9f3b2SDimitry Andric     std::vector<Record *> Predicates =
105*1db9f3b2SDimitry Andric         Fusion->getValueAsListOfDefs("Predicates");
106*1db9f3b2SDimitry Andric 
107*1db9f3b2SDimitry Andric     OS << "bool is" << Fusion->getName() << "(\n";
108*1db9f3b2SDimitry Andric     OS.indent(4) << "const TargetInstrInfo &TII,\n";
109*1db9f3b2SDimitry Andric     OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
110*1db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr *FirstMI,\n";
111*1db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr &SecondMI) {\n";
112*1db9f3b2SDimitry Andric     OS.indent(2) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n";
113*1db9f3b2SDimitry Andric 
114*1db9f3b2SDimitry Andric     emitPredicates(Predicates, PE, OS);
115*1db9f3b2SDimitry Andric 
116*1db9f3b2SDimitry Andric     OS.indent(2) << "return true;\n";
117*1db9f3b2SDimitry Andric     OS << "}\n";
118*1db9f3b2SDimitry Andric   }
119*1db9f3b2SDimitry Andric 
120*1db9f3b2SDimitry Andric   OS << "} // end namespace llvm\n";
121*1db9f3b2SDimitry Andric   OS << "\n#endif\n";
122*1db9f3b2SDimitry Andric }
123*1db9f3b2SDimitry Andric 
124*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitPredicates(
125*1db9f3b2SDimitry Andric     std::vector<Record *> &Predicates, PredicateExpander &PE, raw_ostream &OS) {
126*1db9f3b2SDimitry Andric   for (Record *Predicate : Predicates) {
127*1db9f3b2SDimitry Andric     Record *Target = Predicate->getValueAsDef("Target");
128*1db9f3b2SDimitry Andric     if (Target->getName() == "first_fusion_target")
129*1db9f3b2SDimitry Andric       emitFirstPredicate(Predicate, PE, OS);
130*1db9f3b2SDimitry Andric     else if (Target->getName() == "second_fusion_target")
131*1db9f3b2SDimitry Andric       emitSecondPredicate(Predicate, PE, OS);
132*1db9f3b2SDimitry Andric     else if (Target->getName() == "both_fusion_target")
133*1db9f3b2SDimitry Andric       emitBothPredicate(Predicate, PE, OS);
134*1db9f3b2SDimitry Andric     else
135*1db9f3b2SDimitry Andric       PrintFatalError(Target->getLoc(),
136*1db9f3b2SDimitry Andric                       "Unsupported 'FusionTarget': " + Target->getName());
137*1db9f3b2SDimitry Andric   }
138*1db9f3b2SDimitry Andric }
139*1db9f3b2SDimitry Andric 
140*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
141*1db9f3b2SDimitry Andric                                                       PredicateExpander &PE,
142*1db9f3b2SDimitry Andric                                                       raw_ostream &OS) {
143*1db9f3b2SDimitry Andric   if (Predicate->isSubClassOf("WildcardPred")) {
144*1db9f3b2SDimitry Andric     OS.indent(2) << "if (!FirstMI)\n";
145*1db9f3b2SDimitry Andric     OS.indent(2) << "  return "
146*1db9f3b2SDimitry Andric                  << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
147*1db9f3b2SDimitry Andric                  << ";\n";
148*1db9f3b2SDimitry Andric   } else if (Predicate->isSubClassOf("OneUsePred")) {
149*1db9f3b2SDimitry Andric     OS.indent(2) << "{\n";
150*1db9f3b2SDimitry Andric     OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
151*1db9f3b2SDimitry Andric     OS.indent(4)
152*1db9f3b2SDimitry Andric         << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
153*1db9f3b2SDimitry Andric     OS.indent(4) << "  return false;\n";
154*1db9f3b2SDimitry Andric     OS.indent(2) << "}\n";
155*1db9f3b2SDimitry Andric   } else if (Predicate->isSubClassOf(
156*1db9f3b2SDimitry Andric                  "FirstFusionPredicateWithMCInstPredicate")) {
157*1db9f3b2SDimitry Andric     OS.indent(2) << "{\n";
158*1db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
159*1db9f3b2SDimitry Andric     OS.indent(4) << "if (";
160*1db9f3b2SDimitry Andric     PE.setNegatePredicate(true);
161*1db9f3b2SDimitry Andric     PE.setIndentLevel(3);
162*1db9f3b2SDimitry Andric     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
163*1db9f3b2SDimitry Andric     OS << ")\n";
164*1db9f3b2SDimitry Andric     OS.indent(4) << "  return false;\n";
165*1db9f3b2SDimitry Andric     OS.indent(2) << "}\n";
166*1db9f3b2SDimitry Andric   } else {
167*1db9f3b2SDimitry Andric     PrintFatalError(Predicate->getLoc(),
168*1db9f3b2SDimitry Andric                     "Unsupported predicate for first instruction: " +
169*1db9f3b2SDimitry Andric                         Predicate->getType()->getAsString());
170*1db9f3b2SDimitry Andric   }
171*1db9f3b2SDimitry Andric }
172*1db9f3b2SDimitry Andric 
173*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
174*1db9f3b2SDimitry Andric                                                        PredicateExpander &PE,
175*1db9f3b2SDimitry Andric                                                        raw_ostream &OS) {
176*1db9f3b2SDimitry Andric   if (Predicate->isSubClassOf("SecondFusionPredicateWithMCInstPredicate")) {
177*1db9f3b2SDimitry Andric     OS.indent(2) << "{\n";
178*1db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
179*1db9f3b2SDimitry Andric     OS.indent(4) << "if (";
180*1db9f3b2SDimitry Andric     PE.setNegatePredicate(true);
181*1db9f3b2SDimitry Andric     PE.setIndentLevel(3);
182*1db9f3b2SDimitry Andric     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
183*1db9f3b2SDimitry Andric     OS << ")\n";
184*1db9f3b2SDimitry Andric     OS.indent(4) << "  return false;\n";
185*1db9f3b2SDimitry Andric     OS.indent(2) << "}\n";
186*1db9f3b2SDimitry Andric   } else {
187*1db9f3b2SDimitry Andric     PrintFatalError(Predicate->getLoc(),
188*1db9f3b2SDimitry Andric                     "Unsupported predicate for first instruction: " +
189*1db9f3b2SDimitry Andric                         Predicate->getType()->getAsString());
190*1db9f3b2SDimitry Andric   }
191*1db9f3b2SDimitry Andric }
192*1db9f3b2SDimitry Andric 
193*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
194*1db9f3b2SDimitry Andric                                                      PredicateExpander &PE,
195*1db9f3b2SDimitry Andric                                                      raw_ostream &OS) {
196*1db9f3b2SDimitry Andric   if (Predicate->isSubClassOf("FusionPredicateWithCode"))
197*1db9f3b2SDimitry Andric     OS << Predicate->getValueAsString("Predicate");
198*1db9f3b2SDimitry Andric   else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
199*1db9f3b2SDimitry Andric     Record *MCPred = Predicate->getValueAsDef("Predicate");
200*1db9f3b2SDimitry Andric     emitFirstPredicate(MCPred, PE, OS);
201*1db9f3b2SDimitry Andric     emitSecondPredicate(MCPred, PE, OS);
202*1db9f3b2SDimitry Andric   } else if (Predicate->isSubClassOf("TieReg")) {
203*1db9f3b2SDimitry Andric     int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
204*1db9f3b2SDimitry Andric     int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
205*1db9f3b2SDimitry Andric     OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
206*1db9f3b2SDimitry Andric                  << ").isReg() &&\n";
207*1db9f3b2SDimitry Andric     OS.indent(2) << "      SecondMI.getOperand(" << SecondOpIdx
208*1db9f3b2SDimitry Andric                  << ").isReg() &&\n";
209*1db9f3b2SDimitry Andric     OS.indent(2) << "      FirstMI->getOperand(" << FirstOpIdx
210*1db9f3b2SDimitry Andric                  << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
211*1db9f3b2SDimitry Andric                  << ").getReg()))\n";
212*1db9f3b2SDimitry Andric     OS.indent(2) << "  return false;\n";
213*1db9f3b2SDimitry Andric   } else
214*1db9f3b2SDimitry Andric     PrintFatalError(Predicate->getLoc(),
215*1db9f3b2SDimitry Andric                     "Unsupported predicate for both instruction: " +
216*1db9f3b2SDimitry Andric                         Predicate->getType()->getAsString());
217*1db9f3b2SDimitry Andric }
218*1db9f3b2SDimitry Andric 
219*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
220*1db9f3b2SDimitry Andric   // Emit file header.
221*1db9f3b2SDimitry Andric   emitSourceFileHeader("Macro Fusion Predicators", OS);
222*1db9f3b2SDimitry Andric 
223*1db9f3b2SDimitry Andric   PredicateExpander PE(Target.getName());
224*1db9f3b2SDimitry Andric   PE.setByRef(false);
225*1db9f3b2SDimitry Andric   PE.setExpandForMC(false);
226*1db9f3b2SDimitry Andric 
227*1db9f3b2SDimitry Andric   std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
228*1db9f3b2SDimitry Andric   // Sort macro fusions by name.
229*1db9f3b2SDimitry Andric   sort(Fusions, LessRecord());
230*1db9f3b2SDimitry Andric   emitMacroFusionDecl(Fusions, PE, OS);
231*1db9f3b2SDimitry Andric   OS << "\n";
232*1db9f3b2SDimitry Andric   emitMacroFusionImpl(Fusions, PE, OS);
233*1db9f3b2SDimitry Andric }
234*1db9f3b2SDimitry Andric 
235*1db9f3b2SDimitry Andric static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
236*1db9f3b2SDimitry Andric     X("gen-macro-fusion-pred", "Generate macro fusion predicators.");
237