Skip to content

Commit 4bfe410

Browse files
committed
[TableGen][SubtargetEmitter] Add the StartAtCycles field in the WriteRes class.
Conditions that need to be met: 1. count(StartAtCycle) == count(ReservedCycles); 2. For each i: StartAtCycles[i] < ReservedCycles[i]; 3. For each i: StartAtCycles[i] >= 0; 4. If left unspecified, the elements are set to 0. Differential Revision: https://reviews.llvm.org/D150310
1 parent 0e37ef0 commit 4bfe410

File tree

5 files changed

+165
-16
lines changed

5 files changed

+165
-16
lines changed

llvm/include/llvm/MC/MCSchedule.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,14 @@ struct MCProcResourceDesc {
6363
struct MCWriteProcResEntry {
6464
uint16_t ProcResourceIdx;
6565
uint16_t Cycles;
66+
// Cycle at which the resource will be grabbed by an instruction,
67+
// relatively to the cycle in which the instruction is issued
68+
// (assuming no stalls inbetween).
69+
uint16_t StartAtCycle;
6670

6771
bool operator==(const MCWriteProcResEntry &Other) const {
68-
return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles;
72+
return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles &&
73+
StartAtCycle == Other.StartAtCycle;
6974
}
7075
};
7176

llvm/include/llvm/Target/TargetSchedule.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ class WriteSequence<list<SchedWrite> writes, int rep = 1> : SchedWrite {
250250
class ProcWriteResources<list<ProcResourceKind> resources> {
251251
list<ProcResourceKind> ProcResources = resources;
252252
list<int> ResourceCycles = [];
253+
list<int> StartAtCycles = [];
253254
int Latency = 1;
254255
int NumMicroOps = 1;
255256
bit BeginGroup = false;

llvm/test/TableGen/StartAtCycle.td

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: llvm-tblgen -gen-subtarget -DCORRECT -I %p/../../include %s 2>&1 | \
2+
// RUN: FileCheck %s --check-prefix=CORRECT
3+
4+
// RUN: not llvm-tblgen -gen-subtarget -DWRONG_SIZE -I %p/../../include %s 2>&1 | \
5+
// RUN: FileCheck %s --check-prefix=WRONG_SIZE
6+
7+
// RUN: not llvm-tblgen -gen-subtarget -DWRONG_VALUE -I %p/../../include %s 2>&1 | \
8+
// RUN: FileCheck %s --check-prefix=WRONG_VALUE
9+
10+
// RUN: not llvm-tblgen -gen-subtarget -DNEGATIVE_INVALID -I %p/../../include %s 2>&1 | \
11+
// RUN: FileCheck %s --check-prefix=NEGATIVE_INVALID
12+
13+
// Make sure that StartAtCycle in WriteRes is used to generate the
14+
// correct data.
15+
16+
include "llvm/Target/Target.td"
17+
18+
def MyTarget : Target;
19+
20+
let BufferSize = 0 in {
21+
def ResX0 : ProcResource<1>; // X0
22+
def ResX1 : ProcResource<1>; // X1
23+
def ResX2 : ProcResource<1>; // X2
24+
}
25+
26+
let OutOperandList = (outs), InOperandList = (ins) in {
27+
def Inst_A : Instruction;
28+
def Inst_B : Instruction;
29+
}
30+
31+
let CompleteModel = 0 in {
32+
def SchedModel_A: SchedMachineModel;
33+
}
34+
35+
def WriteInst_A : SchedWrite;
36+
def WriteInst_B : SchedWrite;
37+
38+
let SchedModel = SchedModel_A in {
39+
// Check the generated data when there are no semantic issues.
40+
#ifdef CORRECT
41+
// CORRECT-LABEL: llvm::MCWriteProcResEntry MyTargetWriteProcResTable[] = {
42+
// CORRECT-NEXT: { 0, 0, 0 }, // Invalid
43+
def : WriteRes<WriteInst_A, [ResX0, ResX1, ResX2]> {
44+
// CORRECT-NEXT: { 1, 2, 0}, // #1
45+
// CORRECT-NEXT: { 2, 4, 1}, // #2
46+
// CORRECT-NEXT: { 3, 3, 2}, // #3
47+
let ResourceCycles = [2, 4, 3];
48+
let StartAtCycles = [0, 1, 2];
49+
}
50+
def : WriteRes<WriteInst_B, [ResX2]> {
51+
// If unspecified, StartAtCycle is set to 0.
52+
// CORRECT-NEXT: { 3, 1, 0} // #4
53+
let ResourceCycles = [1];
54+
}
55+
#endif // CORRECT
56+
57+
#ifdef WRONG_SIZE
58+
// WRONG_SIZE: StartAtCycle.td:[[@LINE+1]]:1: error: Inconsistent resource cycles: size(StartAtCycles) != size(ProcResources): 2 vs 3
59+
def : WriteRes<WriteInst_A, [ResX0, ResX1, ResX2]> {
60+
let ResourceCycles = [2, 4, 3];
61+
let StartAtCycles = [0, 1];
62+
}
63+
#endif
64+
65+
#ifdef WRONG_VALUE
66+
// WRONG_VALUE: StartAtCycle.td:[[@LINE+1]]:1: error: Inconsistent resource cycles: StartAtCycles < Cycles must hold
67+
def : WriteRes<WriteInst_A, [ResX0, ResX1, ResX2]> {
68+
let ResourceCycles = [2, 4, 3];
69+
let StartAtCycles = [0, 1, 8];
70+
}
71+
#endif
72+
73+
#ifdef NEGATIVE_INVALID
74+
// NEGATIVE_INVALID: StartAtCycle.td:[[@LINE+1]]:1: error: Invalid value: StartAtCycle must be a non-negative value.
75+
def : WriteRes<WriteInst_A, [ResX0]> {
76+
let ResourceCycles = [2];
77+
let StartAtCycles = [-1];
78+
}
79+
#endif
80+
81+
def : InstRW<[WriteInst_A], (instrs Inst_A)>;
82+
def : InstRW<[WriteInst_B], (instrs Inst_B)>;
83+
}
84+
85+
def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
86+

llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,14 @@ getNonRedundantWriteProcRes(const MCSchedClassDesc &SCDesc,
8383
const MCWriteProcResEntry *WPR = Entry.second;
8484
const MCProcResourceDesc *const ProcResDesc =
8585
SM.getProcResource(WPR->ProcResourceIdx);
86+
// TODO: Handle StartAtCycle in llvm-exegesis and llvm-mca. See
87+
// https://github.com/llvm/llvm-project/issues/62680 and
88+
// https://github.com/llvm/llvm-project/issues/62681
89+
assert(WPR->StartAtCycle == 0 &&
90+
"`llvm-exegesis` does not handle StartAtCycle > 0");
8691
if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
8792
// This is a ProcResUnit.
88-
Result.push_back({WPR->ProcResourceIdx, WPR->Cycles});
93+
Result.push_back({WPR->ProcResourceIdx, WPR->Cycles, WPR->StartAtCycle});
8994
ProcResUnitUsage[WPR->ProcResourceIdx] += WPR->Cycles;
9095
} else {
9196
// This is a ProcResGroup. First see if it contributes any cycles or if
@@ -102,7 +107,8 @@ getNonRedundantWriteProcRes(const MCSchedClassDesc &SCDesc,
102107
}
103108
// The ProcResGroup contributes `RemainingCycles` cycles of its own.
104109
Result.push_back({WPR->ProcResourceIdx,
105-
static_cast<uint16_t>(std::round(RemainingCycles))});
110+
static_cast<uint16_t>(std::round(RemainingCycles)),
111+
WPR->StartAtCycle});
106112
// Spread the remaining cycles over all subunits.
107113
for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
108114
SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;

llvm/utils/TableGen/SubtargetEmitter.cpp

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class SubtargetEmitter {
111111
Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
112112
const CodeGenProcModel &ProcModel);
113113
void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
114+
std::vector<int64_t> &StartAtCycles,
114115
const CodeGenProcModel &ProcModel);
115116
void GenSchedClassTables(const CodeGenProcModel &ProcModel,
116117
SchedClassTables &SchedTables);
@@ -968,6 +969,7 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
968969
// resource groups and super resources that cover them.
969970
void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
970971
std::vector<int64_t> &Cycles,
972+
std::vector<int64_t> &StartAtCycles,
971973
const CodeGenProcModel &PM) {
972974
assert(PRVec.size() == Cycles.size() && "failed precondition");
973975
for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
@@ -990,6 +992,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
990992
SubDef->getLoc());
991993
PRVec.push_back(SuperDef);
992994
Cycles.push_back(Cycles[i]);
995+
StartAtCycles.push_back(StartAtCycles[i]);
993996
SubDef = SuperDef;
994997
}
995998
}
@@ -1006,6 +1009,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
10061009
if (SubI == SubE) {
10071010
PRVec.push_back(PR);
10081011
Cycles.push_back(Cycles[i]);
1012+
StartAtCycles.push_back(StartAtCycles[i]);
10091013
}
10101014
}
10111015
}
@@ -1140,29 +1144,66 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
11401144
std::vector<int64_t> Cycles =
11411145
WriteRes->getValueAsListOfInts("ResourceCycles");
11421146

1143-
if (Cycles.empty()) {
1144-
// If ResourceCycles is not provided, default to one cycle per
1145-
// resource.
1146-
Cycles.resize(PRVec.size(), 1);
1147-
} else if (Cycles.size() != PRVec.size()) {
1147+
std::vector<int64_t> StartAtCycles =
1148+
WriteRes->getValueAsListOfInts("StartAtCycles");
1149+
1150+
// Check consistency of the two vectors carrying the start and
1151+
// stop cycles of the resources.
1152+
if (!Cycles.empty() && Cycles.size() != PRVec.size()) {
11481153
// If ResourceCycles is provided, check consistency.
11491154
PrintFatalError(
11501155
WriteRes->getLoc(),
1151-
Twine("Inconsistent resource cycles: !size(ResourceCycles) != "
1152-
"!size(ProcResources): ")
1156+
Twine("Inconsistent resource cycles: size(ResourceCycles) != "
1157+
"size(ProcResources): ")
11531158
.concat(Twine(PRVec.size()))
11541159
.concat(" vs ")
11551160
.concat(Twine(Cycles.size())));
11561161
}
11571162

1158-
ExpandProcResources(PRVec, Cycles, ProcModel);
1163+
if (!StartAtCycles.empty() && StartAtCycles.size() != PRVec.size()) {
1164+
PrintFatalError(
1165+
WriteRes->getLoc(),
1166+
Twine("Inconsistent resource cycles: size(StartAtCycles) != "
1167+
"size(ProcResources): ")
1168+
.concat(Twine(StartAtCycles.size()))
1169+
.concat(" vs ")
1170+
.concat(Twine(PRVec.size())));
1171+
}
1172+
1173+
if (Cycles.empty()) {
1174+
// If ResourceCycles is not provided, default to one cycle
1175+
// per resource.
1176+
Cycles.resize(PRVec.size(), 1);
1177+
}
1178+
1179+
if (StartAtCycles.empty()) {
1180+
// If StartAtCycles is not provided, reserve the resource
1181+
// starting from cycle 0.
1182+
StartAtCycles.resize(PRVec.size(), 0);
1183+
}
1184+
1185+
assert(StartAtCycles.size() == Cycles.size());
1186+
1187+
ExpandProcResources(PRVec, Cycles, StartAtCycles, ProcModel);
1188+
assert(StartAtCycles.size() == Cycles.size());
11591189

11601190
for (unsigned PRIdx = 0, PREnd = PRVec.size();
11611191
PRIdx != PREnd; ++PRIdx) {
11621192
MCWriteProcResEntry WPREntry;
11631193
WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
11641194
assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
11651195
WPREntry.Cycles = Cycles[PRIdx];
1196+
WPREntry.StartAtCycle = StartAtCycles[PRIdx];
1197+
if (StartAtCycles[PRIdx] > Cycles[PRIdx]) {
1198+
PrintFatalError(WriteRes->getLoc(),
1199+
Twine("Inconsistent resource cycles: StartAtCycles "
1200+
"< Cycles must hold."));
1201+
}
1202+
if (StartAtCycles[PRIdx] < 0) {
1203+
PrintFatalError(WriteRes->getLoc(),
1204+
Twine("Invalid value: StartAtCycle "
1205+
"must be a non-negative value."));
1206+
}
11661207
// If this resource is already used in this sequence, add the current
11671208
// entry's cycles so that the same resource appears to be used
11681209
// serially, rather than multiple parallel uses. This is important for
@@ -1171,6 +1212,15 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
11711212
for( ; WPRIdx != WPREnd; ++WPRIdx) {
11721213
if (WriteProcResources[WPRIdx].ProcResourceIdx
11731214
== WPREntry.ProcResourceIdx) {
1215+
// TODO: multiple use of the same resources would
1216+
// require either 1. thinking of how to handle multiple
1217+
// intervals for the same resource in
1218+
// `<Target>WriteProcResTable` (see
1219+
// `SubtargetEmitter::EmitSchedClassTables`), or
1220+
// 2. thinking how to merge multiple intervals into a
1221+
// single interval.
1222+
assert(WPREntry.StartAtCycle == 0 &&
1223+
"multiple use ofthe same resource is not yet handled");
11741224
WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
11751225
break;
11761226
}
@@ -1275,15 +1325,16 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
12751325
void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
12761326
raw_ostream &OS) {
12771327
// Emit global WriteProcResTable.
1278-
OS << "\n// {ProcResourceIdx, Cycles}\n"
1279-
<< "extern const llvm::MCWriteProcResEntry "
1280-
<< Target << "WriteProcResTable[] = {\n"
1281-
<< " { 0, 0}, // Invalid\n";
1328+
OS << "\n// {ProcResourceIdx, Cycles, StartAtCycle}\n"
1329+
<< "extern const llvm::MCWriteProcResEntry " << Target
1330+
<< "WriteProcResTable[] = {\n"
1331+
<< " { 0, 0, 0 }, // Invalid\n";
12821332
for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
12831333
WPRIdx != WPREnd; ++WPRIdx) {
12841334
MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
12851335
OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
1286-
<< format("%2d", WPREntry.Cycles) << "}";
1336+
<< format("%2d", WPREntry.Cycles) << ", "
1337+
<< format("%2d", WPREntry.StartAtCycle) << "}";
12871338
if (WPRIdx + 1 < WPREnd)
12881339
OS << ',';
12891340
OS << " // #" << WPRIdx << '\n';

0 commit comments

Comments
 (0)