11db9f3b2SDimitry Andric //===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===//
21db9f3b2SDimitry Andric //
31db9f3b2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41db9f3b2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
51db9f3b2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61db9f3b2SDimitry Andric //
71db9f3b2SDimitry Andric //===---------------------------------------------------------------------===//
81db9f3b2SDimitry Andric //
91db9f3b2SDimitry Andric // MacroFusionPredicatorEmitter implements a TableGen-driven predicators
101db9f3b2SDimitry Andric // generator for macro-op fusions.
111db9f3b2SDimitry Andric //
121db9f3b2SDimitry Andric // This TableGen backend processes `Fusion` definitions and generates
131db9f3b2SDimitry Andric // predicators for checking if input instructions can be fused. These
141db9f3b2SDimitry Andric // predicators can used in `MacroFusion` DAG mutation.
151db9f3b2SDimitry Andric //
161db9f3b2SDimitry Andric // The generated header file contains two parts: one for predicator
171db9f3b2SDimitry Andric // declarations and one for predicator implementations. The user can get them
181db9f3b2SDimitry Andric // by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or
191db9f3b2SDimitry Andric // `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated
201db9f3b2SDimitry Andric // header file.
211db9f3b2SDimitry Andric //
221db9f3b2SDimitry Andric // The generated predicator will be like:
231db9f3b2SDimitry Andric //
241db9f3b2SDimitry Andric // ```
251db9f3b2SDimitry Andric // bool isNAME(const TargetInstrInfo &TII,
261db9f3b2SDimitry Andric // const TargetSubtargetInfo &STI,
271db9f3b2SDimitry Andric // const MachineInstr *FirstMI,
281db9f3b2SDimitry Andric // const MachineInstr &SecondMI) {
291db9f3b2SDimitry Andric // auto &MRI = SecondMI.getMF()->getRegInfo();
301db9f3b2SDimitry Andric // /* Predicates */
311db9f3b2SDimitry Andric // return true;
321db9f3b2SDimitry Andric // }
331db9f3b2SDimitry Andric // ```
341db9f3b2SDimitry Andric //
351db9f3b2SDimitry Andric // The `Predicates` part is generated from a list of `FusionPredicate`, which
361db9f3b2SDimitry Andric // can be predefined predicates, a raw code string or `MCInstPredicate` defined
371db9f3b2SDimitry Andric // in TargetInstrPredicate.td.
381db9f3b2SDimitry Andric //
391db9f3b2SDimitry Andric //===---------------------------------------------------------------------===//
401db9f3b2SDimitry Andric
41*0fca6ea1SDimitry Andric #include "Common/CodeGenTarget.h"
42*0fca6ea1SDimitry Andric #include "Common/PredicateExpander.h"
431db9f3b2SDimitry Andric #include "llvm/Support/Debug.h"
441db9f3b2SDimitry Andric #include "llvm/TableGen/Error.h"
451db9f3b2SDimitry Andric #include "llvm/TableGen/Record.h"
461db9f3b2SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
471db9f3b2SDimitry Andric #include <vector>
481db9f3b2SDimitry Andric
491db9f3b2SDimitry Andric using namespace llvm;
501db9f3b2SDimitry Andric
511db9f3b2SDimitry Andric #define DEBUG_TYPE "macro-fusion-predicator"
521db9f3b2SDimitry Andric
531db9f3b2SDimitry Andric namespace {
541db9f3b2SDimitry Andric class MacroFusionPredicatorEmitter {
551db9f3b2SDimitry Andric RecordKeeper &Records;
561db9f3b2SDimitry Andric CodeGenTarget Target;
571db9f3b2SDimitry Andric
58*0fca6ea1SDimitry Andric void emitMacroFusionDecl(ArrayRef<Record *> Fusions, PredicateExpander &PE,
591db9f3b2SDimitry Andric raw_ostream &OS);
60*0fca6ea1SDimitry Andric void emitMacroFusionImpl(ArrayRef<Record *> Fusions, PredicateExpander &PE,
611db9f3b2SDimitry Andric raw_ostream &OS);
62*0fca6ea1SDimitry Andric void emitPredicates(ArrayRef<Record *> FirstPredicate, bool IsCommutable,
631db9f3b2SDimitry Andric PredicateExpander &PE, raw_ostream &OS);
64*0fca6ea1SDimitry Andric void emitFirstPredicate(Record *SecondPredicate, bool IsCommutable,
65*0fca6ea1SDimitry Andric PredicateExpander &PE, raw_ostream &OS);
66*0fca6ea1SDimitry Andric void emitSecondPredicate(Record *SecondPredicate, bool IsCommutable,
67*0fca6ea1SDimitry Andric PredicateExpander &PE, raw_ostream &OS);
68*0fca6ea1SDimitry Andric void emitBothPredicate(Record *Predicates, bool IsCommutable,
69*0fca6ea1SDimitry Andric PredicateExpander &PE, raw_ostream &OS);
701db9f3b2SDimitry Andric
711db9f3b2SDimitry Andric public:
MacroFusionPredicatorEmitter(RecordKeeper & R)721db9f3b2SDimitry Andric MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
731db9f3b2SDimitry Andric
741db9f3b2SDimitry Andric void run(raw_ostream &OS);
751db9f3b2SDimitry Andric };
761db9f3b2SDimitry Andric } // End anonymous namespace.
771db9f3b2SDimitry Andric
emitMacroFusionDecl(ArrayRef<Record * > Fusions,PredicateExpander & PE,raw_ostream & OS)781db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionDecl(
79*0fca6ea1SDimitry Andric ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
801db9f3b2SDimitry Andric OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";
811db9f3b2SDimitry Andric OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";
821db9f3b2SDimitry Andric OS << "namespace llvm {\n";
831db9f3b2SDimitry Andric
841db9f3b2SDimitry Andric for (Record *Fusion : Fusions) {
851db9f3b2SDimitry Andric OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "
861db9f3b2SDimitry Andric << "const TargetSubtargetInfo &, "
871db9f3b2SDimitry Andric << "const MachineInstr *, "
881db9f3b2SDimitry Andric << "const MachineInstr &);\n";
891db9f3b2SDimitry Andric }
901db9f3b2SDimitry Andric
911db9f3b2SDimitry Andric OS << "} // end namespace llvm\n";
921db9f3b2SDimitry Andric OS << "\n#endif\n";
931db9f3b2SDimitry Andric }
941db9f3b2SDimitry Andric
emitMacroFusionImpl(ArrayRef<Record * > Fusions,PredicateExpander & PE,raw_ostream & OS)951db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
96*0fca6ea1SDimitry Andric ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
971db9f3b2SDimitry Andric OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n";
981db9f3b2SDimitry Andric OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
991db9f3b2SDimitry Andric OS << "namespace llvm {\n";
1001db9f3b2SDimitry Andric
1011db9f3b2SDimitry Andric for (Record *Fusion : Fusions) {
1021db9f3b2SDimitry Andric std::vector<Record *> Predicates =
1031db9f3b2SDimitry Andric Fusion->getValueAsListOfDefs("Predicates");
104*0fca6ea1SDimitry Andric bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
1051db9f3b2SDimitry Andric
1061db9f3b2SDimitry Andric OS << "bool is" << Fusion->getName() << "(\n";
1071db9f3b2SDimitry Andric OS.indent(4) << "const TargetInstrInfo &TII,\n";
1081db9f3b2SDimitry Andric OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
1091db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr *FirstMI,\n";
1101db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr &SecondMI) {\n";
111*0fca6ea1SDimitry Andric OS.indent(2)
112*0fca6ea1SDimitry Andric << "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n";
1131db9f3b2SDimitry Andric
114*0fca6ea1SDimitry Andric emitPredicates(Predicates, IsCommutable, PE, OS);
1151db9f3b2SDimitry Andric
1161db9f3b2SDimitry Andric OS.indent(2) << "return true;\n";
1171db9f3b2SDimitry Andric OS << "}\n";
1181db9f3b2SDimitry Andric }
1191db9f3b2SDimitry Andric
1201db9f3b2SDimitry Andric OS << "} // end namespace llvm\n";
1211db9f3b2SDimitry Andric OS << "\n#endif\n";
1221db9f3b2SDimitry Andric }
1231db9f3b2SDimitry Andric
emitPredicates(ArrayRef<Record * > Predicates,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)124*0fca6ea1SDimitry Andric void MacroFusionPredicatorEmitter::emitPredicates(ArrayRef<Record *> Predicates,
125*0fca6ea1SDimitry Andric bool IsCommutable,
126*0fca6ea1SDimitry Andric PredicateExpander &PE,
127*0fca6ea1SDimitry Andric raw_ostream &OS) {
1281db9f3b2SDimitry Andric for (Record *Predicate : Predicates) {
1291db9f3b2SDimitry Andric Record *Target = Predicate->getValueAsDef("Target");
1301db9f3b2SDimitry Andric if (Target->getName() == "first_fusion_target")
131*0fca6ea1SDimitry Andric emitFirstPredicate(Predicate, IsCommutable, PE, OS);
1321db9f3b2SDimitry Andric else if (Target->getName() == "second_fusion_target")
133*0fca6ea1SDimitry Andric emitSecondPredicate(Predicate, IsCommutable, PE, OS);
1341db9f3b2SDimitry Andric else if (Target->getName() == "both_fusion_target")
135*0fca6ea1SDimitry Andric emitBothPredicate(Predicate, IsCommutable, PE, OS);
1361db9f3b2SDimitry Andric else
1371db9f3b2SDimitry Andric PrintFatalError(Target->getLoc(),
1381db9f3b2SDimitry Andric "Unsupported 'FusionTarget': " + Target->getName());
1391db9f3b2SDimitry Andric }
1401db9f3b2SDimitry Andric }
1411db9f3b2SDimitry Andric
emitFirstPredicate(Record * Predicate,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)1421db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
143*0fca6ea1SDimitry Andric bool IsCommutable,
1441db9f3b2SDimitry Andric PredicateExpander &PE,
1451db9f3b2SDimitry Andric raw_ostream &OS) {
1461db9f3b2SDimitry Andric if (Predicate->isSubClassOf("WildcardPred")) {
1471db9f3b2SDimitry Andric OS.indent(2) << "if (!FirstMI)\n";
1481db9f3b2SDimitry Andric OS.indent(2) << " return "
1491db9f3b2SDimitry Andric << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
1501db9f3b2SDimitry Andric << ";\n";
1511db9f3b2SDimitry Andric } else if (Predicate->isSubClassOf("OneUsePred")) {
1521db9f3b2SDimitry Andric OS.indent(2) << "{\n";
1531db9f3b2SDimitry Andric OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
1541db9f3b2SDimitry Andric OS.indent(4)
1551db9f3b2SDimitry Andric << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
1561db9f3b2SDimitry Andric OS.indent(4) << " return false;\n";
1571db9f3b2SDimitry Andric OS.indent(2) << "}\n";
158439352acSDimitry Andric } else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
1591db9f3b2SDimitry Andric OS.indent(2) << "{\n";
1601db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
1611db9f3b2SDimitry Andric OS.indent(4) << "if (";
1621db9f3b2SDimitry Andric PE.setNegatePredicate(true);
1631db9f3b2SDimitry Andric PE.setIndentLevel(3);
1641db9f3b2SDimitry Andric PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
1651db9f3b2SDimitry Andric OS << ")\n";
1661db9f3b2SDimitry Andric OS.indent(4) << " return false;\n";
1671db9f3b2SDimitry Andric OS.indent(2) << "}\n";
1681db9f3b2SDimitry Andric } else {
1691db9f3b2SDimitry Andric PrintFatalError(Predicate->getLoc(),
1701db9f3b2SDimitry Andric "Unsupported predicate for first instruction: " +
1711db9f3b2SDimitry Andric Predicate->getType()->getAsString());
1721db9f3b2SDimitry Andric }
1731db9f3b2SDimitry Andric }
1741db9f3b2SDimitry Andric
emitSecondPredicate(Record * Predicate,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)1751db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
176*0fca6ea1SDimitry Andric bool IsCommutable,
1771db9f3b2SDimitry Andric PredicateExpander &PE,
1781db9f3b2SDimitry Andric raw_ostream &OS) {
179439352acSDimitry Andric if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
1801db9f3b2SDimitry Andric OS.indent(2) << "{\n";
1811db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
1821db9f3b2SDimitry Andric OS.indent(4) << "if (";
1831db9f3b2SDimitry Andric PE.setNegatePredicate(true);
1841db9f3b2SDimitry Andric PE.setIndentLevel(3);
1851db9f3b2SDimitry Andric PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
1861db9f3b2SDimitry Andric OS << ")\n";
1871db9f3b2SDimitry Andric OS.indent(4) << " return false;\n";
1881db9f3b2SDimitry Andric OS.indent(2) << "}\n";
189*0fca6ea1SDimitry Andric } else if (Predicate->isSubClassOf("SameReg")) {
190*0fca6ea1SDimitry Andric int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
191*0fca6ea1SDimitry Andric int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
192*0fca6ea1SDimitry Andric
193*0fca6ea1SDimitry Andric OS.indent(2) << "if (!SecondMI.getOperand(" << FirstOpIdx
194*0fca6ea1SDimitry Andric << ").getReg().isVirtual()) {\n";
195*0fca6ea1SDimitry Andric OS.indent(4) << "if (SecondMI.getOperand(" << FirstOpIdx
196*0fca6ea1SDimitry Andric << ").getReg() != SecondMI.getOperand(" << SecondOpIdx
197*0fca6ea1SDimitry Andric << ").getReg())";
198*0fca6ea1SDimitry Andric
199*0fca6ea1SDimitry Andric if (IsCommutable) {
200*0fca6ea1SDimitry Andric OS << " {\n";
201*0fca6ea1SDimitry Andric OS.indent(6) << "if (!SecondMI.getDesc().isCommutable())\n";
202*0fca6ea1SDimitry Andric OS.indent(6) << " return false;\n";
203*0fca6ea1SDimitry Andric
204*0fca6ea1SDimitry Andric OS.indent(6)
205*0fca6ea1SDimitry Andric << "unsigned SrcOpIdx1 = " << SecondOpIdx
206*0fca6ea1SDimitry Andric << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
207*0fca6ea1SDimitry Andric OS.indent(6)
208*0fca6ea1SDimitry Andric << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
209*0fca6ea1SDimitry Andric OS.indent(6)
210*0fca6ea1SDimitry Andric << " if (SecondMI.getOperand(" << FirstOpIdx
211*0fca6ea1SDimitry Andric << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
212*0fca6ea1SDimitry Andric OS.indent(6) << " return false;\n";
213*0fca6ea1SDimitry Andric OS.indent(4) << "}\n";
214*0fca6ea1SDimitry Andric } else {
215*0fca6ea1SDimitry Andric OS << "\n";
216*0fca6ea1SDimitry Andric OS.indent(4) << " return false;\n";
217*0fca6ea1SDimitry Andric }
218*0fca6ea1SDimitry Andric OS.indent(2) << "}\n";
2191db9f3b2SDimitry Andric } else {
2201db9f3b2SDimitry Andric PrintFatalError(Predicate->getLoc(),
221439352acSDimitry Andric "Unsupported predicate for second instruction: " +
2221db9f3b2SDimitry Andric Predicate->getType()->getAsString());
2231db9f3b2SDimitry Andric }
2241db9f3b2SDimitry Andric }
2251db9f3b2SDimitry Andric
emitBothPredicate(Record * Predicate,bool IsCommutable,PredicateExpander & PE,raw_ostream & OS)2261db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
227*0fca6ea1SDimitry Andric bool IsCommutable,
2281db9f3b2SDimitry Andric PredicateExpander &PE,
2291db9f3b2SDimitry Andric raw_ostream &OS) {
2301db9f3b2SDimitry Andric if (Predicate->isSubClassOf("FusionPredicateWithCode"))
2311db9f3b2SDimitry Andric OS << Predicate->getValueAsString("Predicate");
2321db9f3b2SDimitry Andric else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
233*0fca6ea1SDimitry Andric emitFirstPredicate(Predicate, IsCommutable, PE, OS);
234*0fca6ea1SDimitry Andric emitSecondPredicate(Predicate, IsCommutable, PE, OS);
2351db9f3b2SDimitry Andric } else if (Predicate->isSubClassOf("TieReg")) {
2361db9f3b2SDimitry Andric int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
2371db9f3b2SDimitry Andric int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
2381db9f3b2SDimitry Andric OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
2391db9f3b2SDimitry Andric << ").isReg() &&\n";
2401db9f3b2SDimitry Andric OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx
2411db9f3b2SDimitry Andric << ").isReg() &&\n";
2421db9f3b2SDimitry Andric OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx
2431db9f3b2SDimitry Andric << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
244*0fca6ea1SDimitry Andric << ").getReg()))";
245*0fca6ea1SDimitry Andric
246*0fca6ea1SDimitry Andric if (IsCommutable) {
247*0fca6ea1SDimitry Andric OS << " {\n";
248*0fca6ea1SDimitry Andric OS.indent(4) << "if (!SecondMI.getDesc().isCommutable())\n";
249*0fca6ea1SDimitry Andric OS.indent(4) << " return false;\n";
250*0fca6ea1SDimitry Andric
251*0fca6ea1SDimitry Andric OS.indent(4)
252*0fca6ea1SDimitry Andric << "unsigned SrcOpIdx1 = " << SecondOpIdx
253*0fca6ea1SDimitry Andric << ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";
254*0fca6ea1SDimitry Andric OS.indent(4)
255*0fca6ea1SDimitry Andric << "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";
256*0fca6ea1SDimitry Andric OS.indent(4)
257*0fca6ea1SDimitry Andric << " if (FirstMI->getOperand(" << FirstOpIdx
258*0fca6ea1SDimitry Andric << ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";
259*0fca6ea1SDimitry Andric OS.indent(4) << " return false;\n";
260*0fca6ea1SDimitry Andric OS.indent(2) << "}";
261*0fca6ea1SDimitry Andric } else {
262*0fca6ea1SDimitry Andric OS << "\n";
263*0fca6ea1SDimitry Andric OS.indent(2) << " return false;";
264*0fca6ea1SDimitry Andric }
265*0fca6ea1SDimitry Andric OS << "\n";
2661db9f3b2SDimitry Andric } else
2671db9f3b2SDimitry Andric PrintFatalError(Predicate->getLoc(),
2681db9f3b2SDimitry Andric "Unsupported predicate for both instruction: " +
2691db9f3b2SDimitry Andric Predicate->getType()->getAsString());
2701db9f3b2SDimitry Andric }
2711db9f3b2SDimitry Andric
run(raw_ostream & OS)2721db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
2731db9f3b2SDimitry Andric // Emit file header.
2741db9f3b2SDimitry Andric emitSourceFileHeader("Macro Fusion Predicators", OS);
2751db9f3b2SDimitry Andric
2761db9f3b2SDimitry Andric PredicateExpander PE(Target.getName());
2771db9f3b2SDimitry Andric PE.setByRef(false);
2781db9f3b2SDimitry Andric PE.setExpandForMC(false);
2791db9f3b2SDimitry Andric
2801db9f3b2SDimitry Andric std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
2811db9f3b2SDimitry Andric // Sort macro fusions by name.
2821db9f3b2SDimitry Andric sort(Fusions, LessRecord());
2831db9f3b2SDimitry Andric emitMacroFusionDecl(Fusions, PE, OS);
2841db9f3b2SDimitry Andric OS << "\n";
2851db9f3b2SDimitry Andric emitMacroFusionImpl(Fusions, PE, OS);
2861db9f3b2SDimitry Andric }
2871db9f3b2SDimitry Andric
2881db9f3b2SDimitry Andric static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
2891db9f3b2SDimitry Andric X("gen-macro-fusion-pred", "Generate macro fusion predicators.");
290