[llvm] [TableGen][RISCV] Generate pre/post-RA statistics for macro fusions (PR #209394)
Pengcheng Wang via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 02:30:27 PDT 2026
https://github.com/wangpc-pp updated https://github.com/llvm/llvm-project/pull/209394
>From 25af0cf0f330985bf69d06c57ea28061ddba5138 Mon Sep 17 00:00:00 2001
From: Pengcheng Wang <wangpengcheng.pp at bytedance.com>
Date: Tue, 14 Jul 2026 15:22:06 +0800
Subject: [PATCH 1/4] [TableGen][RISCV] Generate pre/post-RA statistics for
macro fusions
Emit a per-fusion Statistic from MacroFusionPredicatorEmitter that counts
how often each fusion is matched. Following the design suggested in
llvm/llvm-project#186499:
* Add `bit GenerateStatistic = 1` to class Fusion so a fusion can opt out.
* Emit a new `GET_<Target>_MACRO_FUSION_STATISTICS` section that defines
ENABLE_STATISTIC and the Statistic counters, and guard the increments
in each predicator behind ENABLE_STATISTIC.
Because both the pre-RA and post-RA schedulers run MacroFusion, the counts
are split into pre-ra/post-ra variants (distinguished via the NoVRegs
property) to avoid conflating the two.
Wire the new section into RISCVSubtarget.cpp and update the generic
TableGen test.
Co-authored-by: Sam Elliot <aelliott at qti.qualcomm.com>
Assisted-by: TRAE CLI (DeepSeek V4 Pro)
---
llvm/include/llvm/Target/TargetMacroFusion.td | 6 ++
llvm/lib/Target/RISCV/RISCVSubtarget.cpp | 13 +++
llvm/test/TableGen/MacroFusion.td | 96 +++++++++++++++++++
.../TableGen/MacroFusionPredicatorEmitter.cpp | 61 +++++++++++-
4 files changed, 172 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetMacroFusion.td b/llvm/include/llvm/Target/TargetMacroFusion.td
index 1f070853c3084..02df4c4b52f99 100644
--- a/llvm/include/llvm/Target/TargetMacroFusion.td
+++ b/llvm/include/llvm/Target/TargetMacroFusion.td
@@ -107,6 +107,12 @@ class Fusion<string name, string fieldName, string desc, list<FusionPredicate> p
: SubtargetFeature<"fusion-" # name, fieldName, "true", desc> {
list<FusionPredicate> Predicates = predicates;
bit IsCommutable = 0;
+
+ // When true, the MacroFusionPredicatorEmitter generates `Statistic`s that
+ // count how often this fusion is matched (see the
+ // `GET_<TargetName>_MACRO_FUSION_STATISTICS` section of the generated file).
+ // Set this to 0 to opt out, for fusions whose statistics are not interesting.
+ bit GenerateStatistic = 1;
}
// The generated predicator will be like:
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index 524a48750e985..fa432da77f2ae 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/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
@@ -30,9 +31,21 @@ using namespace llvm;
#define GET_SUBTARGETINFO_CTOR
#include "RISCVGenSubtargetInfo.inc"
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "riscv-macro-fusion"
+
+// The statistics section defines `ENABLE_STATISTIC` and the `Statistic`
+// counters, so it must be included before the predicator implementations that
+// reference them.
+#define GET_RISCV_MACRO_FUSION_STATISTICS
+#include "RISCVGenMacroFusion.inc"
+
#define GET_RISCV_MACRO_FUSION_PRED_IMPL
#include "RISCVGenMacroFusion.inc"
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "riscv-subtarget"
+
namespace llvm::RISCVTuneInfoTable {
#define GET_RISCVTuneInfoTable_IMPL
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index 8fd823184a2b1..a597d10704760 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -68,6 +68,14 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
bit IsCommutable = 1;
}
+// A fusion that opts out of statistics collection.
+def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatisticFusion",
+ "Test Fusion Without Statistic",
+ CheckOpcode<[Inst0]>,
+ CheckOpcode<[Inst1]>> {
+ let GenerateStatistic = 0;
+}
+
// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL
// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_DECL
// CHECK-PREDICATOR-EMPTY:
@@ -77,6 +85,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: bool isTestCommutableFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestFirstSameRegFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
+// CHECK-PREDICATOR-NEXT: bool isTestNoStatisticFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestSingleFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: } // namespace llvm
@@ -104,6 +113,12 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: if (MI->getOperand(0).getReg() != Test::X0)
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: #ifdef ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestBothFusionPredicatePostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestBothFusionPredicatePreRA;
+// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestCommutableFusion(
@@ -152,6 +167,12 @@ 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: #ifdef ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestCommutableFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestCommutableFusionPreRA;
+// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestFirstSameRegFusion(
@@ -170,6 +191,12 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: #ifdef ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestFirstSameRegFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestFirstSameRegFusionPreRA;
+// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestFusion(
@@ -206,6 +233,45 @@ 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: #ifdef ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestFusionPreRA;
+// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: return true;
+// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: bool isTestNoStatisticFusion(
+// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
+// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
+// CHECK-PREDICATOR-NEXT: const MachineInstr *FirstMI,
+// 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: if (( MI->getOpcode() != Test::Inst1 ))
+// CHECK-PREDICATOR-NEXT: return false;
+// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (!FirstMI)
+// CHECK-PREDICATOR-NEXT: return true;
+// CHECK-PREDICATOR-NEXT: {
+// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI;
+// CHECK-PREDICATOR-NEXT: if (( MI->getOpcode() != Test::Inst0 ))
+// CHECK-PREDICATOR-NEXT: return false;
+// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (!SecondMI.getOperand(0).getReg().isVirtual()) {
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getOperand(0).getReg() != SecondMI.getOperand(1).getReg())
+// CHECK-PREDICATOR-NEXT: return false;
+// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: {
+// CHECK-PREDICATOR-NEXT: Register FirstDest = FirstMI->getOperand(0).getReg();
+// CHECK-PREDICATOR-NEXT: if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))
+// CHECK-PREDICATOR-NEXT: return false;
+// CHECK-PREDICATOR-NEXT: }
+// CHECK-PREDICATOR-NEXT: if (!(FirstMI->getOperand(0).isReg() &&
+// 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: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestSingleFusion(
@@ -257,6 +323,12 @@ 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: #ifdef ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
+// CHECK-PREDICATOR-NEXT: ++NumTestSingleFusionPostRA;
+// CHECK-PREDICATOR-NEXT: else
+// CHECK-PREDICATOR-NEXT: ++NumTestSingleFusionPreRA;
+// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-EMPTY:
@@ -264,6 +336,29 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: #endif // GET_Test_MACRO_FUSION_PRED_IMPL
+// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_STATISTICS
+// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_STATISTICS
+// CHECK-PREDICATOR-EMPTY:
+// CHECK-PREDICATOR-NEXT: #ifndef ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: #define ENABLE_STATISTIC
+// CHECK-PREDICATOR-NEXT: #endif
+// 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: STATISTIC(NumTestCommutableFusionPreRA, "Times TestCommutableFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestCommutableFusionPostRA, "Times TestCommutableFusion Triggered (post-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFirstSameRegFusionPreRA, "Times TestFirstSameRegFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFirstSameRegFusionPostRA, "Times TestFirstSameRegFusion Triggered (post-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFusionPreRA, "Times TestFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFusionPostRA, "Times TestFusion Triggered (post-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestSingleFusionPreRA, "Times TestSingleFusion Triggered (pre-ra)");
+// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestSingleFusionPostRA, "Times TestSingleFusion Triggered (post-ra)");
+// CHECK-PREDICATOR-EMPTY:
+// CHECK-PREDICATOR-NEXT: } // namespace llvm
+// CHECK-PREDICATOR-EMPTY:
+// CHECK-PREDICATOR-NEXT: #endif // GET_Test_MACRO_FUSION_STATISTICS
+
// Check that we have generated `getMacroFusions()` function.
// CHECK-SUBTARGET: std::vector<MacroFusionPredTy> getMacroFusions() const final;
@@ -273,6 +368,7 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestCommutableFusion)) Fusions.push_back(llvm::isTestCommutableFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFirstSameRegFusion)) Fusions.push_back(llvm::isTestFirstSameRegFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFusion)) Fusions.push_back(llvm::isTestFusion);
+// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestNoStatisticFusion)) Fusions.push_back(llvm::isTestNoStatisticFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestSingleFusion)) Fusions.push_back(llvm::isTestSingleFusion);
// CHECK-SUBTARGET-NEXT: return Fusions;
// CHECK-SUBTARGET-NEXT: }
diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
index 0ff0098407c65..37b173b2c4723 100644
--- a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
+++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
@@ -13,12 +13,23 @@
// predicators for checking if input instructions can be fused. These
// predicators can used in `MacroFusion` DAG mutation.
//
-// The generated header file contains two parts: one for predicator
-// declarations and one for predicator implementations. The user can get them
-// by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or
-// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated
+// The generated header file contains three parts: one for predicator
+// declarations, one for predicator implementations, and one for the
+// definitions of the `Statistic`s that count how often each fusion is matched.
+// The user can get them by defining macro
+// `GET_<TargetName>_MACRO_FUSION_PRED_DECL`,
+// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` or
+// `GET_<TargetName>_MACRO_FUSION_STATISTICS` and then including the generated
// header file.
//
+// The statistics are opt-in: the predicator implementations only increment the
+// counters when `ENABLE_STATISTIC` is defined, and the
+// `GET_<TargetName>_MACRO_FUSION_STATISTICS` section both defines
+// `ENABLE_STATISTIC` and emits the `Statistic` definitions. So a target that
+// wants the statistics should include the `..._STATISTICS` section *before* the
+// `..._PRED_IMPL` section. Per-fusion, the statistics can be disabled by
+// setting `GenerateStatistic = 0` on the `Fusion` definition.
+//
// The generated predicator will be like:
//
// ```
@@ -60,6 +71,8 @@ class MacroFusionPredicatorEmitter {
PredicateExpander &PE, raw_ostream &OS);
void emitMacroFusionImpl(ArrayRef<const Record *> Fusions,
PredicateExpander &PE, raw_ostream &OS);
+ void emitMacroFusionStatistics(ArrayRef<const Record *> Fusions,
+ raw_ostream &OS);
void emitPredicates(ArrayRef<const Record *> FirstPredicate,
bool IsCommutable, PredicateExpander &PE,
raw_ostream &OS);
@@ -99,6 +112,7 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
std::vector<const Record *> Predicates =
Fusion->getValueAsListOfDefs("Predicates");
bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
+ bool GenerateStatistic = Fusion->getValueAsBit("GenerateStatistic");
OS << "bool is" << Fusion->getName() << "(\n";
OS.indent(4) << "const TargetInstrInfo &TII,\n";
@@ -110,11 +124,48 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
emitPredicates(Predicates, IsCommutable, PE, OS);
+ // Bump the statistics that count how often this fusion is matched. The
+ // pre-RA and post-RA schedulers both run MacroFusion, so we distinguish
+ // them (using the `NoVRegs` property) to avoid conflating the two.
+ if (GenerateStatistic) {
+ OS << "#ifdef ENABLE_STATISTIC\n";
+ 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 << "#endif // ENABLE_STATISTIC\n";
+ }
+
OS.indent(2) << "return true;\n";
OS << "}\n";
}
}
+void MacroFusionPredicatorEmitter::emitMacroFusionStatistics(
+ ArrayRef<const Record *> Fusions, raw_ostream &OS) {
+ IfDefEmitter IfDef(
+ OS, ("GET_" + Target.getName() + "_MACRO_FUSION_STATISTICS").str());
+
+ // Requesting the statistics implies collecting them, so make sure the
+ // increments emitted in the predicators (guarded by `ENABLE_STATISTIC`) are
+ // compiled in when this section is included.
+ OS << "#ifndef ENABLE_STATISTIC\n";
+ OS << "#define ENABLE_STATISTIC\n";
+ OS << "#endif\n";
+
+ NamespaceEmitter LlvmNS(OS, "llvm");
+
+ for (const Record *Fusion : Fusions) {
+ if (!Fusion->getValueAsBit("GenerateStatistic"))
+ continue;
+
+ 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";
+ }
+}
+
void MacroFusionPredicatorEmitter::emitPredicates(
ArrayRef<const Record *> Predicates, bool IsCommutable,
PredicateExpander &PE, raw_ostream &OS) {
@@ -305,6 +356,8 @@ void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
emitMacroFusionDecl(Fusions, PE, OS);
OS << "\n";
emitMacroFusionImpl(Fusions, PE, OS);
+ OS << "\n";
+ emitMacroFusionStatistics(Fusions, OS);
}
static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
>From 54f88be9f78a5e9ef1c4d45c5625866385540c77 Mon Sep 17 00:00:00 2001
From: Pengcheng Wang <wangpengcheng.pp at bytedance.com>
Date: Wed, 15 Jul 2026 16:41:03 +0800
Subject: [PATCH 2/4] [TableGen] Use `true` for Fusion.GenerateStatistic
default
Prefer the boolean literal `true` over `1` for the `GenerateStatistic`
bit and update the doc comment accordingly. NFC.
Assisted-by: TRAE CLI (DeepSeek V4 Pro)
---
llvm/include/llvm/Target/TargetMacroFusion.td | 5 +++--
llvm/test/TableGen/MacroFusion.td | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetMacroFusion.td b/llvm/include/llvm/Target/TargetMacroFusion.td
index 02df4c4b52f99..e89483b2c2598 100644
--- a/llvm/include/llvm/Target/TargetMacroFusion.td
+++ b/llvm/include/llvm/Target/TargetMacroFusion.td
@@ -111,8 +111,9 @@ class Fusion<string name, string fieldName, string desc, list<FusionPredicate> p
// When true, the MacroFusionPredicatorEmitter generates `Statistic`s that
// count how often this fusion is matched (see the
// `GET_<TargetName>_MACRO_FUSION_STATISTICS` section of the generated file).
- // Set this to 0 to opt out, for fusions whose statistics are not interesting.
- bit GenerateStatistic = 1;
+ // Set this to false to opt out, for fusions whose statistics are not
+ // interesting.
+ bit GenerateStatistic = true;
}
// The generated predicator will be like:
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index a597d10704760..de88ab10f1d08 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -73,7 +73,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
"Test Fusion Without Statistic",
CheckOpcode<[Inst0]>,
CheckOpcode<[Inst1]>> {
- let GenerateStatistic = 0;
+ let GenerateStatistic = false;
}
// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL
>From 97547794b96702461897a0693b58203723aba5d6 Mon Sep 17 00:00:00 2001
From: Pengcheng Wang <wangpengcheng.pp at bytedance.com>
Date: Wed, 15 Jul 2026 17:04:09 +0800
Subject: [PATCH 3/4] [TableGen][RISCV] Drop ENABLE_STATISTIC, emit fusion
statistics inline
Simplify the macro fusion statistics to a single level of control. Instead
of a separate `GET_<Target>_MACRO_FUSION_STATISTICS` section that defines
`ENABLE_STATISTIC` and guards the counters, emit the `STATISTIC` definitions
and increments directly in the predicator implementations.
Untriggered `Statistic`s never appear in `-stats` output and are no-ops when
`LLVM_ENABLE_STATS` is off, so there is no cost to always emitting them. A
target that does not want the counters for a specific fusion can still opt
out via `GenerateStatistic = false`.
Assisted-by: TRAE CLI (DeepSeek V4 Pro)
---
llvm/include/llvm/Target/TargetMacroFusion.td | 7 +-
llvm/lib/Target/RISCV/RISCVSubtarget.cpp | 6 --
llvm/test/TableGen/MacroFusion.td | 68 ++++++-----------
.../TableGen/MacroFusionPredicatorEmitter.cpp | 73 +++++++------------
4 files changed, 51 insertions(+), 103 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetMacroFusion.td b/llvm/include/llvm/Target/TargetMacroFusion.td
index e89483b2c2598..e7ca52b190690 100644
--- a/llvm/include/llvm/Target/TargetMacroFusion.td
+++ b/llvm/include/llvm/Target/TargetMacroFusion.td
@@ -109,10 +109,9 @@ class Fusion<string name, string fieldName, string desc, list<FusionPredicate> p
bit IsCommutable = 0;
// When true, the MacroFusionPredicatorEmitter generates `Statistic`s that
- // count how often this fusion is matched (see the
- // `GET_<TargetName>_MACRO_FUSION_STATISTICS` section of the generated file).
- // Set this to false to opt out, for fusions whose statistics are not
- // interesting.
+ // count how often this fusion is matched (split into pre-RA and post-RA
+ // counters). Set this to false to opt out, for fusions whose statistics are
+ // not interesting.
bit GenerateStatistic = true;
}
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index fa432da77f2ae..eded8677eed32 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -34,12 +34,6 @@ using namespace llvm;
#undef DEBUG_TYPE
#define DEBUG_TYPE "riscv-macro-fusion"
-// The statistics section defines `ENABLE_STATISTIC` and the `Statistic`
-// counters, so it must be included before the predicator implementations that
-// reference them.
-#define GET_RISCV_MACRO_FUSION_STATISTICS
-#include "RISCVGenMacroFusion.inc"
-
#define GET_RISCV_MACRO_FUSION_PRED_IMPL
#include "RISCVGenMacroFusion.inc"
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index de88ab10f1d08..f606157523114 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -91,12 +91,15 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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,
@@ -104,23 +107,23 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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: #ifdef ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
// CHECK-PREDICATOR-NEXT: ++NumTestBothFusionPredicatePostRA;
// CHECK-PREDICATOR-NEXT: else
// CHECK-PREDICATOR-NEXT: ++NumTestBothFusionPredicatePreRA;
-// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// 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,
@@ -128,7 +131,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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
@@ -138,7 +141,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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: }
@@ -167,14 +170,14 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-NEXT: if (FirstMI->getOperand(0).getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: #ifdef ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
// CHECK-PREDICATOR-NEXT: ++NumTestCommutableFusionPostRA;
// CHECK-PREDICATOR-NEXT: else
// CHECK-PREDICATOR-NEXT: ++NumTestCommutableFusionPreRA;
-// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// 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,
@@ -191,14 +194,14 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: #ifdef ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
// CHECK-PREDICATOR-NEXT: ++NumTestFirstSameRegFusionPostRA;
// CHECK-PREDICATOR-NEXT: else
// CHECK-PREDICATOR-NEXT: ++NumTestFirstSameRegFusionPreRA;
-// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// 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,
@@ -206,7 +209,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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
@@ -216,7 +219,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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: }
@@ -233,12 +236,10 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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: #ifdef ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
// CHECK-PREDICATOR-NEXT: ++NumTestFusionPostRA;
// CHECK-PREDICATOR-NEXT: else
// CHECK-PREDICATOR-NEXT: ++NumTestFusionPreRA;
-// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-NEXT: bool isTestNoStatisticFusion(
@@ -248,14 +249,14 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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 (( MI->getOpcode() != Test::Inst1 ))
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
// 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: }
@@ -274,6 +275,8 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-NEXT: return false;
// 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,
@@ -281,7 +284,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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
@@ -291,7 +294,7 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// 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
@@ -323,12 +326,10 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-NEXT: if (FirstMI->getOperand(0).getReg() != SecondMI.getOperand(SrcOpIdx2).getReg())
// CHECK-PREDICATOR-NEXT: return false;
// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: #ifdef ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: if (SecondMI.getMF()->getProperties().hasNoVRegs())
// CHECK-PREDICATOR-NEXT: ++NumTestSingleFusionPostRA;
// CHECK-PREDICATOR-NEXT: else
// CHECK-PREDICATOR-NEXT: ++NumTestSingleFusionPreRA;
-// CHECK-PREDICATOR-NEXT: #endif // ENABLE_STATISTIC
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
// CHECK-PREDICATOR-EMPTY:
@@ -336,29 +337,6 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: #endif // GET_Test_MACRO_FUSION_PRED_IMPL
-// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_STATISTICS
-// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_STATISTICS
-// CHECK-PREDICATOR-EMPTY:
-// CHECK-PREDICATOR-NEXT: #ifndef ENABLE_STATISTIC
-// CHECK-PREDICATOR-NEXT: #define ENABLE_STATISTIC
-// CHECK-PREDICATOR-NEXT: #endif
-// 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: STATISTIC(NumTestCommutableFusionPreRA, "Times TestCommutableFusion Triggered (pre-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestCommutableFusionPostRA, "Times TestCommutableFusion Triggered (post-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFirstSameRegFusionPreRA, "Times TestFirstSameRegFusion Triggered (pre-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFirstSameRegFusionPostRA, "Times TestFirstSameRegFusion Triggered (post-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFusionPreRA, "Times TestFusion Triggered (pre-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestFusionPostRA, "Times TestFusion Triggered (post-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestSingleFusionPreRA, "Times TestSingleFusion Triggered (pre-ra)");
-// CHECK-PREDICATOR-NEXT: STATISTIC(NumTestSingleFusionPostRA, "Times TestSingleFusion Triggered (post-ra)");
-// CHECK-PREDICATOR-EMPTY:
-// CHECK-PREDICATOR-NEXT: } // namespace llvm
-// CHECK-PREDICATOR-EMPTY:
-// CHECK-PREDICATOR-NEXT: #endif // GET_Test_MACRO_FUSION_STATISTICS
-
// Check that we have generated `getMacroFusions()` function.
// CHECK-SUBTARGET: std::vector<MacroFusionPredTy> getMacroFusions() const final;
diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
index 37b173b2c4723..da5763a8c8fbf 100644
--- a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
+++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
@@ -13,32 +13,32 @@
// predicators for checking if input instructions can be fused. These
// predicators can used in `MacroFusion` DAG mutation.
//
-// The generated header file contains three parts: one for predicator
-// declarations, one for predicator implementations, and one for the
-// definitions of the `Statistic`s that count how often each fusion is matched.
-// The user can get them by defining macro
-// `GET_<TargetName>_MACRO_FUSION_PRED_DECL`,
-// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` or
-// `GET_<TargetName>_MACRO_FUSION_STATISTICS` and then including the generated
+// The generated header file contains two parts: one for predicator
+// declarations and one for predicator implementations. The user can get them
+// by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or
+// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated
// header file.
//
-// The statistics are opt-in: the predicator implementations only increment the
-// counters when `ENABLE_STATISTIC` is defined, and the
-// `GET_<TargetName>_MACRO_FUSION_STATISTICS` section both defines
-// `ENABLE_STATISTIC` and emits the `Statistic` definitions. So a target that
-// wants the statistics should include the `..._STATISTICS` section *before* the
-// `..._PRED_IMPL` section. Per-fusion, the statistics can be disabled by
-// setting `GenerateStatistic = 0` on the `Fusion` definition.
+// 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. Per-fusion, these can be disabled by setting
+// `GenerateStatistic = false` on the `Fusion` definition.
//
// 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;
// }
// ```
@@ -71,8 +71,6 @@ class MacroFusionPredicatorEmitter {
PredicateExpander &PE, raw_ostream &OS);
void emitMacroFusionImpl(ArrayRef<const Record *> Fusions,
PredicateExpander &PE, raw_ostream &OS);
- void emitMacroFusionStatistics(ArrayRef<const Record *> Fusions,
- raw_ostream &OS);
void emitPredicates(ArrayRef<const Record *> FirstPredicate,
bool IsCommutable, PredicateExpander &PE,
raw_ostream &OS);
@@ -114,6 +112,17 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
bool GenerateStatistic = Fusion->getValueAsBit("GenerateStatistic");
+ // 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.
+ if (GenerateStatistic) {
+ 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";
@@ -124,16 +133,11 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
emitPredicates(Predicates, IsCommutable, PE, OS);
- // Bump the statistics that count how often this fusion is matched. The
- // pre-RA and post-RA schedulers both run MacroFusion, so we distinguish
- // them (using the `NoVRegs` property) to avoid conflating the two.
if (GenerateStatistic) {
- OS << "#ifdef ENABLE_STATISTIC\n";
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 << "#endif // ENABLE_STATISTIC\n";
}
OS.indent(2) << "return true;\n";
@@ -141,31 +145,6 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
}
}
-void MacroFusionPredicatorEmitter::emitMacroFusionStatistics(
- ArrayRef<const Record *> Fusions, raw_ostream &OS) {
- IfDefEmitter IfDef(
- OS, ("GET_" + Target.getName() + "_MACRO_FUSION_STATISTICS").str());
-
- // Requesting the statistics implies collecting them, so make sure the
- // increments emitted in the predicators (guarded by `ENABLE_STATISTIC`) are
- // compiled in when this section is included.
- OS << "#ifndef ENABLE_STATISTIC\n";
- OS << "#define ENABLE_STATISTIC\n";
- OS << "#endif\n";
-
- NamespaceEmitter LlvmNS(OS, "llvm");
-
- for (const Record *Fusion : Fusions) {
- if (!Fusion->getValueAsBit("GenerateStatistic"))
- continue;
-
- 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";
- }
-}
-
void MacroFusionPredicatorEmitter::emitPredicates(
ArrayRef<const Record *> Predicates, bool IsCommutable,
PredicateExpander &PE, raw_ostream &OS) {
@@ -356,8 +335,6 @@ void MacroFusionPredicatorEmitter::run(raw_ostream &OS) {
emitMacroFusionDecl(Fusions, PE, OS);
OS << "\n";
emitMacroFusionImpl(Fusions, PE, OS);
- OS << "\n";
- emitMacroFusionStatistics(Fusions, OS);
}
static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter>
>From 12985dcd1e1be571011a3b804f1fc2ddd63146de Mon Sep 17 00:00:00 2001
From: Pengcheng Wang <wangpengcheng.pp at bytedance.com>
Date: Wed, 15 Jul 2026 17:27:11 +0800
Subject: [PATCH 4/4] [TableGen] Always emit macro fusion statistics, drop
GenerateStatistic
Remove the per-fusion `GenerateStatistic` opt-out and unconditionally emit
the pre-RA/post-RA statistics for every fusion. Untriggered `Statistic`s
never show up in `-stats` output and are no-ops when `LLVM_ENABLE_STATS` is
off, so a control knob is unnecessary.
Assisted-by: TRAE CLI (DeepSeek V4 Pro)
---
llvm/include/llvm/Target/TargetMacroFusion.td | 6 ---
llvm/test/TableGen/MacroFusion.td | 43 -------------------
.../TableGen/MacroFusionPredicatorEmitter.cpp | 24 ++++-------
3 files changed, 9 insertions(+), 64 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetMacroFusion.td b/llvm/include/llvm/Target/TargetMacroFusion.td
index e7ca52b190690..1f070853c3084 100644
--- a/llvm/include/llvm/Target/TargetMacroFusion.td
+++ b/llvm/include/llvm/Target/TargetMacroFusion.td
@@ -107,12 +107,6 @@ class Fusion<string name, string fieldName, string desc, list<FusionPredicate> p
: SubtargetFeature<"fusion-" # name, fieldName, "true", desc> {
list<FusionPredicate> Predicates = predicates;
bit IsCommutable = 0;
-
- // When true, the MacroFusionPredicatorEmitter generates `Statistic`s that
- // count how often this fusion is matched (split into pre-RA and post-RA
- // counters). Set this to false to opt out, for fusions whose statistics are
- // not interesting.
- bit GenerateStatistic = true;
}
// The generated predicator will be like:
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index f606157523114..64c0885874e71 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -68,14 +68,6 @@ def TestFirstSameRegFusion: Fusion<"test-first-same-reg", "HasTestFirstSameRegFu
bit IsCommutable = 1;
}
-// A fusion that opts out of statistics collection.
-def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatisticFusion",
- "Test Fusion Without Statistic",
- CheckOpcode<[Inst0]>,
- CheckOpcode<[Inst1]>> {
- let GenerateStatistic = false;
-}
-
// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL
// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_DECL
// CHECK-PREDICATOR-EMPTY:
@@ -85,7 +77,6 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-NEXT: bool isTestCommutableFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestFirstSameRegFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
-// CHECK-PREDICATOR-NEXT: bool isTestNoStatisticFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-NEXT: bool isTestSingleFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &);
// CHECK-PREDICATOR-EMPTY:
// CHECK-PREDICATOR-NEXT: } // namespace llvm
@@ -242,39 +233,6 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-PREDICATOR-NEXT: ++NumTestFusionPreRA;
// CHECK-PREDICATOR-NEXT: return true;
// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: bool isTestNoStatisticFusion(
-// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII,
-// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI,
-// CHECK-PREDICATOR-NEXT: const MachineInstr *FirstMI,
-// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) {
-// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
-// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
-// CHECK-PREDICATOR-NEXT: if (( MI->getOpcode() != Test::Inst1 ))
-// CHECK-PREDICATOR-NEXT: return false;
-// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: if (!FirstMI)
-// CHECK-PREDICATOR-NEXT: return true;
-// CHECK-PREDICATOR-NEXT: {
-// 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: }
-// CHECK-PREDICATOR-NEXT: if (!SecondMI.getOperand(0).getReg().isVirtual()) {
-// CHECK-PREDICATOR-NEXT: if (SecondMI.getOperand(0).getReg() != SecondMI.getOperand(1).getReg())
-// CHECK-PREDICATOR-NEXT: return false;
-// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: {
-// CHECK-PREDICATOR-NEXT: Register FirstDest = FirstMI->getOperand(0).getReg();
-// CHECK-PREDICATOR-NEXT: if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))
-// CHECK-PREDICATOR-NEXT: return false;
-// CHECK-PREDICATOR-NEXT: }
-// CHECK-PREDICATOR-NEXT: if (!(FirstMI->getOperand(0).isReg() &&
-// 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: 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(
@@ -346,7 +304,6 @@ def TestNoStatisticFusion: SimpleFusion<"test-no-statistic", "HasTestNoStatistic
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestCommutableFusion)) Fusions.push_back(llvm::isTestCommutableFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFirstSameRegFusion)) Fusions.push_back(llvm::isTestFirstSameRegFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestFusion)) Fusions.push_back(llvm::isTestFusion);
-// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestNoStatisticFusion)) Fusions.push_back(llvm::isTestNoStatisticFusion);
// CHECK-SUBTARGET-NEXT: if (hasFeature(Test::TestSingleFusion)) Fusions.push_back(llvm::isTestSingleFusion);
// CHECK-SUBTARGET-NEXT: return Fusions;
// CHECK-SUBTARGET-NEXT: }
diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
index da5763a8c8fbf..1a446408e9a7f 100644
--- a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
+++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp
@@ -21,8 +21,7 @@
//
// 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. Per-fusion, these can be disabled by setting
-// `GenerateStatistic = false` on the `Fusion` definition.
+// run MacroFusion.
//
// The generated predicator will be like:
//
@@ -110,18 +109,15 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
std::vector<const Record *> Predicates =
Fusion->getValueAsListOfDefs("Predicates");
bool IsCommutable = Fusion->getValueAsBit("IsCommutable");
- bool GenerateStatistic = Fusion->getValueAsBit("GenerateStatistic");
// 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.
- if (GenerateStatistic) {
- 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 << "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";
@@ -133,12 +129,10 @@ void MacroFusionPredicatorEmitter::emitMacroFusionImpl(
emitPredicates(Predicates, IsCommutable, PE, OS);
- if (GenerateStatistic) {
- 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) << "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