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

Conversation

rj-jesus
Copy link
Contributor

@rj-jesus rj-jesus commented Feb 5, 2025

This patch adds support for describing per-write resource cycle counts
for ReadAdvance records via a new optional field called tunables.

This makes it possible to declare ReadAdvance records such as:

  def : ReadAdvance<Read_C, 1, [Write_A, Write_B], [2]>;

The above will effectively declare two entries in the ReadAdvance
table for Read_C, one for Write_A with a cycle count of 1+2, and one for
Write_B with a cycle count of 1+0 (omitted values are assumed 0).

The field tunables provides a list of deltas relative to the base
cycle count of the ReadAdvance. Since the field is optional and
defaults to a list of 0's, this change doesn't affect current targets.

This patch adds support for describing per-write resource cycle counts
for ReadAdvance records via a new optional field called `tunables'.

This makes it possible to declare ReadAdvance records such as:

  def : ReadAdvance<Read_C, 1, [Write_A, Write_B], [2]>;

The above will effectivelly declare two entries in the ReadAdvance
table for Read_C, one for Write_A with a cycle count of 1+2, and one for
Write_B with a cycle count of 1+0 (omitted values are assumed 0).

The field `tunables' provides a list of deltas relative to the base
`cycle' count of the ReadAdvance. Since the field is optional and
defaults to a list of 0's, this change doesn't affect current targets.
@llvmbot
Copy link
Member

llvmbot commented Feb 5, 2025

@llvm/pr-subscribers-tablegen

Author: Ricardo Jesus (rj-jesus)

Changes

This patch adds support for describing per-write resource cycle counts
for ReadAdvance records via a new optional field called tunables.

This makes it possible to declare ReadAdvance records such as:

  def : ReadAdvance&lt;Read_C, 1, [Write_A, Write_B], [2]&gt;;

The above will effectively declare two entries in the ReadAdvance
table for Read_C, one for Write_A with a cycle count of 1+2, and one for
Write_B with a cycle count of 1+0 (omitted values are assumed 0).

The field tunables provides a list of deltas relative to the base
cycle count of the ReadAdvance. Since the field is optional and
defaults to a list of 0's, this change doesn't affect current targets.


Full diff: https://github.com/llvm/llvm-project/pull/125870.diff

3 Files Affected:

  • (modified) llvm/include/llvm/Target/TargetSchedule.td (+9-5)
  • (added) llvm/test/TableGen/PreWriteCycleCount.td (+41)
  • (modified) llvm/utils/TableGen/SubtargetEmitter.cpp (+13-6)
diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td
index 2562ed0901303fe..4b82c1e2410fc8c 100644
--- a/llvm/include/llvm/Target/TargetSchedule.td
+++ b/llvm/include/llvm/Target/TargetSchedule.td
@@ -321,9 +321,11 @@ 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 = []> {
   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;
@@ -340,15 +342,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;
diff --git a/llvm/test/TableGen/PreWriteCycleCount.td b/llvm/test/TableGen/PreWriteCycleCount.td
new file mode 100644
index 000000000000000..40260a9bacef449
--- /dev/null
+++ b/llvm/test/TableGen/PreWriteCycleCount.td
@@ -0,0 +1,41 @@
+// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s 2>&1 | FileCheck %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;
+
+// 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]>;
+}
+
+def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 49362ff5ef65563..ec0990292738230 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -1308,23 +1308,30 @@ 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;
+      if (!CycleTunables.empty() && CycleTunables.size() > ValidWrites.size())
+        PrintFatalError(ReadAdvance->getLoc(),
+                        "If specified, CycleTunables must have at most the "
+                        "same number of elements of ValidWrites.\n");
+      CycleTunables.resize(ValidWrites.size(), 0);
       if (ValidWrites.empty())
-        WriteIDs.push_back(0);
+        WriteIDs.push_back(std::make_pair(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.push_back(std::make_pair(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);
       }
     }

@rj-jesus
Copy link
Contributor Author

Ping. :)

@jurahul
Copy link
Contributor

jurahul commented Feb 12, 2025

Also, once that is done, I think you need to re-request the review by clicking the small circle arrow button next to the reviewers, otherwise I am suspecting it won't get back on their radar.

@rj-jesus rj-jesus requested review from jurahul and topperc February 13, 2025 11:10
Copy link
Contributor

@jurahul jurahul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but please wait for @topperc 's (or someone else's) approval as well

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@rj-jesus
Copy link
Contributor Author

Thanks very much for the comments!

@rj-jesus rj-jesus merged commit 80b08d1 into llvm:main Feb 17, 2025
8 checks passed
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Feb 24, 2025
This patch adds support for describing per-write resource cycle counts
for ReadAdvance records via a new optional field called `tunables`.
    
This makes it possible to declare ReadAdvance records such as:
    
      def : ReadAdvance<Read_C, 1, [Write_A, Write_B], [2]>;
    
The above will effectively declare two entries in the ReadAdvance
table for Read_C, one for Write_A with a cycle count of 1+2, and one for
Write_B with a cycle count of 1+0 (omitted values are assumed 0).
    
The field `tunables` provides a list of deltas relative to the base
`cycle` count of the ReadAdvance. Since the field is optional and
defaults to a list of 0's, this change doesn't affect current targets.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants