[llvm] 18fc5a8 - [TableGen][RISCV] Generate pre/post-RA statistics for macro fusions (#209394)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 05:12:21 PDT 2026
Author: Pengcheng Wang
Date: 2026-07-16T12:12:15Z
New Revision: 18fc5a8adbe5dba7dc281bacdb149e95dc7dc1be
URL: https://github.com/llvm/llvm-project/commit/18fc5a8adbe5dba7dc281bacdb149e95dc7dc1be
DIFF: https://github.com/llvm/llvm-project/commit/18fc5a8adbe5dba7dc281bacdb149e95dc7dc1be.diff
LOG: [TableGen][RISCV] Generate pre/post-RA statistics for macro fusions (#209394)
Teach `MacroFusionPredicatorEmitter` to emit `Statistic` counters
recording how often each macro fusion is matched, and wire them
up for RISC-V.
This is based on the idea in #186499, generalized so counters are
generated automatically for any target using the emitter.
Because both the pre-RA and post-RA schedulers run MacroFusion,
a single counter would conflate the two. Counters are split into
pre-RA/post-RA variants, distinguished by the `NoVRegs` property,
addressing the double-counting concern from #186499:
```cpp
STATISTIC(NumTuneLDADDFusionPreRA, "Times TuneLDADDFusion Triggered (pre-ra)");
STATISTIC(NumTuneLDADDFusionPostRA, "Times TuneLDADDFusion Triggered (post-ra)");
...
if (SecondMI.getMF()->getProperties().hasNoVRegs())
++NumTuneLDADDFusionPostRA;
else
++NumTuneLDADDFusionPreRA;
```
Besides, RISC-V counters use the `riscv-macro-fusion` debug type.
Co-authored-by: Sam Elliott <aelliott at qti.qualcomm.com>
Assisted-by: TRAE CLI (DeepSeek V4 Pro)
Added:
Modified:
llvm/lib/Target/RISCV/RISCVSubtarget.cpp
llvm/test/TableGen/MacroFusion.td
llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index 0ba474abd4481..319dbdd03fb79 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -18,6 +18,7 @@
#include "RISCVFrameLowering.h"
#include "RISCVSelectionDAGInfo.h"
#include "RISCVTargetMachine.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/MC/MCSchedule.h"
#include "llvm/MC/TargetRegistry.h"
@@ -39,15 +40,18 @@ static cl::opt<unsigned> SchedLoadLatency(
cl::desc("Override the load latency (in cycles) in the scheduler model. "
"A non-negative value overrides the target default."));
+#define DEBUG_TYPE "riscv-macro-fusion"
+
+#define GET_RISCV_MACRO_FUSION_PRED_IMPL
+#include "RISCVGenMacroFusion.inc"
+
+#undef DEBUG_TYPE
#define DEBUG_TYPE "riscv-subtarget"
#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "RISCVGenSubtargetInfo.inc"
-#define GET_RISCV_MACRO_FUSION_PRED_IMPL
-#include "RISCVGenMacroFusion.inc"
-
namespace llvm::RISCVTuneInfoTable {
#define GET_RISCVTuneInfoTable_IMPL
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index 8fd823184a2b1..64c0885874e71 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -82,12 +82,15 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: } // namespace llvm
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: #endif // GET_Test_MACRO_FUSION_PRED_DECL
-
-// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_IMPL
+// CHECK-PREDICATOR-EMPTY:
+// CHECK-PREDICATOR-EMPTY:
+// CHECK-PREDICATOR-NEXT: #ifdef GET_Test_MACRO_FUSION_PRED_IMPL
// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_IMPL
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: namespace llvm {
// CHECK-PREDICATOR-EMPTY:
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestBothFusionPredicatePreRA, "Times TestBothFusionPredicate Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestBothFusionPredicatePostRA, "Times TestBothFusionPredicate Triggered (post-ra)");
// CHECK-PREDICATOR-NEXT: bool isTestBothFusionPredicate(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
@@ -95,17 +98,23 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = FirstMI;
// CHECK-PREDICATOR-NEXT: if (MI->getOperand(0).getReg() != Test::X0)
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
// CHECK-PREDICATOR-NEXT: if (MI->getOperand(0).getReg() != Test::X0)
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestBothFusionPredicatePostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestBothFusionPredicatePreRA;
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestCommutableFusionPreRA, "Times TestCommutableFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestCommutableFusionPostRA, "Times TestCommutableFusion Triggered (post-ra)");
// CHECK-PREDICATOR-NEXT: bool isTestCommutableFusion(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
@@ -113,7 +122,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
// CHECK-PREDICATOR-NEXT: if (!(
// CHECK-PREDICATOR-NEXT: ( MI->getOpcode() == Test::Inst1 )
// CHECK-PREDICATOR-NEXT: && MI->getOperand(0).getReg() == Test::X0
@@ -123,7 +132,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: if (!FirstMI)
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = FirstMI;
// CHECK-PREDICATOR-NEXT: if (( MI->getOpcode() != Test::Inst0 ))
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
@@ -152,8 +161,14 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: if (FirstMI->getOperand(0).getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestCommutableFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestCommutableFusionPreRA;
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFirstSameRegFusionPreRA, "Times TestFirstSameRegFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFirstSameRegFusionPostRA, "Times TestFirstSameRegFusion Triggered (post-ra)");
// CHECK-PREDICATOR-NEXT: bool isTestFirstSameRegFusion(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
@@ -170,8 +185,14 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestFirstSameRegFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestFirstSameRegFusionPreRA;
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFusionPreRA, "Times TestFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFusionPostRA, "Times TestFusion Triggered (post-ra)");
// CHECK-PREDICATOR-NEXT: bool isTestFusion(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
@@ -179,7 +200,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
// CHECK-PREDICATOR-NEXT: if (!(
// CHECK-PREDICATOR-NEXT: ( MI->getOpcode() == Test::Inst1 )
// CHECK-PREDICATOR-NEXT: && MI->getOperand(0).getReg() == Test::X0
@@ -189,7 +210,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: if (!FirstMI)
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = FirstMI;
// CHECK-PREDICATOR-NEXT: if (!llvm::is_contained({Test::Inst0, Test::Inst1}, MI->getOpcode()))
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
@@ -206,8 +227,14 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: SecondMI.getOperand(1).isReg() &&
// CHECK-PREDICATOR-NEXT: FirstMI->getOperand(0).getReg() == SecondMI.getOperand(1).getReg()))
// CHECK-PREDICATOR-NEXT: return false;
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestFusionPreRA;
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestSingleFusionPreRA, "Times TestSingleFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestSingleFusionPostRA, "Times TestSingleFusion Triggered (post-ra)");
// CHECK-PREDICATOR-NEXT: bool isTestSingleFusion(
// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
@@ -215,7 +242,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
// CHECK-PREDICATOR-NEXT: if (!(
// CHECK-PREDICATOR-NEXT: ( MI->getOpcode() == Test::Inst2 )
// CHECK-PREDICATOR-NEXT: && MI->getOperand(0).getReg() == Test::X0
@@ -225,7 +252,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: if (!FirstMI)
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI;
+// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = FirstMI;
// CHECK-PREDICATOR-NEXT: if (!(
// CHECK-PREDICATOR-NEXT: ( MI->getOpcode() == Test::Inst0 )
// CHECK-PREDICATOR-NEXT: && true
@@ -257,6 +284,10 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: if (FirstMI->getOperand(0).getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestSingleFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestSingleFusionPreRA;
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-EMPTY:
diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
index 0ff0098407c65..1a446408e9a7f 100644
--- a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
+++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
@@ -19,15 +19,25 @@
// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated
// header file.
//
+// Each predicator also maintains `Statistic`s that count how often the fusion
+// is matched, split into pre-RA and post-RA counters because both schedulers
+// run MacroFusion.
+//
// The generated predicator will be like:
//
// ```
+// STATISTIC(NumNAMEPreRA, "Times NAME Triggered (pre-ra)");
+// STATISTIC(NumNAMEPostRA, "Times NAME Triggered (post-ra)");
// bool isNAME(const TargetInstrInfo &TII,
// const TargetSubtargetInfo &STI,
// const MachineInstr *FirstMI,
// const MachineInstr &SecondMI) {
// auto &MRI = SecondMI.getMF()->getRegInfo();
// /* Predicates */
+// if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// ++NumNAMEPostRA;
+// else
+// ++NumNAMEPreRA;
// return true;
// }
// ```
@@ -100,6 +110,15 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
Fusion->getValueAsListOfDefs("Predicates");
bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
+ // Emit the statistics that count how often this fusion is matched. The
+ // pre-RA and post-RA schedulers both run MacroFusion, so they are split
+ // into separate counters (distinguished below via the `NoVRegs` property)
+ // to avoid conflating the two.
+ OS << "STATISTIC(Num" << Fusion->getName() << "PreRA, \"Times "
+ << Fusion->getName() << " Triggered (pre-ra)\");\n";
+ OS << "STATISTIC(Num" << Fusion->getName() << "PostRA, \"Times "
+ << Fusion->getName() << " Triggered (post-ra)\");\n";
+
OS << "bool is" << Fusion->getName() << "(\n";
OS.indent(4) << "const TargetInstrInfo &TII,\n";
OS.indent(4) << "const TargetSubtargetInfo &STI,\n";
@@ -110,6 +129,11 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
emitPredicates(Predicates, IsCommutable, PE, OS);
+ OS.indent(2) << "if (SecondMI.getMF()->getProperties().hasNoVRegs())\n";
+ OS.indent(4) << "++Num" << Fusion->getName() << "PostRA;\n";
+ OS.indent(2) << "else\n";
+ OS.indent(4) << "++Num" << Fusion->getName() << "PreRA;\n";
+
OS.indent(2) << "return true;\n";
OS << "}\n";
}
More information about the llvm-commits
mailing list