Skip to content

Conversation

@wangpc-pp
Copy link
Contributor

@wangpc-pp wangpc-pp commented Nov 14, 2023

FusionPredicate is used to predicate if target instruction matches
the requirement. The targets can be firstMI, secondMI or both.

The Fusion contains a list of FusionPredicate. The generated code
will be like:

bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Predicates */ return true; } 

A boilerplate class called SimpleFusion is added. SimpleFusion has
a predefined structure of predicates and accepts predicate for
firstMI, predicate for secondMI and epilog/prolog as arguments.
The generated code for SimpleFusion will be like:

bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Prolog */ /* Predicate for `SecondMI` */ /* Wildcard */ /* Predicate for `FirstMI` */ /* Check One Use */ /* Tie registers */ /* Epilog */ return true; } 
@llvmbot
Copy link
Member

llvmbot commented Nov 15, 2023

@llvm/pr-subscribers-backend-arm
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-backend-risc-v
@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-backend-amdgpu

Author: Wang Pengcheng (wangpc-pp)

Changes

The MacroFusion contains four predicates, which are for first MI,
second MI, prolog and epilog.

The generated code will be like:

bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Prolog */ /* Predicate for `FirstMI` */ /* Predicate for `SecondMI` */ /* Epilog */ return true; } 

The predicates of first/second MI can be any predicates defined in
TargetInstrPredicate.td


Patch is 22.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72222.diff

15 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/MacroFusion.h (+9-9)
  • (modified) llvm/include/llvm/Target/TargetInstrPredicate.td (+6)
  • (modified) llvm/include/llvm/Target/TargetSchedule.td (+61)
  • (modified) llvm/lib/CodeGen/MacroFusion.cpp (+27-12)
  • (modified) llvm/lib/Target/AArch64/AArch64MacroFusion.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUMacroFusion.cpp (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMMacroFusion.cpp (+2-2)
  • (modified) llvm/lib/Target/PowerPC/PPCMacroFusion.cpp (+2-2)
  • (modified) llvm/lib/Target/RISCV/RISCVMacroFusion.cpp (+1-1)
  • (modified) llvm/lib/Target/X86/X86MacroFusion.cpp (+2-3)
  • (modified) llvm/utils/TableGen/CMakeLists.txt (+1)
  • (added) llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp (+176)
  • (modified) llvm/utils/TableGen/PredicateExpander.cpp (+8)
  • (modified) llvm/utils/TableGen/PredicateExpander.h (+1)
diff --git a/llvm/include/llvm/CodeGen/MacroFusion.h b/llvm/include/llvm/CodeGen/MacroFusion.h index ea2c7a5faae385a..a97f776335368c7 100644 --- a/llvm/include/llvm/CodeGen/MacroFusion.h +++ b/llvm/include/llvm/CodeGen/MacroFusion.h @@ -14,8 +14,8 @@ #ifndef LLVM_CODEGEN_MACROFUSION_H #define LLVM_CODEGEN_MACROFUSION_H -#include <functional> #include <memory> +#include <vector> namespace llvm { @@ -29,10 +29,10 @@ class SUnit; /// Check if the instr pair, FirstMI and SecondMI, should be fused /// together. Given SecondMI, when FirstMI is unspecified, then check if /// SecondMI may be part of a fused pair at all. -using ShouldSchedulePredTy = std::function<bool(const TargetInstrInfo &TII, - const TargetSubtargetInfo &TSI, - const MachineInstr *FirstMI, - const MachineInstr &SecondMI)>; +using MacroFusionPredTy = bool (*)(const TargetInstrInfo &TII, + const TargetSubtargetInfo &STI, + const MachineInstr *FirstMI, + const MachineInstr &SecondMI); /// Checks if the number of cluster edges between SU and its predecessors is /// less than FuseLimit @@ -48,15 +48,15 @@ bool fuseInstructionPair(ScheduleDAGInstrs &DAG, SUnit &FirstSU, /// Create a DAG scheduling mutation to pair instructions back to back /// for instructions that benefit according to the target-specific -/// shouldScheduleAdjacent predicate function. +/// predicate functions. std::unique_ptr<ScheduleDAGMutation> -createMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent); +createMacroFusionDAGMutation(std::vector<MacroFusionPredTy> Predicates); /// Create a DAG scheduling mutation to pair branch instructions with one /// of their predecessors back to back for instructions that benefit according -/// to the target-specific shouldScheduleAdjacent predicate function. +/// to the target-specific predicate functions. std::unique_ptr<ScheduleDAGMutation> -createBranchMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent); +createBranchMacroFusionDAGMutation(std::vector<MacroFusionPredTy> Predicates); } // end namespace llvm diff --git a/llvm/include/llvm/Target/TargetInstrPredicate.td b/llvm/include/llvm/Target/TargetInstrPredicate.td index 9f2cde9d923050a..82c4c7b23a49b6a 100644 --- a/llvm/include/llvm/Target/TargetInstrPredicate.td +++ b/llvm/include/llvm/Target/TargetInstrPredicate.td @@ -95,6 +95,12 @@ class MCOperandPredicate<int Index> : MCInstPredicate { // Return true if machine operand at position `Index` is a register operand. class CheckIsRegOperand<int Index> : MCOperandPredicate<Index>; +// Return true if machine operand at position `Index` is a virtual register operand. +class CheckIsVRegOperand<int Index> : MCOperandPredicate<Index>; + +// Return true if machine operand at position `Index` is not a virtual register operand. +class CheckIsNotVRegOperand<int Index> : CheckNot<CheckIsVRegOperand<Index>>; + // Return true if machine operand at position `Index` is an immediate operand. class CheckIsImmOperand<int Index> : MCOperandPredicate<Index>; diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td index 949baa5d2105c45..699d35875b1fbdb 100644 --- a/llvm/include/llvm/Target/TargetSchedule.td +++ b/llvm/include/llvm/Target/TargetSchedule.td @@ -469,6 +469,67 @@ class SchedAlias<SchedReadWrite match, SchedReadWrite alias> { SchedMachineModel SchedModel = ?; } +// Base class of MacroFusionPredicate, etc. The avaliable variables are: +// * const TargetInstrInfo &TII +// * const TargetSubtargetInfo &STI +// * const MachineRegisterInfo &MRI +// * const MachineInstr *FirstMI +// * const MachineInstr &SecondMI +class MacroFusionPredicateBase; + +// MacroFusionPredicate with raw code predicate. +class MacroFusionPredicate<code pred> : MacroFusionPredicateBase { + code Predicate = pred; +} + +// Tie firstOpIdx and secondOpIdx. The operand of `FirstMI` at position +// `firstOpIdx` should be the same as the operand of `SenondMI` at position +// `secondOpIdx`. +class TieReg<int firstOpIdx, int secondOpIdx> : MacroFusionPredicateBase { + int FirstOpIdx = firstOpIdx; + int SecondOpIdx = secondOpIdx; +} + +// A predicate for wildcard. The generated code will be like: +// ``` +// if (!FirstMI) +// return ReturnValue; +// ``` +class WildcardPred<bit ret> : MacroFusionPredicateBase { + bit ReturnValue = ret; +} +def WildcardFalse : WildcardPred<0>; +def WildcardTrue : WildcardPred<1>; + +// Indicates that the destination register of `FirstMI` should be have one +// use if it is an virtual register. +class OneUsePred : MacroFusionPredicateBase; +def OneUse : OneUsePred; + +// Handled by MacroFusionPredicatorEmitter backend. +// The generated predicator will be like: +// ``` +// bool isNAME(const TargetInstrInfo &TII, +// const TargetSubtargetInfo &STI, +// const MachineInstr *FirstMI, +// const MachineInstr &SecondMI) { +// auto &MRI = SecondMI.getMF()->getRegInfo(); +// /* Prolog */ +// /* Predicate for `FirstMI` */ +// /* Predicate for `SecondMI` */ +// /* Epilog */ +// return true; +// } +// ``` +class MacroFusion<MCInstPredicate first, MCInstPredicate second, + list<MacroFusionPredicateBase> prolog = [], + list<MacroFusionPredicateBase> epilog = []> { + MCInstPredicate First = first; + MCInstPredicate Second = second; + list<MacroFusionPredicateBase> Prolog = prolog; + list<MacroFusionPredicateBase> Epilog = epilog; +} + // Allow the definition of processor register files for register renaming // purposes. // diff --git a/llvm/lib/CodeGen/MacroFusion.cpp b/llvm/lib/CodeGen/MacroFusion.cpp index fa5df68b8abcc0f..1ce2f49763b076f 100644 --- a/llvm/lib/CodeGen/MacroFusion.cpp +++ b/llvm/lib/CodeGen/MacroFusion.cpp @@ -137,19 +137,35 @@ namespace { /// Post-process the DAG to create cluster edges between instrs that may /// be fused by the processor into a single operation. class MacroFusion : public ScheduleDAGMutation { - ShouldSchedulePredTy shouldScheduleAdjacent; + std::vector<MacroFusionPredTy> Predicates; bool FuseBlock; bool scheduleAdjacentImpl(ScheduleDAGInstrs &DAG, SUnit &AnchorSU); public: - MacroFusion(ShouldSchedulePredTy shouldScheduleAdjacent, bool FuseBlock) - : shouldScheduleAdjacent(shouldScheduleAdjacent), FuseBlock(FuseBlock) {} + MacroFusion(std::vector<MacroFusionPredTy> Predicates, bool FuseBlock) + : Predicates(std::move(Predicates)), FuseBlock(FuseBlock) {} void apply(ScheduleDAGInstrs *DAGInstrs) override; + + bool shouldScheduleAdjacent(const TargetInstrInfo &TII, + const TargetSubtargetInfo &STI, + const MachineInstr *FirstMI, + const MachineInstr &SecondMI); }; } // end anonymous namespace +bool MacroFusion::shouldScheduleAdjacent(const TargetInstrInfo &TII, + const TargetSubtargetInfo &STI, + const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + for (MacroFusionPredTy Predicate : Predicates) { + if (Predicate(TII, STI, FirstMI, SecondMI)) + return true; + } + return false; +} + void MacroFusion::apply(ScheduleDAGInstrs *DAG) { if (FuseBlock) // For each of the SUnits in the scheduling block, try to fuse the instr in @@ -197,17 +213,16 @@ bool MacroFusion::scheduleAdjacentImpl(ScheduleDAGInstrs &DAG, SUnit &AnchorSU) } std::unique_ptr<ScheduleDAGMutation> -llvm::createMacroFusionDAGMutation( - ShouldSchedulePredTy shouldScheduleAdjacent) { - if(EnableMacroFusion) - return std::make_unique<MacroFusion>(shouldScheduleAdjacent, true); +llvm::createMacroFusionDAGMutation(std::vector<MacroFusionPredTy> Predicates) { + if (EnableMacroFusion) { + return std::make_unique<MacroFusion>(Predicates, true); + } return nullptr; } -std::unique_ptr<ScheduleDAGMutation> -llvm::createBranchMacroFusionDAGMutation( - ShouldSchedulePredTy shouldScheduleAdjacent) { - if(EnableMacroFusion) - return std::make_unique<MacroFusion>(shouldScheduleAdjacent, false); +std::unique_ptr<ScheduleDAGMutation> llvm::createBranchMacroFusionDAGMutation( + std::vector<MacroFusionPredTy> Predicates) { + if (EnableMacroFusion) + return std::make_unique<MacroFusion>(Predicates, false); return nullptr; } diff --git a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp index 05d60872bf51aca..8f46f3eabb3ef45 100644 --- a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp +++ b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp @@ -478,5 +478,5 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, std::unique_ptr<ScheduleDAGMutation> llvm::createAArch64MacroFusionDAGMutation() { - return createMacroFusionDAGMutation(shouldScheduleAdjacent); + return createMacroFusionDAGMutation({shouldScheduleAdjacent}); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMacroFusion.cpp b/llvm/lib/Target/AMDGPU/AMDGPUMacroFusion.cpp index c15c94ee17f8b1d..b2b11d661523e9c 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUMacroFusion.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUMacroFusion.cpp @@ -59,8 +59,8 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII_, namespace llvm { -std::unique_ptr<ScheduleDAGMutation> createAMDGPUMacroFusionDAGMutation () { - return createMacroFusionDAGMutation(shouldScheduleAdjacent); +std::unique_ptr<ScheduleDAGMutation> createAMDGPUMacroFusionDAGMutation() { + return createMacroFusionDAGMutation({shouldScheduleAdjacent}); } } // end namespace llvm diff --git a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp index 29c9b9ccf27614f..0bddeeef9e9b1a3 100644 --- a/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp +++ b/llvm/lib/Target/AMDGPU/GCNVOPDUtils.cpp @@ -142,10 +142,10 @@ namespace { /// be turned into VOPD instructions /// Greedily pairs instruction candidates. O(n^2) algorithm. struct VOPDPairingMutation : ScheduleDAGMutation { - ShouldSchedulePredTy shouldScheduleAdjacent; // NOLINT: function pointer + MacroFusionPredTy shouldScheduleAdjacent; // NOLINT: function pointer VOPDPairingMutation( - ShouldSchedulePredTy shouldScheduleAdjacent) // NOLINT: function pointer + MacroFusionPredTy shouldScheduleAdjacent) // NOLINT: function pointer : shouldScheduleAdjacent(shouldScheduleAdjacent) {} void apply(ScheduleDAGInstrs *DAG) override { diff --git a/llvm/lib/Target/ARM/ARMMacroFusion.cpp b/llvm/lib/Target/ARM/ARMMacroFusion.cpp index 38bf28ba8219b90..7de117925e464fe 100644 --- a/llvm/lib/Target/ARM/ARMMacroFusion.cpp +++ b/llvm/lib/Target/ARM/ARMMacroFusion.cpp @@ -62,8 +62,8 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, return false; } -std::unique_ptr<ScheduleDAGMutation> createARMMacroFusionDAGMutation () { - return createMacroFusionDAGMutation(shouldScheduleAdjacent); +std::unique_ptr<ScheduleDAGMutation> createARMMacroFusionDAGMutation() { + return createMacroFusionDAGMutation({shouldScheduleAdjacent}); } } // end namespace llvm diff --git a/llvm/lib/Target/PowerPC/PPCMacroFusion.cpp b/llvm/lib/Target/PowerPC/PPCMacroFusion.cpp index bf1c39a3a3a2d47..d6a4a5dd5faabae 100644 --- a/llvm/lib/Target/PowerPC/PPCMacroFusion.cpp +++ b/llvm/lib/Target/PowerPC/PPCMacroFusion.cpp @@ -286,8 +286,8 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, namespace llvm { -std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () { - return createMacroFusionDAGMutation(shouldScheduleAdjacent); +std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation() { + return createMacroFusionDAGMutation({shouldScheduleAdjacent}); } } // end namespace llvm diff --git a/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp b/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp index 02a8d5c18fe1a0e..1b82cc8b5b858f4 100644 --- a/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp +++ b/llvm/lib/Target/RISCV/RISCVMacroFusion.cpp @@ -65,5 +65,5 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, } std::unique_ptr<ScheduleDAGMutation> llvm::createRISCVMacroFusionDAGMutation() { - return createMacroFusionDAGMutation(shouldScheduleAdjacent); + return createMacroFusionDAGMutation({shouldScheduleAdjacent}); } diff --git a/llvm/lib/Target/X86/X86MacroFusion.cpp b/llvm/lib/Target/X86/X86MacroFusion.cpp index aa6e8645e0927f5..382cc9a71c2a184 100644 --- a/llvm/lib/Target/X86/X86MacroFusion.cpp +++ b/llvm/lib/Target/X86/X86MacroFusion.cpp @@ -67,9 +67,8 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, namespace llvm { -std::unique_ptr<ScheduleDAGMutation> -createX86MacroFusionDAGMutation () { - return createBranchMacroFusionDAGMutation(shouldScheduleAdjacent); +std::unique_ptr<ScheduleDAGMutation> createX86MacroFusionDAGMutation() { + return createBranchMacroFusionDAGMutation({shouldScheduleAdjacent}); } } // end namespace llvm diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt index 071ea3bc07054bb..f765cc36d3bebed 100644 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -72,6 +72,7 @@ add_tablegen(llvm-tblgen LLVM PredicateExpander.cpp PseudoLoweringEmitter.cpp CompressInstEmitter.cpp + MacroFusionPredicatorEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp SearchableTableEmitter.cpp diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp new file mode 100644 index 000000000000000..28a12a5c857603f --- /dev/null +++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp @@ -0,0 +1,176 @@ +//===--- MacroFusionPredicatorEmitter.cpp - Generator for MacroFusion ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// MacroFusionPredicatorEmitter implements a TableGen-driven predicators +// generator for MacroFusion. +// +//===---------------------------------------------------------------------===// + +#include "CodeGenTarget.h" +#include "PredicateExpander.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <set> +#include <vector> + +using namespace llvm; + +#define DEBUG_TYPE "macro-fusion-predicator" + +namespace { +class MacroFusionPredicatorEmitter { + RecordKeeper &Records; + CodeGenTarget Target; + + void emitMacroFusionDecl(std::vector<Record *> MacroFusions, + PredicateExpander &PE, raw_ostream &OS); + void emitMacroFusionImpl(std::vector<Record *> MacroFusions, + PredicateExpander &PE, raw_ostream &OS); + void emitFirstPredicate(Record *FirstPredicate, PredicateExpander &PE, + raw_ostream &OS); + void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE, + raw_ostream &OS); + void emitPrologAndEpilog(std::vector<Record *> Predicates, + PredicateExpander &PE, raw_ostream &OS); + +public: + MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {} + + void run(raw_ostream &OS); +}; +} // End anonymous namespace. + +void MacroFusionPredicatorEmitter::emitMacroFusionDecl( + std::vector<Record *> MacroFusions, PredicateExpander &PE, + raw_ostream &OS) { + OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n"; + + for (Record *MacroFusion : MacroFusions) { + OS << "bool is" << MacroFusion->getName() << "(const TargetInstrInfo &, " + << "const TargetSubtargetInfo &, " << "const MachineInstr *, " + << "const MachineInstr &);\n"; + } + + OS << "\n#endif\n"; + OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n"; +} + +void MacroFusionPredicatorEmitter::emitMacroFusionImpl( + std::vector<Record *> MacroFusions, PredicateExpander &PE, + raw_ostream &OS) { + OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n"; + + for (Record *MacroFusion : MacroFusions) { + Record *First = MacroFusion->getValueAsDef("First"); + Record *Second = MacroFusion->getValueAsDef("Second"); + std::vector<Record *> Prolog = MacroFusion->getValueAsListOfDefs("Prolog"); + std::vector<Record *> Epilog = MacroFusion->getValueAsListOfDefs("Epilog"); + + OS << "bool is" << MacroFusion->getName() << "(\n"; + OS.indent(5) << "const TargetInstrInfo &TII,\n"; + OS.indent(5) << "const TargetSubtargetInfo &STI,\n"; + OS.indent(5) << "const MachineInstr *FirstMI,\n"; + OS.indent(5) << "const MachineInstr &SecondMI) {\n"; + OS.indent(2) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n"; + + emitFirstPredicate(First, PE, OS); + emitSecondPredicate(Second, PE, OS); + + if (!Prolog.empty()) + emitPrologAndEpilog(Prolog, PE, OS); + + OS.indent(2) << "if (!matchFirst(FirstMI))\n"; + OS.indent(2) << " return false;\n"; + OS.indent(2) << "if (!matchSecond(&SecondMI))\n"; + OS.indent(2) << " return false;\n"; + + if (!Epilog.empty()) + emitPrologAndEpilog(Epilog, PE, OS); + + OS.indent(2) << "return true;\n"; + OS << "}\n"; + } + + OS << "\n#endif\n"; + OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n"; +} + +void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *FirstPredicate, + PredicateExpander &PE, + raw_ostream &OS) { + + OS.indent(2) << "auto matchFirst = [&](const MachineInstr *MI) {\n"; + OS.indent(4) << "return "; + PE.expandPredicate(OS, FirstPredicate); + OS << ";\n"; + OS.indent(2) << "};\n"; +} + +void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *SecondPredicate, + PredicateExpander &PE, + raw_ostream &OS) { + OS.indent(2) << "auto matchSecond = [&](const MachineInstr *MI) {\n"; + OS.indent(4) << "return "; + PE.expandPredicate(OS, SecondPredicate); + OS << ";\n"; + OS.indent(2) << "};\n"; +} + +void MacroFusionPredicatorEmitter::emitPrologAndEpilog( + std::vector<Record *> Predicates, PredicateExpander &PE, raw_ostream &OS) { + for (auto *Predicate : Predicates) { + if (Predicate->isSubClassOf("MacroFusionPredicate")) + OS << Predicate->getValueAsString("Predicate"); + else if (Predicate->isSubClassOf("WildcardPred")) { + OS.indent(2) << "if (!FirstMI)\n"; + OS.indent(2) << " return " + << (Predicate->getValueAsBit("ReturnValue") ? "true" + : "false") + << ";\n"; + } else if (Predicate->isSubClassOf("OneUsePred")) { + OS.indent(2) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n"; + OS.indent(2) + << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n"; + OS.indent(2) << " return false;\n"; + } else if (Predicate->isSubClassOf("TieReg")) { + int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx"); + int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx"); + OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx + << ").isReg() &&\n"; + OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx + << ").isReg() &&\n"; + OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx + << ").getReg() == SecondMI.getOperand(" << SecondOpIdx + << ").isReg()))\n"; + OS.indent(2) << " return false;\n"; + } else + PrintFatalError(Predicate->getLoc(), + "Unsupported subclass of 'MacroFusionPredicateBase':" + + Predicate->getType()->getAsString()); + } +} + +void MacroFusionPredicatorEmitter::run(raw_ostream &OS) { + // Emit file header. + emitSourceFileHeade... [truncated] 
@github-actions
Copy link

github-actions bot commented Nov 15, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@wangpc-pp wangpc-pp force-pushed the main-tablegen-macro-fusion-predicators branch from a6d97ed to ead0fdf Compare November 15, 2023 06:37
@wangpc-pp wangpc-pp force-pushed the main-tablegen-macro-fusion-predicators branch from ead0fdf to 77908a1 Compare November 20, 2023 03:46
Copy link
Contributor

@Sisyph Sisyph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the approach. It seems quite powerful and useful.

Copy link
Member

@mshockwave mshockwave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add TableGen tests?

Copy link
Contributor

@Pierre-vh Pierre-vh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not part of the review but adding some nits/comments.

I also think it would be nice if this backend had at least one test to track the expected codegen, and see codegen changes. It makes future maintenance a lot easier if we can see what changes do to codegen during a review.

@wangpc-pp wangpc-pp force-pushed the main-tablegen-macro-fusion-predicators branch 2 times, most recently from 087f84e to 8b1c64a Compare November 21, 2023 08:25
wangpc-pp added a commit to wangpc-pp/llvm-project that referenced this pull request Nov 21, 2023
Doc: https://xiangshan-doc.readthedocs.io/zh-cn/latest/frontend/decode/ This PR is to show the usage of TableGen-based macro fusions. Some instrcution pairs can be folded into one MacroFusion definition but I leave them standalone to show the different ways to define a macro fusion. This PR is stacked on llvm#72219, llvm#72222, llvm#72223, llvm#72224, llvm#72227
wangpc-pp added a commit to wangpc-pp/llvm-project that referenced this pull request Nov 22, 2023
We add an option `-mfusion` like `-mattr` to add/remove supported macro fusions, so that we can test each macro fusion separately via `llc`. This PR is stacked on llvm#72219, llvm#72222, llvm#72223
@wangpc-pp wangpc-pp force-pushed the main-tablegen-macro-fusion-predicators branch from 8b1c64a to ed638ba Compare November 22, 2023 12:37
@wangpc-pp wangpc-pp force-pushed the main-tablegen-macro-fusion-predicators branch from ed638ba to 3512239 Compare December 8, 2023 10:20
@wangpc-pp
Copy link
Contributor Author

Could you also add TableGen tests?

I have added a test, thanks!

@wangpc-pp
Copy link
Contributor Author

Ping.

`FusionPredicate` is used to predicate if target instruction matches the requirement. The targets can be firstMI, secondMI or both. The `Fusion` contains a list of `FusionPredicate`. The generated code will be like: ``` bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Predicates */ return true; } ``` A boilerplate class called `SimpleFusion` is added. `SimpleFusion` has a predefined structure of predicates and accepts predicate for `firstMI`, predicate for `secondMI` and epilog/prolog as arguments. The generated code for `SimpleFusion` will be like: ``` bool isNAME(const TargetInstrInfo &TII, const TargetSubtargetInfo &STI, const MachineInstr *FirstMI, const MachineInstr &SecondMI) { auto &MRI = SecondMI.getMF()->getRegInfo(); /* Prolog */ /* Predicate for `SecondMI` */ /* Wildcard */ /* Predicate for `FirstMI` */ /* Check One Use */ /* Tie registers */ /* Epilog */ return true; } ```
@wangpc-pp wangpc-pp force-pushed the main-tablegen-macro-fusion-predicators branch from 3512239 to 8eb4285 Compare December 19, 2023 11:03
@wangpc-pp
Copy link
Contributor Author

I will land this at this Friday if there is no more comment. :-)

@wangpc-pp wangpc-pp merged commit a0e6b7c into llvm:main Jan 5, 2024
@wangpc-pp wangpc-pp deleted the main-tablegen-macro-fusion-predicators branch January 5, 2024 14:44
wangpc-pp added a commit to wangpc-pp/llvm-project that referenced this pull request Jan 30, 2024
Doc: https://xiangshan-doc.readthedocs.io/zh-cn/latest/frontend/decode/ This PR is to show the usage of TableGen-based macro fusions. Some instrcution pairs can be folded into one MacroFusion definition but I leave them standalone to show the different ways to define a macro fusion. This PR is stacked on llvm#72219, llvm#72222, llvm#72223, llvm#72224, llvm#72227
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

7 participants