[llvm] [MC] Pack scheduling class entry counts (PR #202649)
David Zbarsky via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 09:50:43 PDT 2026
https://github.com/dzbarsky updated https://github.com/llvm/llvm-project/pull/202649
>From 3337a73b1919b497b447921c1d9d5051eeb2590a Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Mon, 8 Jun 2026 15:38:18 -0400
Subject: [PATCH] [MC] Pack scheduling class entry counts
Generated scheduling classes currently use at most 20 write-resource entries and 35 write-latency entries, while read-advance counts reach 504. Narrow the two write counts to uint8_t and order the descriptor as the three table indices followed by the three entry counts.
Emit the observed write-count maxima as static_asserts in the generated subtarget source so model growth cannot silently exceed the packed fields. Keep compile-time sizeof checks for the 12-byte release and 16-byte debug layouts.
This reduces the fully stripped arm64 llvm-mca binary from 36,535,760 to 35,990,864 bytes, saving 544,896 bytes (1.49%). The stripped all-tools multicall binary decreases from 143,567,584 to 143,039,208 bytes, saving 528,376 bytes (0.368%).
All 1,417 llvm-mca tests pass with three expected failures, both scheduling TableGen tests pass, and nine AArch64 SVE scheduling-model tests pass. AArch64 and X86 generated target descriptors compile, and their llc output and llvm-mca instruction tables remain byte-identical.
The existing Znver4 instruction-table workload, repeated 50 times across 20 runs in both orderings, changed mean user CPU time from 0.270977 to 0.271476 seconds (+0.184%).
---
llvm/include/llvm/MC/MCSchedule.h | 12 +++++++---
.../TableGen/CompressWriteLatencyEntry.td | 9 ++++---
llvm/utils/TableGen/SubtargetEmitter.cpp | 24 +++++++++++++++----
3 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/MC/MCSchedule.h b/llvm/include/llvm/MC/MCSchedule.h
index 8c21dbd0ae385..ddcb4ded42ff2 100644
--- a/llvm/include/llvm/MC/MCSchedule.h
+++ b/llvm/include/llvm/MC/MCSchedule.h
@@ -137,12 +137,12 @@ struct MCSchedClassDesc {
uint16_t BeginGroup : 1;
uint16_t EndGroup : 1;
uint16_t RetireOOO : 1;
+ uint16_t ReadAdvanceIdx; // First index into ReadAdvanceTable.
uint16_t WriteProcResIdx; // First index into WriteProcResTable.
- uint16_t NumWriteProcResEntries;
uint16_t WriteLatencyIdx; // First index into WriteLatencyTable.
- uint16_t NumWriteLatencyEntries;
- uint16_t ReadAdvanceIdx; // First index into ReadAdvanceTable.
uint16_t NumReadAdvanceEntries;
+ uint8_t NumWriteProcResEntries;
+ uint8_t NumWriteLatencyEntries;
bool isValid() const {
return NumMicroOps != InvalidNumMicroOps;
@@ -152,6 +152,12 @@ struct MCSchedClassDesc {
}
};
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+static_assert(sizeof(MCSchedClassDesc) == 16);
+#else
+static_assert(sizeof(MCSchedClassDesc) == 12);
+#endif
+
/// Specify the cost of a register definition in terms of number of physical
/// register allocated at register renaming stage. For example, AMD Jaguar.
/// natively supports 128-bit data types, and operations on 256-bit registers
diff --git a/llvm/test/TableGen/CompressWriteLatencyEntry.td b/llvm/test/TableGen/CompressWriteLatencyEntry.td
index d6a9f0ac0dd76..53ce09629870e 100644
--- a/llvm/test/TableGen/CompressWriteLatencyEntry.td
+++ b/llvm/test/TableGen/CompressWriteLatencyEntry.td
@@ -21,6 +21,9 @@ let CompleteModel = 0 in {
def Read_D : SchedRead;
+// CHECK: static_assert(0 <= UINT8_MAX, "NumWriteProcResEntries does not fit in uint8_t");
+// CHECK-NEXT: static_assert(1 <= UINT8_MAX, "NumWriteLatencyEntries does not fit in uint8_t");
+
// CHECK: extern const llvm::MCWriteLatencyEntry MyTargetWriteLatencyTable[] = {
// CHECK-NEXT: { 0, 0}, // Invalid
// CHECK-NEXT: { 1, 0}, // #1 Write_A_Write_C
@@ -34,9 +37,9 @@ def Read_D : SchedRead;
// CHECK: static const llvm::MCSchedClassDesc SchedModel_ASchedClasses[] = {
// CHECK-NEXT: {DBGFIELD(1) 8191, false, false, false, 0, 0, 0, 0, 0, 0},
-// CHECK-NEXT: {DBGFIELD(/*Inst_A*/ {{[0-9]+}}) 1, false, false, false, 0, 0, 1, 1, 0, 0}, // #1
-// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ {{[0-9]+}}) 1, false, false, false, 0, 0, 2, 1, 0, 0}, // #2
-// CHECK-NEXT: {DBGFIELD(/*Inst_C*/ {{[0-9]+}}) 1, false, false, false, 0, 0, 1, 1, 1, 1}, // #3
+// CHECK-NEXT: {DBGFIELD(/*Inst_A*/ {{[0-9]+}}) 1, false, false, false, 0, 0, 1, 0, 0, 1}, // #1
+// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ {{[0-9]+}}) 1, false, false, false, 0, 0, 2, 0, 0, 1}, // #2
+// CHECK-NEXT: {DBGFIELD(/*Inst_C*/ {{[0-9]+}}) 1, false, false, false, 1, 0, 1, 1, 0, 1}, // #3
// CHECK-NEXT: }; // SchedModel_ASchedClasses
let SchedModel = SchedModel_A in {
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index c3a9d69d6ec3e..57cecfc4bd0d7 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -55,6 +55,8 @@ class SubtargetEmitter : TargetFeaturesEmitter {
std::vector<MCWriteLatencyEntry> WriteLatencies;
std::vector<std::string> WriterNames;
std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
+ size_t MaxWriteProcResEntries = 0;
+ size_t MaxWriteLatencyEntries = 0;
// Reserve an invalid entry at index 0
SchedClassTables() {
@@ -1287,6 +1289,8 @@ void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel,
// WritePrecRes entries are sorted by ProcResIdx.
llvm::sort(WriteProcResources, LessWriteProcResources());
+ SchedTables.MaxWriteProcResEntries =
+ std::max(SchedTables.MaxWriteProcResEntries, WriteProcResources.size());
SCDesc.NumWriteProcResEntries = WriteProcResources.size();
std::vector<MCWriteProcResEntry>::iterator WPRPos =
std::search(SchedTables.WriteProcResources.begin(),
@@ -1300,6 +1304,8 @@ void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel,
WriteProcResources.end());
}
// Latency entries must remain in operand order.
+ SchedTables.MaxWriteLatencyEntries =
+ std::max(SchedTables.MaxWriteLatencyEntries, WriteLatencies.size());
SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
std::vector<MCWriteLatencyEntry>::iterator WLPos = std::search(
SchedTables.WriteLatencies.begin(), SchedTables.WriteLatencies.end(),
@@ -1335,6 +1341,11 @@ void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel,
// Emit SchedClass tables for all processors and associated global tables.
void SubtargetEmitter::emitSchedClassTables(SchedClassTables &SchedTables,
raw_ostream &OS) {
+ OS << "\nstatic_assert(" << SchedTables.MaxWriteProcResEntries
+ << " <= UINT8_MAX, \"NumWriteProcResEntries does not fit in uint8_t\");\n"
+ << "static_assert(" << SchedTables.MaxWriteLatencyEntries
+ << " <= UINT8_MAX, \"NumWriteLatencyEntries does not fit in uint8_t\");\n";
+
// Emit global WriteProcResTable.
OS << "\n// {ProcResourceIdx, ReleaseAtCycle, AcquireAtCycle}\n"
<< "extern const llvm::MCWriteProcResEntry " << Target
@@ -1398,7 +1409,9 @@ void SubtargetEmitter::emitSchedClassTables(SchedClassTables &SchedTables,
SchedTables.ProcSchedClasses[1 + Idx];
OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"
- << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
+ << " ReadAdvanceIdx, WriteProcResIdx, WriteLatencyIdx,"
+ << " NumReadAdvanceEntries, NumWriteProcResEntries,"
+ << " NumWriteLatencyEntries}\n";
OS << "static const llvm::MCSchedClassDesc " << Proc.ModelName
<< "SchedClasses[] = {\n";
@@ -1420,12 +1433,13 @@ void SubtargetEmitter::emitSchedClassTables(SchedClassTables &SchedTables,
OS << MCDesc.NumMicroOps << ", " << (MCDesc.BeginGroup ? "true" : "false")
<< ", " << (MCDesc.EndGroup ? "true" : "false") << ", "
<< (MCDesc.RetireOOO ? "true" : "false") << ", "
+ << format("%2d", MCDesc.ReadAdvanceIdx) << ", "
<< format("%2d", MCDesc.WriteProcResIdx) << ", "
- << MCDesc.NumWriteProcResEntries << ", "
<< format("%2d", MCDesc.WriteLatencyIdx) << ", "
- << MCDesc.NumWriteLatencyEntries << ", "
- << format("%2d", MCDesc.ReadAdvanceIdx) << ", "
- << MCDesc.NumReadAdvanceEntries << "}, // #" << SCIdx << '\n';
+ << MCDesc.NumReadAdvanceEntries << ", "
+ << static_cast<unsigned>(MCDesc.NumWriteProcResEntries) << ", "
+ << static_cast<unsigned>(MCDesc.NumWriteLatencyEntries) << "}, // #"
+ << SCIdx << '\n';
}
OS << "}; // " << Proc.ModelName << "SchedClasses\n";
}
More information about the llvm-commits
mailing list