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