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