Index: llvm/include/llvm/MC/MCSchedule.h =================================================================== --- llvm/include/llvm/MC/MCSchedule.h +++ llvm/include/llvm/MC/MCSchedule.h @@ -78,8 +78,9 @@ /// Specify the number of cycles allowed after instruction issue before a /// particular use operand reads its registers. This effectively reduces the /// write's latency. Here we allow negative cycles for corner cases where -/// latency increases. This rule only applies when the entry's WriteResource -/// matches the write's WriteResource. +/// latency increases. Optionally, the read instruction may be clustered with +/// the write instruction. This rule only applies when the entry's +/// WriteResource matches the write's WriteResource. /// /// MCReadAdvanceEntries are sorted first by operand index (UseIdx), then by /// WriteResourceIdx. @@ -87,6 +88,7 @@ unsigned UseIdx; unsigned WriteResourceID; int Cycles; + bool Cluster; bool operator==(const MCReadAdvanceEntry &Other) const { return UseIdx == Other.UseIdx && WriteResourceID == Other.WriteResourceID Index: llvm/include/llvm/MC/MCSubtargetInfo.h =================================================================== --- llvm/include/llvm/MC/MCSubtargetInfo.h +++ llvm/include/llvm/MC/MCSubtargetInfo.h @@ -145,7 +145,7 @@ } int getReadAdvanceCycles(const MCSchedClassDesc *SC, unsigned UseIdx, - unsigned WriteResID) const { + unsigned WriteResID, bool *Cluster = nullptr) const { // TODO: The number of read advance entries in a class can be significant // (~50). Consider compressing the WriteID into a dense ID of those that are // used by ReadAdvance and representing them as a bitset. @@ -157,6 +157,8 @@ break; // Find the first WriteResIdx match, which has the highest cycle count. if (!I->WriteResourceID || I->WriteResourceID == WriteResID) { + if (Cluster != nullptr) + *Cluster = I->Cluster; return I->Cycles; } } Index: llvm/include/llvm/Target/TargetSchedule.td =================================================================== --- llvm/include/llvm/Target/TargetSchedule.td +++ llvm/include/llvm/Target/TargetSchedule.td @@ -312,6 +312,7 @@ class ProcReadAdvance writes = []> { int Cycles = cycles; list ValidWrites = writes; + bit Cluster = 0; // Allow a processor to mark some scheduling classes as unsupported // for stronger verification. bit Unsupported = 0; @@ -333,10 +334,24 @@ SchedRead ReadType = read; } +// A processor may define a similar pipeline bypass that also requires that the +// reader and writer instructions be clustered together and scheduled back to +// back. +class ReadCluster writes = []> + : ReadAdvance { + let Cluster = 1; +} + // 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 = []> + : SchedRead, ProcReadAdvance; + +// Likewise, with clustered instructions. +class SchedReadCluster writes = []> + : SchedReadAdvance { + let Cluster = 1; +} // Define SchedRead defaults. Reads seldom need special treatment. def ReadDefault : SchedRead; Index: llvm/utils/TableGen/SubtargetEmitter.cpp =================================================================== --- llvm/utils/TableGen/SubtargetEmitter.cpp +++ llvm/utils/TableGen/SubtargetEmitter.cpp @@ -980,6 +980,7 @@ RAEntry.UseIdx = UseIdx; RAEntry.WriteResourceID = W; RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); + RAEntry.Cluster = ReadAdvance->getValueAsBit("Cluster"); ReadAdvanceEntries.push_back(RAEntry); } } @@ -1082,19 +1083,20 @@ OS << "}; // " << Target << "WriteLatencyTable\n"; // Emit global ReadAdvanceTable. - OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" + OS << "\n// {UseIdx, WriteResourceID, Cycles, Cluster}\n" << "extern const llvm::MCReadAdvanceEntry " << Target << "ReadAdvanceTable[] = {\n" - << " {0, 0, 0}, // Invalid\n"; + << " {0, 0, 0, 0}, // Invalid\n"; for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); RAIdx != RAEnd; ++RAIdx) { MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; - OS << " {" << RAEntry.UseIdx << ", " - << format("%2d", RAEntry.WriteResourceID) << ", " - << format("%2d", RAEntry.Cycles) << "}"; - if (RAIdx + 1 < RAEnd) - OS << ','; - OS << " // #" << RAIdx << '\n'; + OS << " {" + << RAEntry.UseIdx << ", " + << format("%3d", RAEntry.WriteResourceID) << ", " + << format("%2d", RAEntry.Cycles) << ", " + << RAEntry.Cluster << "}" + << (RAIdx + 1 < RAEnd ? ',' : ' ') + << " // #" << RAIdx << '\n'; } OS << "}; // " << Target << "ReadAdvanceTable\n";