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