xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
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 
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 
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 
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 
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 
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 
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 
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