diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td index 2562ed0901303..f55bff16dcecd 100644 --- a/llvm/include/llvm/Target/TargetSchedule.td +++ b/llvm/include/llvm/Target/TargetSchedule.td @@ -321,9 +321,13 @@ class SchedWriteRes resources> : SchedWrite, // Define values common to ReadAdvance and SchedReadAdvance. // // SchedModel ties these resources to a processor. -class ProcReadAdvance writes = []> { +class ProcReadAdvance writes = [], + list tunables = []> { + assert !le(!size(tunables), !size(writes)), + "cannot have more `tunables' than `writes'"; int Cycles = cycles; list ValidWrites = writes; + list CycleTunables = tunables; // Allow a processor to mark some scheduling classes as unsupported // for stronger verification. bit Unsupported = false; @@ -340,15 +344,17 @@ class ProcReadAdvance 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 writes = []> - : ProcReadAdvance { +class ReadAdvance writes = [], + list tunables = []> + : ProcReadAdvance { SchedRead ReadType = read; } // Directly associate a new SchedRead type with a delay and optional // pipeline bypass. For use with InstRW or ItinRW. -class SchedReadAdvance writes = []> : SchedRead, - ProcReadAdvance; +class SchedReadAdvance writes = [], + list tunables = []> + : SchedRead, ProcReadAdvance; // Define SchedRead defaults. Reads seldom need special treatment. def ReadDefault : SchedRead; diff --git a/llvm/test/TableGen/PerWriteCycleCount.td b/llvm/test/TableGen/PerWriteCycleCount.td new file mode 100644 index 0000000000000..ac60d8c438834 --- /dev/null +++ b/llvm/test/TableGen/PerWriteCycleCount.td @@ -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; + +#ifdef ERROR1 +// ERROR1: error: assertion failed: cannot have more `tunables' than `writes' + def : ReadAdvance; +#endif +} + +def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>; diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 49362ff5ef655..aec05f1ae7742 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -1308,23 +1308,27 @@ void SubtargetEmitter::genSchedClassTables(const CodeGenProcModel &ProcModel, } ConstRecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites"); - IdxVec WriteIDs; + std::vector CycleTunables = + ReadAdvance->getValueAsListOfInts("CycleTunables"); + std::vector> 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); } }