[llvm] [TableGen] Pool duplicate scheduling class descriptors (PR #202659)
David Zbarsky via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 13:54:49 PDT 2026
https://github.com/dzbarsky updated https://github.com/llvm/llvm-project/pull/202659
>From 47cfd806ab606edbd1b17b78610785b38eb0718a Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Tue, 9 Jun 2026 03:08:33 -0400
Subject: [PATCH] [TableGen] Pool duplicate scheduling class descriptors
Each processor model currently emits a separate MCSchedClassDesc table.
RISC-V emits 158,654 release descriptors even though only 4,206
descriptor values are unique.
Build target-wide release and debug pools when both representations are
smaller than their direct tables. The release key ignores the scheduling
class name. The debug key includes SchedClassIdx so NameOff remains exact.
Emit the descriptors and each processor's uint16_t index table in one
aggregate. MCSchedModel stores typed pointers to the shared descriptor array
and the processor's index array. Release builds omit SchedClassNames and its
string table. Static assertions enforce descriptor sizes and the uint16_t
pool index range.
For all RISC-V processors, the generated table payload changes as follows:
Release: 2,221,156 -> 376,192 bytes (-1,844,964, -83.1%)
Debug: 3,173,080 -> 1,401,428 bytes (-1,771,652, -55.8%)
In an arm64 Release build with all RISC-V processors, linked sizes are:
llc: 57,253,384 -> 55,386,176 bytes (-1,867,208, -3.3%)
llvm-mca: 6,242,056 -> 4,374,824 bytes (-1,867,232, -29.9%)
Both binaries remove 1,844,960 bytes from __TEXT,__const.
__DATA_CONST,__const and __DATA,__data are unchanged. Typed index pointers
increase dynamic fixups from 53,268 to 53,291 for llc and from 7,684 to
7,707 for llvm-mca. Both binaries have zero static relocations.
All 420 TableGen tests pass. Release and assertion-enabled RISC-V
generated code compile. llc output is byte-identical for generic-rv64,
sifive-p670, spacemit-x100, and xiangshan-kunminghu. llvm-mca output is
byte-identical for the SCR7 ALU test.
On the SCR7 ALU test with 100,000 iterations, 30-run means were 1.103
seconds for direct tables and 1.092 seconds for pooled tables. Ten RISC-V
TableGen runs averaged 2.057 seconds for direct tables and 2.061 seconds
for pooled tables.
---
llvm/include/llvm/MC/MCSchedule.h | 13 +-
llvm/lib/MC/MCSchedule.cpp | 3 +
llvm/test/TableGen/InvalidMCSchedClassDesc.td | 35 ++-
llvm/test/TableGen/SchedClassTablePooling.td | 75 +++++
llvm/utils/TableGen/SubtargetEmitter.cpp | 258 ++++++++++++++----
5 files changed, 320 insertions(+), 64 deletions(-)
create mode 100644 llvm/test/TableGen/SchedClassTablePooling.td
diff --git a/llvm/include/llvm/MC/MCSchedule.h b/llvm/include/llvm/MC/MCSchedule.h
index 8c21dbd0ae385..7fc299debb719 100644
--- a/llvm/include/llvm/MC/MCSchedule.h
+++ b/llvm/include/llvm/MC/MCSchedule.h
@@ -152,6 +152,12 @@ struct MCSchedClassDesc {
}
};
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+static_assert(sizeof(MCSchedClassDesc) == 20);
+#else
+static_assert(sizeof(MCSchedClassDesc) == 14);
+#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
@@ -329,9 +335,12 @@ struct MCSchedModel {
unsigned ProcID;
const MCProcResourceDesc *ProcResourceTable;
const MCSchedClassDesc *SchedClassTable;
+ const uint16_t *SchedClassTableIndices;
unsigned NumProcResourceKinds;
unsigned NumSchedClasses;
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
const StringTable *SchedClassNames;
+#endif
// Instruction itinerary tables used by InstrItineraryData.
friend class InstrItineraryData;
const InstrItinerary *InstrItineraries;
@@ -373,12 +382,14 @@ struct MCSchedModel {
assert(hasInstrSchedModel() && "No scheduling machine model");
assert(SchedClassIdx < NumSchedClasses && "bad scheduling class idx");
+ if (SchedClassTableIndices)
+ SchedClassIdx = SchedClassTableIndices[SchedClassIdx];
return &SchedClassTable[SchedClassIdx];
}
StringRef getSchedClassName(unsigned SchedClassIdx) const {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- return (*SchedClassNames)[SchedClassTable[SchedClassIdx].NameOff];
+ return (*SchedClassNames)[getSchedClassDesc(SchedClassIdx)->NameOff];
#else
return "<unknown>";
#endif
diff --git a/llvm/lib/MC/MCSchedule.cpp b/llvm/lib/MC/MCSchedule.cpp
index e2124c1c76355..6dbab6a44c982 100644
--- a/llvm/lib/MC/MCSchedule.cpp
+++ b/llvm/lib/MC/MCSchedule.cpp
@@ -50,9 +50,12 @@ const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,
0,
nullptr,
nullptr,
+ nullptr,
0,
0,
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
nullptr,
+#endif
nullptr,
nullptr};
diff --git a/llvm/test/TableGen/InvalidMCSchedClassDesc.td b/llvm/test/TableGen/InvalidMCSchedClassDesc.td
index e43edd4174589..7ba46dfca9a5a 100644
--- a/llvm/test/TableGen/InvalidMCSchedClassDesc.td
+++ b/llvm/test/TableGen/InvalidMCSchedClassDesc.td
@@ -16,32 +16,45 @@ let CompleteModel = 0 in {
def SchedModel_C: SchedMachineModel;
}
-// Inst_B didn't have the resoures, and it is invalid.
-// CHECK: SchedModel_ASchedClasses[] = {
-// CHECK: {DBGFIELD(/*Inst_A*/ 19) 1
-// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ 26) 8191
+// The debug pool keeps distinct valid and invalid descriptors for each
+// scheduling class.
+// CHECK: llvm::MCSchedClassDesc Descs[5];
+// CHECK: uint16_t SchedModel_AIndices[3];
+// CHECK-NEXT: uint16_t SchedModel_BIndices[3];
+// CHECK-NEXT: uint16_t SchedModel_CIndices[3];
+// CHECK: {DBGFIELD(/*Inst_A*/ 19) 1
+// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ 26) 8191
let SchedModel = SchedModel_A in {
def Write_A : SchedWriteRes<[]>;
def : InstRW<[Write_A], (instrs Inst_A)>;
}
-// Inst_A didn't have the resoures, and it is invalid.
-// CHECK: SchedModel_BSchedClasses[] = {
-// CHECK: {DBGFIELD(/*Inst_A*/ 19) 8191
-// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ 26) 1
+// CHECK-NEXT: {DBGFIELD(/*Inst_A*/ 19) 8191
+// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ 26) 1
let SchedModel = SchedModel_B in {
def Write_B: SchedWriteRes<[]>;
def : InstRW<[Write_B], (instrs Inst_B)>;
}
-// CHECK: SchedModel_CSchedClasses[] = {
-// CHECK: {DBGFIELD(/*Inst_A*/ 19) 1
-// CHECK-NEXT: {DBGFIELD(/*Inst_B*/ 26) 1
let SchedModel = SchedModel_C in {
def Write_C: SchedWriteRes<[]>;
def : InstRW<[Write_C], (instrs Inst_A, Inst_B)>;
}
+// SchedModel_A maps Inst_A to the valid descriptor and Inst_B to the invalid
+// descriptor.
+// CHECK: 0, // #0
+// CHECK-NEXT: 1, // #1
+// CHECK-NEXT: 2, // #2
+// SchedModel_B uses the inverse mapping.
+// CHECK: 0, // #0
+// CHECK-NEXT: 3, // #1
+// CHECK-NEXT: 4, // #2
+// Both classes are valid in SchedModel_C.
+// CHECK: 0, // #0
+// CHECK-NEXT: 1, // #1
+// CHECK-NEXT: 4, // #2
+
def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
def ProcessorB: ProcessorModel<"ProcessorB", SchedModel_B, []>;
def ProcessorC: ProcessorModel<"ProcessorC", SchedModel_C, []>;
diff --git a/llvm/test/TableGen/SchedClassTablePooling.td b/llvm/test/TableGen/SchedClassTablePooling.td
new file mode 100644
index 0000000000000..ff3062609a5cf
--- /dev/null
+++ b/llvm/test/TableGen/SchedClassTablePooling.td
@@ -0,0 +1,75 @@
+// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def MyTarget : Target;
+
+let OutOperandList = (outs), InOperandList = (ins) in {
+ def InstA : Instruction;
+ def InstB : Instruction;
+}
+
+let CompleteModel = 0 in {
+ def ModelA : SchedMachineModel;
+ def ModelB : SchedMachineModel;
+}
+
+let SchedModel = ModelA in {
+ def WriteA0 : SchedWriteRes<[]>;
+ def WriteB0 : SchedWriteRes<[]>;
+
+ def : InstRW<[WriteA0], (instrs InstA)>;
+ def : InstRW<[WriteB0], (instrs InstB)>;
+}
+
+let SchedModel = ModelB in {
+ def WriteA1 : SchedWriteRes<[]>;
+ def WriteB1 : SchedWriteRes<[]>;
+
+ def : InstRW<[WriteA1], (instrs InstA)>;
+ def : InstRW<[WriteB1], (instrs InstB)>;
+}
+
+def ProcessorA : ProcessorModel<"processor-a", ModelA, []>;
+def ProcessorB : ProcessorModel<"processor-b", ModelB, []>;
+
+// Debug builds pool descriptors with the scheduling class name in the key.
+// CHECK: #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+// CHECK: static const struct {
+// CHECK-NEXT: llvm::MCSchedClassDesc Descs[3];
+// CHECK-NEXT: uint16_t ModelAIndices[3];
+// CHECK-NEXT: uint16_t ModelBIndices[3];
+// CHECK-NEXT: } MyTargetSchedClassPool = {
+// CHECK: {DBGFIELD(/*InstA*/
+// CHECK: {DBGFIELD(/*InstB*/
+// CHECK: 0, // #0
+// CHECK-NEXT: 1, // #1
+// CHECK-NEXT: 2, // #2
+
+// Release builds omit scheduling class names from the key.
+// CHECK: #else
+// CHECK: static const struct {
+// CHECK-NEXT: llvm::MCSchedClassDesc Descs[2];
+// CHECK-NEXT: uint16_t ModelAIndices[3];
+// CHECK-NEXT: uint16_t ModelBIndices[3];
+// CHECK-NEXT: } MyTargetSchedClassPool = {
+// CHECK: 0, // #0
+// CHECK-NEXT: 1, // #1
+// CHECK-NEXT: 1, // #2
+// CHECK: static_assert(sizeof(MyTargetSchedClassPool.Descs) / sizeof(MyTargetSchedClassPool.Descs[0]) <= (1ULL << 16));
+// CHECK-NEXT: #endif
+
+// CHECK: #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+// CHECK: MyTargetSchedClassNamesStorage[] =
+// CHECK: MyTargetSchedClassNames = MyTargetSchedClassNamesStorage;
+// CHECK-NEXT: #endif
+
+// CHECK: static const llvm::MCSchedModel ModelA = {
+// CHECK: MyTargetSchedClassPool.Descs,
+// CHECK-NEXT: MyTargetSchedClassPool.ModelAIndices,
+// CHECK: DBGFIELD(&MyTargetSchedClassNames)
+
+// CHECK: static const llvm::MCSchedModel ModelB = {
+// CHECK: MyTargetSchedClassPool.Descs,
+// CHECK-NEXT: MyTargetSchedClassPool.ModelBIndices,
+// CHECK: DBGFIELD(&MyTargetSchedClassNames)
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index c3a9d69d6ec3e..49f7a99a74e3d 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -36,7 +36,10 @@
#include <cassert>
#include <cstdint>
#include <iterator>
+#include <limits>
+#include <map>
#include <string>
+#include <tuple>
#include <vector>
using namespace llvm;
@@ -45,7 +48,32 @@ using namespace llvm;
namespace {
+using SchedClassKey =
+ std::tuple<unsigned, uint16_t, bool, bool, bool, uint16_t, uint16_t,
+ uint16_t, uint16_t, uint16_t, uint16_t>;
+
+static SchedClassKey getSchedClassKey(unsigned SchedClassIdx,
+ const MCSchedClassDesc &Desc) {
+ return {SchedClassIdx,
+ Desc.NumMicroOps,
+ Desc.BeginGroup,
+ Desc.EndGroup,
+ Desc.RetireOOO,
+ Desc.WriteProcResIdx,
+ Desc.NumWriteProcResEntries,
+ Desc.WriteLatencyIdx,
+ Desc.NumWriteLatencyEntries,
+ Desc.ReadAdvanceIdx,
+ Desc.NumReadAdvanceEntries};
+}
+
class SubtargetEmitter : TargetFeaturesEmitter {
+ struct SchedClassPool {
+ std::vector<MCSchedClassDesc> Descs;
+ std::vector<unsigned> SchedClassIndices;
+ std::vector<std::vector<uint16_t>> ProcIndices;
+ };
+
// Each processor has a SchedClassDesc table with an entry for each
// SchedClass. The SchedClassDesc table indexes into a global write resource
// table, write latency table, and read advance table.
@@ -55,6 +83,8 @@ class SubtargetEmitter : TargetFeaturesEmitter {
std::vector<MCWriteLatencyEntry> WriteLatencies;
std::vector<std::string> WriterNames;
std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
+ SchedClassPool ReleaseSchedClassPool;
+ SchedClassPool DebugSchedClassPool;
// Reserve an invalid entry at index 0
SchedClassTables() {
@@ -124,8 +154,15 @@ class SubtargetEmitter : TargetFeaturesEmitter {
const CodeGenProcModel &ProcModel);
void genSchedClassTables(const CodeGenProcModel &ProcModel,
SchedClassTables &SchedTables);
+ void buildSchedClassPool(const SchedClassTables &SchedTables,
+ SchedClassPool &Pool, bool IncludeSchedClassName,
+ size_t SchedClassDescSize);
+ void emitSchedClassPool(const SchedClassPool &Pool,
+ ArrayRef<unsigned> SchedClassNameOffsets,
+ raw_ostream &OS);
void emitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
- void emitProcessorModels(raw_ostream &OS);
+ void emitProcessorModels(const SchedClassTables &SchedTables,
+ raw_ostream &OS);
void emitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS);
void emitSchedModelHelpersImpl(raw_ostream &OS,
bool OnlyExpandMCInstPredicates = false);
@@ -1332,6 +1369,100 @@ void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel,
}
}
+void SubtargetEmitter::buildSchedClassPool(const SchedClassTables &SchedTables,
+ SchedClassPool &Pool,
+ bool IncludeSchedClassName,
+ size_t SchedClassDescSize) {
+ std::map<SchedClassKey, uint16_t> PoolIndices;
+ size_t NumSchedClassDescs = 0;
+
+ Pool = {};
+ Pool.ProcIndices.resize(SchedTables.ProcSchedClasses.size());
+
+ for (const auto &[Idx, Proc] : enumerate(SchedModels.procModels())) {
+ if (!Proc.hasInstrSchedModel())
+ continue;
+
+ const std::vector<MCSchedClassDesc> &SCTab =
+ SchedTables.ProcSchedClasses[1 + Idx];
+ std::vector<uint16_t> &Indices = Pool.ProcIndices[1 + Idx];
+ Indices.reserve(SCTab.size());
+ NumSchedClassDescs += SCTab.size();
+
+ for (const auto &[SchedClassIdx, Desc] : enumerate(SCTab)) {
+ SchedClassKey Key =
+ getSchedClassKey(IncludeSchedClassName ? SchedClassIdx : 0, Desc);
+ auto It = PoolIndices.find(Key);
+ if (It == PoolIndices.end()) {
+ if (Pool.Descs.size() > std::numeric_limits<uint16_t>::max()) {
+ Pool = {};
+ return;
+ }
+ uint16_t PoolIdx = Pool.Descs.size();
+ It = PoolIndices.emplace(std::move(Key), PoolIdx).first;
+ Pool.Descs.push_back(Desc);
+ Pool.SchedClassIndices.push_back(SchedClassIdx);
+ }
+ Indices.push_back(It->second);
+ }
+ }
+
+ size_t DirectSize = NumSchedClassDescs * SchedClassDescSize;
+ size_t PooledSize = Pool.Descs.size() * SchedClassDescSize +
+ NumSchedClassDescs * sizeof(uint16_t);
+ if (PooledSize >= DirectSize)
+ Pool = {};
+}
+
+static void emitSchedClassDesc(raw_ostream &OS, const MCSchedClassDesc &Desc) {
+ OS << Desc.NumMicroOps << ", " << (Desc.BeginGroup ? "true" : "false") << ", "
+ << (Desc.EndGroup ? "true" : "false") << ", "
+ << (Desc.RetireOOO ? "true" : "false") << ", "
+ << format("%2d", Desc.WriteProcResIdx) << ", "
+ << Desc.NumWriteProcResEntries << ", "
+ << format("%2d", Desc.WriteLatencyIdx) << ", "
+ << Desc.NumWriteLatencyEntries << ", "
+ << format("%2d", Desc.ReadAdvanceIdx) << ", " << Desc.NumReadAdvanceEntries
+ << '}';
+}
+
+void SubtargetEmitter::emitSchedClassPool(
+ const SchedClassPool &Pool, ArrayRef<unsigned> SchedClassNameOffsets,
+ raw_ostream &OS) {
+ OS << "\nstatic const struct {\n"
+ << " llvm::MCSchedClassDesc Descs[" << Pool.Descs.size() << "];\n";
+ for (const auto &[Idx, Proc] : enumerate(SchedModels.procModels())) {
+ if (!Proc.hasInstrSchedModel())
+ continue;
+ OS << " uint16_t " << Proc.ModelName << "Indices["
+ << Pool.ProcIndices[1 + Idx].size() << "];\n";
+ }
+ OS << "} " << Target << "SchedClassPool = {\n {\n";
+ for (const auto &[PoolIdx, Desc] : enumerate(Pool.Descs)) {
+ unsigned SchedClassIdx = Pool.SchedClassIndices[PoolIdx];
+ StringRef Name = "InvalidSchedClass";
+ if (SchedClassIdx != 0)
+ Name = SchedModels.getSchedClass(SchedClassIdx).Name;
+ OS << " {DBGFIELD(/*" << Name << "*/ "
+ << SchedClassNameOffsets[SchedClassIdx] << ") ";
+ emitSchedClassDesc(OS, Desc);
+ OS << ", // #" << PoolIdx << '\n';
+ }
+ OS << " },\n";
+ for (const auto &[Idx, Proc] : enumerate(SchedModels.procModels())) {
+ if (!Proc.hasInstrSchedModel())
+ continue;
+ OS << " {\n";
+ for (const auto [SchedClassIdx, PoolIdx] :
+ enumerate(Pool.ProcIndices[1 + Idx]))
+ OS << " " << PoolIdx << ", // #" << SchedClassIdx << '\n';
+ OS << " },\n";
+ }
+ OS << "};\n";
+ OS << "static_assert(sizeof(" << Target << "SchedClassPool.Descs) / sizeof("
+ << Target << "SchedClassPool.Descs[0]) <= (1ULL << 16));\n";
+}
+
// Emit SchedClass tables for all processors and associated global tables.
void SubtargetEmitter::emitSchedClassTables(SchedClassTables &SchedTables,
raw_ostream &OS) {
@@ -1387,53 +1518,62 @@ void SubtargetEmitter::emitSchedClassTables(SchedClassTables &SchedTables,
// Pool all SchedClass names in a string table.
StringToOffsetTable StrTab;
- unsigned InvalidNameOff = StrTab.GetOrAddStringOffset("InvalidSchedClass");
-
- // Emit a SchedClass table for each processor.
- for (const auto &[Idx, Proc] : enumerate(SchedModels.procModels())) {
- if (!Proc.hasInstrSchedModel())
- continue;
-
- std::vector<MCSchedClassDesc> &SCTab =
- SchedTables.ProcSchedClasses[1 + Idx];
+ std::vector<unsigned> SchedClassNameOffsets(
+ SchedModels.schedClasses().size());
+ assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" &&
+ "invalid class not first");
+ SchedClassNameOffsets[0] = StrTab.GetOrAddStringOffset("InvalidSchedClass");
+ for (unsigned Idx = 1; Idx != SchedModels.schedClasses().size(); ++Idx)
+ SchedClassNameOffsets[Idx] =
+ StrTab.GetOrAddStringOffset(SchedModels.getSchedClass(Idx).Name);
+
+ bool UseSchedClassPool = !SchedTables.ReleaseSchedClassPool.Descs.empty() &&
+ !SchedTables.DebugSchedClassPool.Descs.empty();
+ if (UseSchedClassPool) {
+ OS << "\n#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n";
+ emitSchedClassPool(SchedTables.DebugSchedClassPool, SchedClassNameOffsets,
+ OS);
+ OS << "#else\n";
+ emitSchedClassPool(SchedTables.ReleaseSchedClassPool, SchedClassNameOffsets,
+ OS);
+ OS << "#endif\n";
+ } else {
+ // Emit a SchedClass table for each processor.
+ for (const auto &[Idx, Proc] : enumerate(SchedModels.procModels())) {
+ if (!Proc.hasInstrSchedModel())
+ continue;
- OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"
- << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
- OS << "static const llvm::MCSchedClassDesc " << Proc.ModelName
- << "SchedClasses[] = {\n";
-
- // The first class is always invalid. We no way to distinguish it except by
- // name and position.
- assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" &&
- "invalid class not first");
- OS << " {DBGFIELD(" << InvalidNameOff << ") "
- << MCSchedClassDesc::InvalidNumMicroOps
- << ", false, false, false, 0, 0, 0, 0, 0, 0},\n";
-
- for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
- MCSchedClassDesc &MCDesc = SCTab[SCIdx];
- const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
- unsigned NameOff = StrTab.GetOrAddStringOffset(SchedClass.Name);
- OS << " {DBGFIELD(/*" << SchedClass.Name << "*/ " << NameOff << ") ";
- if (SchedClass.Name.size() < 18)
- OS.indent(18 - SchedClass.Name.size());
- OS << MCDesc.NumMicroOps << ", " << (MCDesc.BeginGroup ? "true" : "false")
- << ", " << (MCDesc.EndGroup ? "true" : "false") << ", "
- << (MCDesc.RetireOOO ? "true" : "false") << ", "
- << format("%2d", MCDesc.WriteProcResIdx) << ", "
- << MCDesc.NumWriteProcResEntries << ", "
- << format("%2d", MCDesc.WriteLatencyIdx) << ", "
- << MCDesc.NumWriteLatencyEntries << ", "
- << format("%2d", MCDesc.ReadAdvanceIdx) << ", "
- << MCDesc.NumReadAdvanceEntries << "}, // #" << SCIdx << '\n';
+ std::vector<MCSchedClassDesc> &SCTab =
+ SchedTables.ProcSchedClasses[1 + Idx];
+ OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"
+ << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"
+ << "static const llvm::MCSchedClassDesc " << Proc.ModelName
+ << "SchedClasses[] = {\n"
+ << " {DBGFIELD(" << SchedClassNameOffsets[0] << ") "
+ << MCSchedClassDesc::InvalidNumMicroOps
+ << ", false, false, false, 0, 0, 0, 0, 0, 0},\n";
+ for (unsigned SCIdx = 1, End = SCTab.size(); SCIdx != End; ++SCIdx) {
+ const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx);
+ OS << " {DBGFIELD(/*" << SchedClass.Name << "*/ "
+ << SchedClassNameOffsets[SCIdx] << ") ";
+ if (SchedClass.Name.size() < 18)
+ OS.indent(18 - SchedClass.Name.size());
+ emitSchedClassDesc(OS, SCTab[SCIdx]);
+ OS << ", // #" << SCIdx << '\n';
+ }
+ OS << "}; // " << Proc.ModelName << "SchedClasses\n";
}
- OS << "}; // " << Proc.ModelName << "SchedClasses\n";
}
+ OS << "\n#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n";
StrTab.EmitStringTableDef(OS, Target + "SchedClassNames");
+ OS << "#endif\n";
}
-void SubtargetEmitter::emitProcessorModels(raw_ostream &OS) {
+void SubtargetEmitter::emitProcessorModels(const SchedClassTables &SchedTables,
+ raw_ostream &OS) {
+ bool UseSchedClassPool = !SchedTables.ReleaseSchedClassPool.Descs.empty() &&
+ !SchedTables.DebugSchedClassPool.Descs.empty();
// For each processor model.
for (const CodeGenProcModel &PM : SchedModels.procModels()) {
// Emit extra processor info if available.
@@ -1477,21 +1617,32 @@ void SubtargetEmitter::emitProcessorModels(raw_ostream &OS) {
OS << " " << PM.Index << ", // Processor ID\n";
if (PM.hasInstrSchedModel())
- OS << " " << PM.ModelName << "ProcResources" << ",\n"
- << " " << PM.ModelName << "SchedClasses" << ",\n"
- << " " << PM.ProcResourceDefs.size() + 1 << ",\n"
+ OS << " " << PM.ModelName << "ProcResources" << ",\n";
+ else
+ OS << " nullptr,\n";
+ if (PM.hasInstrSchedModel() && UseSchedClassPool)
+ OS << " " << Target << "SchedClassPool.Descs,\n";
+ else if (PM.hasInstrSchedModel())
+ OS << " " << PM.ModelName << "SchedClasses,\n";
+ else
+ OS << " nullptr,\n";
+ if (PM.hasInstrSchedModel() && UseSchedClassPool)
+ OS << " " << Target << "SchedClassPool." << PM.ModelName << "Indices,\n";
+ else
+ OS << " nullptr,\n";
+ if (PM.hasInstrSchedModel())
+ OS << " " << PM.ProcResourceDefs.size() + 1 << ",\n"
<< " " << SchedModels.schedClasses().size() << ",\n";
else
- OS << " nullptr, nullptr, 0, 0,"
+ OS << " 0, 0,"
<< " // No instruction-level machine model.\n";
- OS << " DBGVAL_OR_NULLPTR(&" << Target
- << "SchedClassNames), // SchedClassNames\n";
+ OS << " DBGFIELD(&" << Target << "SchedClassNames)\n";
if (PM.hasItineraries())
OS << " " << PM.ItinsDef->getName() << ",\n";
else
OS << " nullptr, // No Itinerary\n";
if (PM.hasExtraProcessorInfo())
- OS << " &" << PM.ModelName << "ExtraInfo,\n";
+ OS << " &" << PM.ModelName << "ExtraInfo\n";
else
OS << " nullptr // No extra processor descriptor\n";
OS << "};\n";
@@ -1507,10 +1658,8 @@ void SubtargetEmitter::emitSchedModel(raw_ostream &OS) {
<< "#endif\n"
<< "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n"
<< "#define DBGFIELD(x) x,\n"
- << "#define DBGVAL_OR_NULLPTR(x) x\n"
<< "#else\n"
<< "#define DBGFIELD(x)\n"
- << "#define DBGVAL_OR_NULLPTR(x) nullptr\n"
<< "#endif\n";
if (SchedModels.hasItineraries()) {
@@ -1526,13 +1675,18 @@ void SubtargetEmitter::emitSchedModel(raw_ostream &OS) {
for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
genSchedClassTables(ProcModel, SchedTables);
}
+ buildSchedClassPool(SchedTables, SchedTables.ReleaseSchedClassPool,
+ /*IncludeSchedClassName=*/false,
+ /*SchedClassDescSize=*/14);
+ buildSchedClassPool(SchedTables, SchedTables.DebugSchedClassPool,
+ /*IncludeSchedClassName=*/true,
+ /*SchedClassDescSize=*/20);
emitSchedClassTables(SchedTables, OS);
// Emit the processor machine model
- emitProcessorModels(OS);
+ emitProcessorModels(SchedTables, OS);
OS << "\n#undef DBGFIELD\n";
- OS << "\n#undef DBGVAL_OR_NULLPTR\n";
}
static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {
More information about the llvm-commits
mailing list