1*1db9f3b2SDimitry Andric //===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===// 2*1db9f3b2SDimitry Andric // 3*1db9f3b2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*1db9f3b2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*1db9f3b2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*1db9f3b2SDimitry Andric // 7*1db9f3b2SDimitry Andric //===---------------------------------------------------------------------===// 8*1db9f3b2SDimitry Andric // 9*1db9f3b2SDimitry Andric // MacroFusionPredicatorEmitter implements a TableGen-driven predicators 10*1db9f3b2SDimitry Andric // generator for macro-op fusions. 11*1db9f3b2SDimitry Andric // 12*1db9f3b2SDimitry Andric // This TableGen backend processes `Fusion` definitions and generates 13*1db9f3b2SDimitry Andric // predicators for checking if input instructions can be fused. These 14*1db9f3b2SDimitry Andric // predicators can used in `MacroFusion` DAG mutation. 15*1db9f3b2SDimitry Andric // 16*1db9f3b2SDimitry Andric // The generated header file contains two parts: one for predicator 17*1db9f3b2SDimitry Andric // declarations and one for predicator implementations. The user can get them 18*1db9f3b2SDimitry Andric // by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or 19*1db9f3b2SDimitry Andric // `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated 20*1db9f3b2SDimitry Andric // header file. 21*1db9f3b2SDimitry Andric // 22*1db9f3b2SDimitry Andric // The generated predicator will be like: 23*1db9f3b2SDimitry Andric // 24*1db9f3b2SDimitry Andric // ``` 25*1db9f3b2SDimitry Andric // bool isNAME(const TargetInstrInfo &TII, 26*1db9f3b2SDimitry Andric // const TargetSubtargetInfo &STI, 27*1db9f3b2SDimitry Andric // const MachineInstr *FirstMI, 28*1db9f3b2SDimitry Andric // const MachineInstr &SecondMI) { 29*1db9f3b2SDimitry Andric // auto &MRI = SecondMI.getMF()->getRegInfo(); 30*1db9f3b2SDimitry Andric // /* Predicates */ 31*1db9f3b2SDimitry Andric // return true; 32*1db9f3b2SDimitry Andric // } 33*1db9f3b2SDimitry Andric // ``` 34*1db9f3b2SDimitry Andric // 35*1db9f3b2SDimitry Andric // The `Predicates` part is generated from a list of `FusionPredicate`, which 36*1db9f3b2SDimitry Andric // can be predefined predicates, a raw code string or `MCInstPredicate` defined 37*1db9f3b2SDimitry Andric // in TargetInstrPredicate.td. 38*1db9f3b2SDimitry Andric // 39*1db9f3b2SDimitry Andric //===---------------------------------------------------------------------===// 40*1db9f3b2SDimitry Andric 41*1db9f3b2SDimitry Andric #include "CodeGenTarget.h" 42*1db9f3b2SDimitry Andric #include "PredicateExpander.h" 43*1db9f3b2SDimitry Andric #include "llvm/ADT/SmallVector.h" 44*1db9f3b2SDimitry Andric #include "llvm/Support/Debug.h" 45*1db9f3b2SDimitry Andric #include "llvm/TableGen/Error.h" 46*1db9f3b2SDimitry Andric #include "llvm/TableGen/Record.h" 47*1db9f3b2SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 48*1db9f3b2SDimitry Andric #include <set> 49*1db9f3b2SDimitry Andric #include <vector> 50*1db9f3b2SDimitry Andric 51*1db9f3b2SDimitry Andric using namespace llvm; 52*1db9f3b2SDimitry Andric 53*1db9f3b2SDimitry Andric #define DEBUG_TYPE "macro-fusion-predicator" 54*1db9f3b2SDimitry Andric 55*1db9f3b2SDimitry Andric namespace { 56*1db9f3b2SDimitry Andric class MacroFusionPredicatorEmitter { 57*1db9f3b2SDimitry Andric RecordKeeper &Records; 58*1db9f3b2SDimitry Andric CodeGenTarget Target; 59*1db9f3b2SDimitry Andric 60*1db9f3b2SDimitry Andric void emitMacroFusionDecl(std::vector<Record *> Fusions, PredicateExpander &PE, 61*1db9f3b2SDimitry Andric raw_ostream &OS); 62*1db9f3b2SDimitry Andric void emitMacroFusionImpl(std::vector<Record *> Fusions, PredicateExpander &PE, 63*1db9f3b2SDimitry Andric raw_ostream &OS); 64*1db9f3b2SDimitry Andric void emitPredicates(std::vector<Record *> &FirstPredicate, 65*1db9f3b2SDimitry Andric PredicateExpander &PE, raw_ostream &OS); 66*1db9f3b2SDimitry Andric void emitFirstPredicate(Record *SecondPredicate, PredicateExpander &PE, 67*1db9f3b2SDimitry Andric raw_ostream &OS); 68*1db9f3b2SDimitry Andric void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE, 69*1db9f3b2SDimitry Andric raw_ostream &OS); 70*1db9f3b2SDimitry Andric void emitBothPredicate(Record *Predicates, PredicateExpander &PE, 71*1db9f3b2SDimitry Andric raw_ostream &OS); 72*1db9f3b2SDimitry Andric 73*1db9f3b2SDimitry Andric public: 74*1db9f3b2SDimitry Andric MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {} 75*1db9f3b2SDimitry Andric 76*1db9f3b2SDimitry Andric void run(raw_ostream &OS); 77*1db9f3b2SDimitry Andric }; 78*1db9f3b2SDimitry Andric } // End anonymous namespace. 79*1db9f3b2SDimitry Andric 80*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionDecl( 81*1db9f3b2SDimitry Andric std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { 82*1db9f3b2SDimitry Andric OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n"; 83*1db9f3b2SDimitry Andric OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n"; 84*1db9f3b2SDimitry Andric OS << "namespace llvm {\n"; 85*1db9f3b2SDimitry Andric 86*1db9f3b2SDimitry Andric for (Record *Fusion : Fusions) { 87*1db9f3b2SDimitry Andric OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, " 88*1db9f3b2SDimitry Andric << "const TargetSubtargetInfo &, " 89*1db9f3b2SDimitry Andric << "const MachineInstr *, " 90*1db9f3b2SDimitry Andric << "const MachineInstr &);\n"; 91*1db9f3b2SDimitry Andric } 92*1db9f3b2SDimitry Andric 93*1db9f3b2SDimitry Andric OS << "} // end namespace llvm\n"; 94*1db9f3b2SDimitry Andric OS << "\n#endif\n"; 95*1db9f3b2SDimitry Andric } 96*1db9f3b2SDimitry Andric 97*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitMacroFusionImpl( 98*1db9f3b2SDimitry Andric std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { 99*1db9f3b2SDimitry Andric OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n"; 100*1db9f3b2SDimitry Andric OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n"; 101*1db9f3b2SDimitry Andric OS << "namespace llvm {\n"; 102*1db9f3b2SDimitry Andric 103*1db9f3b2SDimitry Andric for (Record *Fusion : Fusions) { 104*1db9f3b2SDimitry Andric std::vector<Record *> Predicates = 105*1db9f3b2SDimitry Andric Fusion->getValueAsListOfDefs("Predicates"); 106*1db9f3b2SDimitry Andric 107*1db9f3b2SDimitry Andric OS << "bool is" << Fusion->getName() << "(\n"; 108*1db9f3b2SDimitry Andric OS.indent(4) << "const TargetInstrInfo &TII,\n"; 109*1db9f3b2SDimitry Andric OS.indent(4) << "const TargetSubtargetInfo &STI,\n"; 110*1db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr *FirstMI,\n"; 111*1db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr &SecondMI) {\n"; 112*1db9f3b2SDimitry Andric OS.indent(2) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n"; 113*1db9f3b2SDimitry Andric 114*1db9f3b2SDimitry Andric emitPredicates(Predicates, PE, OS); 115*1db9f3b2SDimitry Andric 116*1db9f3b2SDimitry Andric OS.indent(2) << "return true;\n"; 117*1db9f3b2SDimitry Andric OS << "}\n"; 118*1db9f3b2SDimitry Andric } 119*1db9f3b2SDimitry Andric 120*1db9f3b2SDimitry Andric OS << "} // end namespace llvm\n"; 121*1db9f3b2SDimitry Andric OS << "\n#endif\n"; 122*1db9f3b2SDimitry Andric } 123*1db9f3b2SDimitry Andric 124*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitPredicates( 125*1db9f3b2SDimitry Andric std::vector<Record *> &Predicates, PredicateExpander &PE, raw_ostream &OS) { 126*1db9f3b2SDimitry Andric for (Record *Predicate : Predicates) { 127*1db9f3b2SDimitry Andric Record *Target = Predicate->getValueAsDef("Target"); 128*1db9f3b2SDimitry Andric if (Target->getName() == "first_fusion_target") 129*1db9f3b2SDimitry Andric emitFirstPredicate(Predicate, PE, OS); 130*1db9f3b2SDimitry Andric else if (Target->getName() == "second_fusion_target") 131*1db9f3b2SDimitry Andric emitSecondPredicate(Predicate, PE, OS); 132*1db9f3b2SDimitry Andric else if (Target->getName() == "both_fusion_target") 133*1db9f3b2SDimitry Andric emitBothPredicate(Predicate, PE, OS); 134*1db9f3b2SDimitry Andric else 135*1db9f3b2SDimitry Andric PrintFatalError(Target->getLoc(), 136*1db9f3b2SDimitry Andric "Unsupported 'FusionTarget': " + Target->getName()); 137*1db9f3b2SDimitry Andric } 138*1db9f3b2SDimitry Andric } 139*1db9f3b2SDimitry Andric 140*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate, 141*1db9f3b2SDimitry Andric PredicateExpander &PE, 142*1db9f3b2SDimitry Andric raw_ostream &OS) { 143*1db9f3b2SDimitry Andric if (Predicate->isSubClassOf("WildcardPred")) { 144*1db9f3b2SDimitry Andric OS.indent(2) << "if (!FirstMI)\n"; 145*1db9f3b2SDimitry Andric OS.indent(2) << " return " 146*1db9f3b2SDimitry Andric << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false") 147*1db9f3b2SDimitry Andric << ";\n"; 148*1db9f3b2SDimitry Andric } else if (Predicate->isSubClassOf("OneUsePred")) { 149*1db9f3b2SDimitry Andric OS.indent(2) << "{\n"; 150*1db9f3b2SDimitry Andric OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n"; 151*1db9f3b2SDimitry Andric OS.indent(4) 152*1db9f3b2SDimitry Andric << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n"; 153*1db9f3b2SDimitry Andric OS.indent(4) << " return false;\n"; 154*1db9f3b2SDimitry Andric OS.indent(2) << "}\n"; 155*1db9f3b2SDimitry Andric } else if (Predicate->isSubClassOf( 156*1db9f3b2SDimitry Andric "FirstFusionPredicateWithMCInstPredicate")) { 157*1db9f3b2SDimitry Andric OS.indent(2) << "{\n"; 158*1db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr *MI = FirstMI;\n"; 159*1db9f3b2SDimitry Andric OS.indent(4) << "if ("; 160*1db9f3b2SDimitry Andric PE.setNegatePredicate(true); 161*1db9f3b2SDimitry Andric PE.setIndentLevel(3); 162*1db9f3b2SDimitry Andric PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate")); 163*1db9f3b2SDimitry Andric OS << ")\n"; 164*1db9f3b2SDimitry Andric OS.indent(4) << " return false;\n"; 165*1db9f3b2SDimitry Andric OS.indent(2) << "}\n"; 166*1db9f3b2SDimitry Andric } else { 167*1db9f3b2SDimitry Andric PrintFatalError(Predicate->getLoc(), 168*1db9f3b2SDimitry Andric "Unsupported predicate for first instruction: " + 169*1db9f3b2SDimitry Andric Predicate->getType()->getAsString()); 170*1db9f3b2SDimitry Andric } 171*1db9f3b2SDimitry Andric } 172*1db9f3b2SDimitry Andric 173*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate, 174*1db9f3b2SDimitry Andric PredicateExpander &PE, 175*1db9f3b2SDimitry Andric raw_ostream &OS) { 176*1db9f3b2SDimitry Andric if (Predicate->isSubClassOf("SecondFusionPredicateWithMCInstPredicate")) { 177*1db9f3b2SDimitry Andric OS.indent(2) << "{\n"; 178*1db9f3b2SDimitry Andric OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n"; 179*1db9f3b2SDimitry Andric OS.indent(4) << "if ("; 180*1db9f3b2SDimitry Andric PE.setNegatePredicate(true); 181*1db9f3b2SDimitry Andric PE.setIndentLevel(3); 182*1db9f3b2SDimitry Andric PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate")); 183*1db9f3b2SDimitry Andric OS << ")\n"; 184*1db9f3b2SDimitry Andric OS.indent(4) << " return false;\n"; 185*1db9f3b2SDimitry Andric OS.indent(2) << "}\n"; 186*1db9f3b2SDimitry Andric } else { 187*1db9f3b2SDimitry Andric PrintFatalError(Predicate->getLoc(), 188*1db9f3b2SDimitry Andric "Unsupported predicate for first instruction: " + 189*1db9f3b2SDimitry Andric Predicate->getType()->getAsString()); 190*1db9f3b2SDimitry Andric } 191*1db9f3b2SDimitry Andric } 192*1db9f3b2SDimitry Andric 193*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate, 194*1db9f3b2SDimitry Andric PredicateExpander &PE, 195*1db9f3b2SDimitry Andric raw_ostream &OS) { 196*1db9f3b2SDimitry Andric if (Predicate->isSubClassOf("FusionPredicateWithCode")) 197*1db9f3b2SDimitry Andric OS << Predicate->getValueAsString("Predicate"); 198*1db9f3b2SDimitry Andric else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) { 199*1db9f3b2SDimitry Andric Record *MCPred = Predicate->getValueAsDef("Predicate"); 200*1db9f3b2SDimitry Andric emitFirstPredicate(MCPred, PE, OS); 201*1db9f3b2SDimitry Andric emitSecondPredicate(MCPred, PE, OS); 202*1db9f3b2SDimitry Andric } else if (Predicate->isSubClassOf("TieReg")) { 203*1db9f3b2SDimitry Andric int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx"); 204*1db9f3b2SDimitry Andric int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx"); 205*1db9f3b2SDimitry Andric OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx 206*1db9f3b2SDimitry Andric << ").isReg() &&\n"; 207*1db9f3b2SDimitry Andric OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx 208*1db9f3b2SDimitry Andric << ").isReg() &&\n"; 209*1db9f3b2SDimitry Andric OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx 210*1db9f3b2SDimitry Andric << ").getReg() == SecondMI.getOperand(" << SecondOpIdx 211*1db9f3b2SDimitry Andric << ").getReg()))\n"; 212*1db9f3b2SDimitry Andric OS.indent(2) << " return false;\n"; 213*1db9f3b2SDimitry Andric } else 214*1db9f3b2SDimitry Andric PrintFatalError(Predicate->getLoc(), 215*1db9f3b2SDimitry Andric "Unsupported predicate for both instruction: " + 216*1db9f3b2SDimitry Andric Predicate->getType()->getAsString()); 217*1db9f3b2SDimitry Andric } 218*1db9f3b2SDimitry Andric 219*1db9f3b2SDimitry Andric void MacroFusionPredicatorEmitter::run(raw_ostream &OS) { 220*1db9f3b2SDimitry Andric // Emit file header. 221*1db9f3b2SDimitry Andric emitSourceFileHeader("Macro Fusion Predicators", OS); 222*1db9f3b2SDimitry Andric 223*1db9f3b2SDimitry Andric PredicateExpander PE(Target.getName()); 224*1db9f3b2SDimitry Andric PE.setByRef(false); 225*1db9f3b2SDimitry Andric PE.setExpandForMC(false); 226*1db9f3b2SDimitry Andric 227*1db9f3b2SDimitry Andric std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion"); 228*1db9f3b2SDimitry Andric // Sort macro fusions by name. 229*1db9f3b2SDimitry Andric sort(Fusions, LessRecord()); 230*1db9f3b2SDimitry Andric emitMacroFusionDecl(Fusions, PE, OS); 231*1db9f3b2SDimitry Andric OS << "\n"; 232*1db9f3b2SDimitry Andric emitMacroFusionImpl(Fusions, PE, OS); 233*1db9f3b2SDimitry Andric } 234*1db9f3b2SDimitry Andric 235*1db9f3b2SDimitry Andric static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter> 236*1db9f3b2SDimitry Andric X("gen-macro-fusion-pred", "Generate macro fusion predicators."); 237