Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
35258 views
//===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===---------------------------------------------------------------------===//7//8// MacroFusionPredicatorEmitter implements a TableGen-driven predicators9// generator for macro-op fusions.10//11// This TableGen backend processes `Fusion` definitions and generates12// predicators for checking if input instructions can be fused. These13// predicators can used in `MacroFusion` DAG mutation.14//15// The generated header file contains two parts: one for predicator16// declarations and one for predicator implementations. The user can get them17// by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or18// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated19// header file.20//21// The generated predicator will be like:22//23// ```24// bool isNAME(const TargetInstrInfo &TII,25// const TargetSubtargetInfo &STI,26// const MachineInstr *FirstMI,27// const MachineInstr &SecondMI) {28// auto &MRI = SecondMI.getMF()->getRegInfo();29// /* Predicates */30// return true;31// }32// ```33//34// The `Predicates` part is generated from a list of `FusionPredicate`, which35// can be predefined predicates, a raw code string or `MCInstPredicate` defined36// in TargetInstrPredicate.td.37//38//===---------------------------------------------------------------------===//3940#include "Common/CodeGenTarget.h"41#include "Common/PredicateExpander.h"42#include "llvm/Support/Debug.h"43#include "llvm/TableGen/Error.h"44#include "llvm/TableGen/Record.h"45#include "llvm/TableGen/TableGenBackend.h"46#include <vector>4748using namespace llvm;4950#define DEBUG_TYPE "macro-fusion-predicator"5152namespace {53class MacroFusionPredicatorEmitter {54RecordKeeper &Records;55CodeGenTarget Target;5657void emitMacroFusionDecl(ArrayRef<Record *> Fusions, PredicateExpander &PE,58raw_ostream &OS);59void emitMacroFusionImpl(ArrayRef<Record *> Fusions, PredicateExpander &PE,60raw_ostream &OS);61void emitPredicates(ArrayRef<Record *> FirstPredicate, bool IsCommutable,62PredicateExpander &PE, raw_ostream &OS);63void emitFirstPredicate(Record *SecondPredicate, bool IsCommutable,64PredicateExpander &PE, raw_ostream &OS);65void emitSecondPredicate(Record *SecondPredicate, bool IsCommutable,66PredicateExpander &PE, raw_ostream &OS);67void emitBothPredicate(Record *Predicates, bool IsCommutable,68PredicateExpander &PE, raw_ostream &OS);6970public:71MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {}7273void run(raw_ostream &OS);74};75} // End anonymous namespace.7677void MacroFusionPredicatorEmitter::emitMacroFusionDecl(78ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {79OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n";80OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n";81OS << "namespace llvm {\n";8283for (Record *Fusion : Fusions) {84OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, "85<< "const TargetSubtargetInfo &, "86<< "const MachineInstr *, "87<< "const MachineInstr &);\n";88}8990OS << "} // end namespace llvm\n";91OS << "\n#endif\n";92}9394void MacroFusionPredicatorEmitter::emitMacroFusionImpl(95ArrayRef<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) {96OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n";97OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n";98OS << "namespace llvm {\n";99100for (Record *Fusion : Fusions) {101std::vector<Record *> Predicates =102Fusion->getValueAsListOfDefs("Predicates");103bool IsCommutable = Fusion->getValueAsBit("IsCommutable");104105OS << "bool is" << Fusion->getName() << "(\n";106OS.indent(4) << "const TargetInstrInfo &TII,\n";107OS.indent(4) << "const TargetSubtargetInfo &STI,\n";108OS.indent(4) << "const MachineInstr *FirstMI,\n";109OS.indent(4) << "const MachineInstr &SecondMI) {\n";110OS.indent(2)111<< "[[maybe_unused]] auto &MRI = SecondMI.getMF()->getRegInfo();\n";112113emitPredicates(Predicates, IsCommutable, PE, OS);114115OS.indent(2) << "return true;\n";116OS << "}\n";117}118119OS << "} // end namespace llvm\n";120OS << "\n#endif\n";121}122123void MacroFusionPredicatorEmitter::emitPredicates(ArrayRef<Record *> Predicates,124bool IsCommutable,125PredicateExpander &PE,126raw_ostream &OS) {127for (Record *Predicate : Predicates) {128Record *Target = Predicate->getValueAsDef("Target");129if (Target->getName() == "first_fusion_target")130emitFirstPredicate(Predicate, IsCommutable, PE, OS);131else if (Target->getName() == "second_fusion_target")132emitSecondPredicate(Predicate, IsCommutable, PE, OS);133else if (Target->getName() == "both_fusion_target")134emitBothPredicate(Predicate, IsCommutable, PE, OS);135else136PrintFatalError(Target->getLoc(),137"Unsupported 'FusionTarget': " + Target->getName());138}139}140141void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,142bool IsCommutable,143PredicateExpander &PE,144raw_ostream &OS) {145if (Predicate->isSubClassOf("WildcardPred")) {146OS.indent(2) << "if (!FirstMI)\n";147OS.indent(2) << " return "148<< (Predicate->getValueAsBit("ReturnValue") ? "true" : "false")149<< ";\n";150} else if (Predicate->isSubClassOf("OneUsePred")) {151OS.indent(2) << "{\n";152OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n";153OS.indent(4)154<< "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";155OS.indent(4) << " return false;\n";156OS.indent(2) << "}\n";157} else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {158OS.indent(2) << "{\n";159OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";160OS.indent(4) << "if (";161PE.setNegatePredicate(true);162PE.setIndentLevel(3);163PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));164OS << ")\n";165OS.indent(4) << " return false;\n";166OS.indent(2) << "}\n";167} else {168PrintFatalError(Predicate->getLoc(),169"Unsupported predicate for first instruction: " +170Predicate->getType()->getAsString());171}172}173174void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,175bool IsCommutable,176PredicateExpander &PE,177raw_ostream &OS) {178if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {179OS.indent(2) << "{\n";180OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";181OS.indent(4) << "if (";182PE.setNegatePredicate(true);183PE.setIndentLevel(3);184PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate"));185OS << ")\n";186OS.indent(4) << " return false;\n";187OS.indent(2) << "}\n";188} else if (Predicate->isSubClassOf("SameReg")) {189int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");190int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");191192OS.indent(2) << "if (!SecondMI.getOperand(" << FirstOpIdx193<< ").getReg().isVirtual()) {\n";194OS.indent(4) << "if (SecondMI.getOperand(" << FirstOpIdx195<< ").getReg() != SecondMI.getOperand(" << SecondOpIdx196<< ").getReg())";197198if (IsCommutable) {199OS << " {\n";200OS.indent(6) << "if (!SecondMI.getDesc().isCommutable())\n";201OS.indent(6) << " return false;\n";202203OS.indent(6)204<< "unsigned SrcOpIdx1 = " << SecondOpIdx205<< ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";206OS.indent(6)207<< "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";208OS.indent(6)209<< " if (SecondMI.getOperand(" << FirstOpIdx210<< ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";211OS.indent(6) << " return false;\n";212OS.indent(4) << "}\n";213} else {214OS << "\n";215OS.indent(4) << " return false;\n";216}217OS.indent(2) << "}\n";218} else {219PrintFatalError(Predicate->getLoc(),220"Unsupported predicate for second instruction: " +221Predicate->getType()->getAsString());222}223}224225void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,226bool IsCommutable,227PredicateExpander &PE,228raw_ostream &OS) {229if (Predicate->isSubClassOf("FusionPredicateWithCode"))230OS << Predicate->getValueAsString("Predicate");231else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {232emitFirstPredicate(Predicate, IsCommutable, PE, OS);233emitSecondPredicate(Predicate, IsCommutable, PE, OS);234} else if (Predicate->isSubClassOf("TieReg")) {235int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");236int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");237OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx238<< ").isReg() &&\n";239OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx240<< ").isReg() &&\n";241OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx242<< ").getReg() == SecondMI.getOperand(" << SecondOpIdx243<< ").getReg()))";244245if (IsCommutable) {246OS << " {\n";247OS.indent(4) << "if (!SecondMI.getDesc().isCommutable())\n";248OS.indent(4) << " return false;\n";249250OS.indent(4)251<< "unsigned SrcOpIdx1 = " << SecondOpIdx252<< ", SrcOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;\n";253OS.indent(4)254<< "if (TII.findCommutedOpIndices(SecondMI, SrcOpIdx1, SrcOpIdx2))\n";255OS.indent(4)256<< " if (FirstMI->getOperand(" << FirstOpIdx257<< ").getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())\n";258OS.indent(4) << " return false;\n";259OS.indent(2) << "}";260} else {261OS << "\n";262OS.indent(2) << " return false;";263}264OS << "\n";265} else266PrintFatalError(Predicate->getLoc(),267"Unsupported predicate for both instruction: " +268Predicate->getType()->getAsString());269}270271void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {272// Emit file header.273emitSourceFileHeader("Macro Fusion Predicators", OS);274275PredicateExpander PE(Target.getName());276PE.setByRef(false);277PE.setExpandForMC(false);278279std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");280// Sort macro fusions by name.281sort(Fusions, LessRecord());282emitMacroFusionDecl(Fusions, PE, OS);283OS << "\n";284emitMacroFusionImpl(Fusions, PE, OS);285}286287static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>288X("gen-macro-fusion-pred", "Generate macro fusion predicators.");289290291