xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp (revision 439352ac8257c8419cb4a662abb7f260f31f9932)
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 
411db9f3b2SDimitry Andric #include "CodeGenTarget.h"
421db9f3b2SDimitry Andric #include "PredicateExpander.h"
431db9f3b2SDimitry Andric #include "llvm/ADT/SmallVector.h"
441db9f3b2SDimitry Andric #include "llvm/Support/Debug.h"
451db9f3b2SDimitry Andric #include "llvm/TableGen/Error.h"
461db9f3b2SDimitry Andric #include "llvm/TableGen/Record.h"
471db9f3b2SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
481db9f3b2SDimitry Andric #include <set>
491db9f3b2SDimitry Andric #include <vector>
501db9f3b2SDimitry Andric 
511db9f3b2SDimitry Andric using namespace llvm;
521db9f3b2SDimitry Andric 
531db9f3b2SDimitry Andric #define DEBUG_TYPE "macro-fusion-predicator"
541db9f3b2SDimitry Andric 
551db9f3b2SDimitry Andric namespace {
561db9f3b2SDimitry Andric class MacroFusionPredicatorEmitter {
571db9f3b2SDimitry Andric   RecordKeeper &Records;
581db9f3b2SDimitry Andric   CodeGenTarget Target;
591db9f3b2SDimitry Andric 
601db9f3b2SDimitry Andric   void emitMacroFusionDecl(std::vector<Record *> Fusions, PredicateExpander &PE,
611db9f3b2SDimitry Andric                            raw_ostream &OS);
621db9f3b2SDimitry Andric   void emitMacroFusionImpl(std::vector<Record *> Fusions, PredicateExpander &PE,
631db9f3b2SDimitry Andric                            raw_ostream &OS);
641db9f3b2SDimitry Andric   void emitPredicates(std::vector<Record *> &FirstPredicate,
651db9f3b2SDimitry Andric                       PredicateExpander &PE, raw_ostream &OS);
661db9f3b2SDimitry Andric   void emitFirstPredicate(Record *SecondPredicate, PredicateExpander &PE,
671db9f3b2SDimitry Andric                           raw_ostream &OS);
681db9f3b2SDimitry Andric   void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE,
691db9f3b2SDimitry Andric                            raw_ostream &OS);
701db9f3b2SDimitry Andric   void emitBothPredicate(Record *Predicates, PredicateExpander &PE,
711db9f3b2SDimitry Andric                          raw_ostream &OS);
721db9f3b2SDimitry Andric 
731db9f3b2SDimitry Andric public:
741db9f3b2SDimitry Andric   MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}
751db9f3b2SDimitry Andric 
761db9f3b2SDimitry Andric   void run(raw_ostream &OS);
771db9f3b2SDimitry Andric };
781db9f3b2SDimitry Andric } // End anonymous namespace.
791db9f3b2SDimitry Andric 
801db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionDecl(
811db9f3b2SDimitry Andric     std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
821db9f3b2SDimitry Andric   OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";
831db9f3b2SDimitry Andric   OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";
841db9f3b2SDimitry Andric   OS << "namespace llvm {\n";
851db9f3b2SDimitry Andric 
861db9f3b2SDimitry Andric   for (Record *Fusion : Fusions) {
871db9f3b2SDimitry Andric     OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "
881db9f3b2SDimitry Andric        << "const TargetSubtargetInfo &, "
891db9f3b2SDimitry Andric        << "const MachineInstr *, "
901db9f3b2SDimitry Andric        << "const MachineInstr &);\n";
911db9f3b2SDimitry Andric   }
921db9f3b2SDimitry Andric 
931db9f3b2SDimitry Andric   OS << "} // end namespace llvm\n";
941db9f3b2SDimitry Andric   OS << "\n#endif\n";
951db9f3b2SDimitry Andric }
961db9f3b2SDimitry Andric 
971db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
981db9f3b2SDimitry Andric     std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {
991db9f3b2SDimitry Andric   OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n";
1001db9f3b2SDimitry Andric   OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";
1011db9f3b2SDimitry Andric   OS << "namespace llvm {\n";
1021db9f3b2SDimitry Andric 
1031db9f3b2SDimitry Andric   for (Record *Fusion : Fusions) {
1041db9f3b2SDimitry Andric     std::vector<Record *> Predicates =
1051db9f3b2SDimitry Andric         Fusion->getValueAsListOfDefs("Predicates");
1061db9f3b2SDimitry Andric 
1071db9f3b2SDimitry Andric     OS << "bool is" << Fusion->getName() << "(\n";
1081db9f3b2SDimitry Andric     OS.indent(4) << "const TargetInstrInfo &TII,\n";
1091db9f3b2SDimitry Andric     OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
1101db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr *FirstMI,\n";
1111db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr &SecondMI) {\n";
1121db9f3b2SDimitry Andric     OS.indent(2) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n";
1131db9f3b2SDimitry Andric 
1141db9f3b2SDimitry Andric     emitPredicates(Predicates, 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 
1241db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitPredicates(
1251db9f3b2SDimitry Andric     std::vector<Record *> &Predicates, PredicateExpander &PE, raw_ostream &OS) {
1261db9f3b2SDimitry Andric   for (Record *Predicate : Predicates) {
1271db9f3b2SDimitry Andric     Record *Target = Predicate->getValueAsDef("Target");
1281db9f3b2SDimitry Andric     if (Target->getName() == "first_fusion_target")
1291db9f3b2SDimitry Andric       emitFirstPredicate(Predicate, PE, OS);
1301db9f3b2SDimitry Andric     else if (Target->getName() == "second_fusion_target")
1311db9f3b2SDimitry Andric       emitSecondPredicate(Predicate, PE, OS);
1321db9f3b2SDimitry Andric     else if (Target->getName() == "both_fusion_target")
1331db9f3b2SDimitry Andric       emitBothPredicate(Predicate, PE, OS);
1341db9f3b2SDimitry Andric     else
1351db9f3b2SDimitry Andric       PrintFatalError(Target->getLoc(),
1361db9f3b2SDimitry Andric                       "Unsupported 'FusionTarget': " + Target->getName());
1371db9f3b2SDimitry Andric   }
1381db9f3b2SDimitry Andric }
1391db9f3b2SDimitry Andric 
1401db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
1411db9f3b2SDimitry Andric                                                       PredicateExpander &PE,
1421db9f3b2SDimitry Andric                                                       raw_ostream &OS) {
1431db9f3b2SDimitry Andric   if (Predicate->isSubClassOf("WildcardPred")) {
1441db9f3b2SDimitry Andric     OS.indent(2) << "if (!FirstMI)\n";
1451db9f3b2SDimitry Andric     OS.indent(2) << "  return "
1461db9f3b2SDimitry Andric                  << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")
1471db9f3b2SDimitry Andric                  << ";\n";
1481db9f3b2SDimitry Andric   } else if (Predicate->isSubClassOf("OneUsePred")) {
1491db9f3b2SDimitry Andric     OS.indent(2) << "{\n";
1501db9f3b2SDimitry Andric     OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";
1511db9f3b2SDimitry Andric     OS.indent(4)
1521db9f3b2SDimitry Andric         << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
1531db9f3b2SDimitry Andric     OS.indent(4) << "  return false;\n";
1541db9f3b2SDimitry Andric     OS.indent(2) << "}\n";
155*439352acSDimitry Andric   } else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
1561db9f3b2SDimitry Andric     OS.indent(2) << "{\n";
1571db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
1581db9f3b2SDimitry Andric     OS.indent(4) << "if (";
1591db9f3b2SDimitry Andric     PE.setNegatePredicate(true);
1601db9f3b2SDimitry Andric     PE.setIndentLevel(3);
1611db9f3b2SDimitry Andric     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
1621db9f3b2SDimitry Andric     OS << ")\n";
1631db9f3b2SDimitry Andric     OS.indent(4) << "  return false;\n";
1641db9f3b2SDimitry Andric     OS.indent(2) << "}\n";
1651db9f3b2SDimitry Andric   } else {
1661db9f3b2SDimitry Andric     PrintFatalError(Predicate->getLoc(),
1671db9f3b2SDimitry Andric                     "Unsupported predicate for first instruction: " +
1681db9f3b2SDimitry Andric                         Predicate->getType()->getAsString());
1691db9f3b2SDimitry Andric   }
1701db9f3b2SDimitry Andric }
1711db9f3b2SDimitry Andric 
1721db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
1731db9f3b2SDimitry Andric                                                        PredicateExpander &PE,
1741db9f3b2SDimitry Andric                                                        raw_ostream &OS) {
175*439352acSDimitry Andric   if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
1761db9f3b2SDimitry Andric     OS.indent(2) << "{\n";
1771db9f3b2SDimitry Andric     OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
1781db9f3b2SDimitry Andric     OS.indent(4) << "if (";
1791db9f3b2SDimitry Andric     PE.setNegatePredicate(true);
1801db9f3b2SDimitry Andric     PE.setIndentLevel(3);
1811db9f3b2SDimitry Andric     PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));
1821db9f3b2SDimitry Andric     OS << ")\n";
1831db9f3b2SDimitry Andric     OS.indent(4) << "  return false;\n";
1841db9f3b2SDimitry Andric     OS.indent(2) << "}\n";
1851db9f3b2SDimitry Andric   } else {
1861db9f3b2SDimitry Andric     PrintFatalError(Predicate->getLoc(),
187*439352acSDimitry Andric                     "Unsupported predicate for second instruction: " +
1881db9f3b2SDimitry Andric                         Predicate->getType()->getAsString());
1891db9f3b2SDimitry Andric   }
1901db9f3b2SDimitry Andric }
1911db9f3b2SDimitry Andric 
1921db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
1931db9f3b2SDimitry Andric                                                      PredicateExpander &PE,
1941db9f3b2SDimitry Andric                                                      raw_ostream &OS) {
1951db9f3b2SDimitry Andric   if (Predicate->isSubClassOf("FusionPredicateWithCode"))
1961db9f3b2SDimitry Andric     OS << Predicate->getValueAsString("Predicate");
1971db9f3b2SDimitry Andric   else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
198*439352acSDimitry Andric     emitFirstPredicate(Predicate, PE, OS);
199*439352acSDimitry Andric     emitSecondPredicate(Predicate, PE, OS);
2001db9f3b2SDimitry Andric   } else if (Predicate->isSubClassOf("TieReg")) {
2011db9f3b2SDimitry Andric     int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
2021db9f3b2SDimitry Andric     int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");
2031db9f3b2SDimitry Andric     OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx
2041db9f3b2SDimitry Andric                  << ").isReg() &&\n";
2051db9f3b2SDimitry Andric     OS.indent(2) << "      SecondMI.getOperand(" << SecondOpIdx
2061db9f3b2SDimitry Andric                  << ").isReg() &&\n";
2071db9f3b2SDimitry Andric     OS.indent(2) << "      FirstMI->getOperand(" << FirstOpIdx
2081db9f3b2SDimitry Andric                  << ").getReg() == SecondMI.getOperand(" << SecondOpIdx
2091db9f3b2SDimitry Andric                  << ").getReg()))\n";
2101db9f3b2SDimitry Andric     OS.indent(2) << "  return false;\n";
2111db9f3b2SDimitry Andric   } else
2121db9f3b2SDimitry Andric     PrintFatalError(Predicate->getLoc(),
2131db9f3b2SDimitry Andric                     "Unsupported predicate for both instruction: " +
2141db9f3b2SDimitry Andric                         Predicate->getType()->getAsString());
2151db9f3b2SDimitry Andric }
2161db9f3b2SDimitry Andric 
2171db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
2181db9f3b2SDimitry Andric   // Emit file header.
2191db9f3b2SDimitry Andric   emitSourceFileHeader("Macro Fusion Predicators", OS);
2201db9f3b2SDimitry Andric 
2211db9f3b2SDimitry Andric   PredicateExpander PE(Target.getName());
2221db9f3b2SDimitry Andric   PE.setByRef(false);
2231db9f3b2SDimitry Andric   PE.setExpandForMC(false);
2241db9f3b2SDimitry Andric 
2251db9f3b2SDimitry Andric   std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
2261db9f3b2SDimitry Andric   // Sort macro fusions by name.
2271db9f3b2SDimitry Andric   sort(Fusions, LessRecord());
2281db9f3b2SDimitry Andric   emitMacroFusionDecl(Fusions, PE, OS);
2291db9f3b2SDimitry Andric   OS << "\n";
2301db9f3b2SDimitry Andric   emitMacroFusionImpl(Fusions, PE, OS);
2311db9f3b2SDimitry Andric }
2321db9f3b2SDimitry Andric 
2331db9f3b2SDimitry Andric static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
2341db9f3b2SDimitry Andric     X("gen-macro-fusion-pred", "Generate macro fusion predicators.");
235