Skip to content

[TableGen] Add support for per-write cycle tunables #125870

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions llvm/include/llvm/Target/TargetSchedule.td
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,13 @@ class SchedWriteRes<list<ProcResourceKind> resources> : SchedWrite,
// Define values common to ReadAdvance and SchedReadAdvance.
//
// SchedModel ties these resources to a processor.
class ProcReadAdvance<int cycles, list<SchedWrite> writes = []> {
class ProcReadAdvance<int cycles, list<SchedWrite> writes = [],
list<int> tunables = []> {
assert !le(!size(tunables), !size(writes)),
"cannot have more `tunables' than `writes'";
int Cycles = cycles;
list<SchedWrite> ValidWrites = writes;
list<int> CycleTunables = tunables;
// Allow a processor to mark some scheduling classes as unsupported
// for stronger verification.
bit Unsupported = false;
Expand All @@ -340,15 +344,17 @@ class ProcReadAdvance<int cycles, list<SchedWrite> writes = []> {
// indicate operands that are always read this number of Cycles later
// than a normal register read, allowing the read's parent instruction
// to issue earlier relative to the writer.
class ReadAdvance<SchedRead read, int cycles, list<SchedWrite> writes = []>
: ProcReadAdvance<cycles, writes> {
class ReadAdvance<SchedRead read, int cycles, list<SchedWrite> writes = [],
list<int> tunables = []>
: ProcReadAdvance<cycles, writes, tunables> {
SchedRead ReadType = read;
}

// Directly associate a new SchedRead type with a delay and optional
// pipeline bypass. For use with InstRW or ItinRW.
class SchedReadAdvance<int cycles, list<SchedWrite> writes = []> : SchedRead,
ProcReadAdvance<cycles, writes>;
class SchedReadAdvance<int cycles, list<SchedWrite> writes = [],
list<int> tunables = []>
: SchedRead, ProcReadAdvance<cycles, writes, tunables>;

// Define SchedRead defaults. Reads seldom need special treatment.
def ReadDefault : SchedRead;
Expand Down
48 changes: 48 additions & 0 deletions llvm/test/TableGen/PerWriteCycleCount.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s 2>&1 | FileCheck %s
// RUN: not llvm-tblgen -gen-subtarget -I %p/../../include -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s

// Make sure that ReadAdvance entries with multiple writes are correctly
// handled.

include "llvm/Target/Target.td"

def MyTarget : Target;

let OutOperandList = (outs), InOperandList = (ins) in {
def Inst_A : Instruction;
def Inst_B : Instruction;
def Inst_C : Instruction;
}

let CompleteModel = 0 in {
def SchedModel_A: SchedMachineModel;
}

def Read_D : SchedRead;
def Read_E : SchedRead;

// CHECK: extern const llvm::MCReadAdvanceEntry MyTargetReadAdvanceTable[] = {
// CHECK-NEXT: {0, 0, 0}, // Invalid
// CHECK-NEXT: {0, 1, 1}, // #1
// CHECK-NEXT: {0, 2, 3}, // #2
// CHECK-NEXT: {0, 3, 2} // #3
// CHECK-NEXT: }; // MyTargetReadAdvanceTable

let SchedModel = SchedModel_A in {
def Write_A : SchedWriteRes<[]>;
def Write_B : SchedWriteRes<[]>;
def Write_C : SchedWriteRes<[]>;

def : InstRW<[Write_A], (instrs Inst_A)>;
def : InstRW<[Write_B], (instrs Inst_B)>;
def : InstRW<[Write_C, Read_D], (instrs Inst_C)>;

def : ReadAdvance<Read_D, 2, [Write_A, Write_B, Write_C], [-1, 1]>;

#ifdef ERROR1
// ERROR1: error: assertion failed: cannot have more `tunables' than `writes'
def : ReadAdvance<Read_E, 2, [Write_A, Write_B, Write_C], [1, 2, 3, 4]>;
#endif
}

def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
16 changes: 10 additions & 6 deletions llvm/utils/TableGen/SubtargetEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1308,23 +1308,27 @@ void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel,
}
ConstRecVec ValidWrites =
ReadAdvance->getValueAsListOfDefs("ValidWrites");
IdxVec WriteIDs;
std::vector<int64_t> CycleTunables =
ReadAdvance->getValueAsListOfInts("CycleTunables");
std::vector<std::pair<unsigned, int>> WriteIDs;
assert(CycleTunables.size() <= ValidWrites.size() && "Bad ReadAdvance");
CycleTunables.resize(ValidWrites.size(), 0);
if (ValidWrites.empty())
WriteIDs.push_back(0);
WriteIDs.emplace_back(0, 0);
else {
for (const Record *VW : ValidWrites) {
for (const auto [VW, CT] : zip_equal(ValidWrites, CycleTunables)) {
unsigned WriteID = SchedModels.getSchedRWIdx(VW, /*IsRead=*/false);
assert(WriteID != 0 &&
"Expected a valid SchedRW in the list of ValidWrites");
WriteIDs.push_back(WriteID);
WriteIDs.emplace_back(WriteID, CT);
}
}
llvm::sort(WriteIDs);
for (unsigned W : WriteIDs) {
for (const auto &[W, T] : WriteIDs) {
MCReadAdvanceEntry RAEntry;
RAEntry.UseIdx = UseIdx;
RAEntry.WriteResourceID = W;
RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles") + T;
ReadAdvanceEntries.push_back(RAEntry);
}
}
Expand Down