1 //===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===//
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
7 //===---------------------------------------------------------------------===//
9 // MacroFusionPredicatorEmitter implements a TableGen-driven predicators
10 // generator for macro-op fusions.
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.
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
22 // The generated predicator will be like:
25 // bool isNAME(const TargetInstrInfo &TII,
26 // const TargetSubtargetInfo &STI,
27 // const MachineInstr *FirstMI,
28 // const MachineInstr &SecondMI) {
29 // auto &MRI = SecondMI.getMF()->getRegInfo();
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.
39 //===---------------------------------------------------------------------===//
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"
51 #define DEBUG_TYPE "macro-fusion-predicator"
54 class MacroFusionPredicatorEmitter
{
55 const RecordKeeper
&Records
;
56 const CodeGenTarget Target
;
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
,
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
);
73 MacroFusionPredicatorEmitter(const RecordKeeper
&R
) : Records(R
), Target(R
) {}
75 void run(raw_ostream
&OS
);
77 } // End anonymous namespace.
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";
85 for (const Record
*Fusion
: Fusions
) {
86 OS
<< "bool is" << Fusion
->getName() << "(const TargetInstrInfo &, "
87 << "const TargetSubtargetInfo &, "
88 << "const MachineInstr *, "
89 << "const MachineInstr &);\n";
92 OS
<< "} // end namespace llvm\n";
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";
102 for (const Record
*Fusion
: Fusions
) {
103 std::vector
<const Record
*> Predicates
=
104 Fusion
->getValueAsListOfDefs("Predicates");
105 bool IsCommutable
= Fusion
->getValueAsBit("IsCommutable");
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";
113 << "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n";
115 emitPredicates(Predicates
, IsCommutable
, PE
, OS
);
117 OS
.indent(2) << "return true;\n";
121 OS
<< "} // end namespace llvm\n";
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
);
137 PrintFatalError(Target
->getLoc(),
138 "Unsupported 'FusionTarget': " + Target
->getName());
142 void MacroFusionPredicatorEmitter::emitFirstPredicate(const Record
*Predicate
,
144 PredicateExpander
&PE
,
146 if (Predicate
->isSubClassOf("WildcardPred")) {
147 OS
.indent(2) << "if (!FirstMI)\n";
148 OS
.indent(2) << " return "
149 << (Predicate
->getValueAsBit("ReturnValue") ? "true" : "false")
151 } else if (Predicate
->isSubClassOf("OneUsePred")) {
152 OS
.indent(2) << "{\n";
153 OS
.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
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);
164 PE
.expandPredicate(OS
, Predicate
->getValueAsDef("Predicate"));
166 OS
.indent(4) << " return false;\n";
167 OS
.indent(2) << "}\n";
169 PrintFatalError(Predicate
->getLoc(),
170 "Unsupported predicate for first instruction: " +
171 Predicate
->getType()->getAsString());
175 void MacroFusionPredicatorEmitter::emitSecondPredicate(const Record
*Predicate
,
177 PredicateExpander
&PE
,
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);
185 PE
.expandPredicate(OS
, Predicate
->getValueAsDef("Predicate"));
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");
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
201 OS
.indent(6) << "if (!SecondMI.getDesc().isCommutable())\n";
202 OS
.indent(6) << " return false;\n";
205 << "unsigned SrcOpIdx1 = " << SecondOpIdx
206 << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
208 << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
210 << " if (SecondMI.getOperand(" << FirstOpIdx
211 << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
212 OS
.indent(6) << " return false;\n";
213 OS
.indent(4) << "}\n";
216 OS
.indent(4) << " return false;\n";
218 OS
.indent(2) << "}\n";
220 PrintFatalError(Predicate
->getLoc(),
221 "Unsupported predicate for second instruction: " +
222 Predicate
->getType()->getAsString());
226 void MacroFusionPredicatorEmitter::emitBothPredicate(const Record
*Predicate
,
228 PredicateExpander
&PE
,
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
240 OS
.indent(2) << " SecondMI.getOperand(" << SecondOpIdx
242 OS
.indent(2) << " FirstMI->getOperand(" << FirstOpIdx
243 << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
248 OS
.indent(4) << "if (!SecondMI.getDesc().isCommutable())\n";
249 OS
.indent(4) << " return false;\n";
252 << "unsigned SrcOpIdx1 = " << SecondOpIdx
253 << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
255 << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
257 << " if (FirstMI->getOperand(" << FirstOpIdx
258 << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
259 OS
.indent(4) << " return false;\n";
263 OS
.indent(2) << " return false;";
267 PrintFatalError(Predicate
->getLoc(),
268 "Unsupported predicate for both instruction: " +
269 Predicate
->getType()->getAsString());
272 void MacroFusionPredicatorEmitter::run(raw_ostream
&OS
) {
274 emitSourceFileHeader("Macro Fusion Predicators", OS
);
276 PredicateExpander
PE(Target
.getName());
278 PE
.setExpandForMC(false);
280 ArrayRef
<const Record
*> Fusions
= Records
.getAllDerivedDefinitions("Fusion");
281 emitMacroFusionDecl(Fusions
, PE
, OS
);
283 emitMacroFusionImpl(Fusions
, PE
, OS
);
286 static TableGen::Emitter::OptClass
<MacroFusionPredicatorEmitter
>
287 X("gen-macro-fusion-pred", "Generate macro fusion predicators.");