[llvm] 4bfe410 - [TableGen][SubtargetEmitter] Add the StartAtCycles field in the WriteRes class.

Francesco Petrogalli via llvm-commits llvm-commits at lists.llvm.org
Mon May 15 01:54:06 PDT 2023


Author: Francesco Petrogalli
Date: 2023-05-15T10:39:45+02:00
New Revision: 4bfe4108022ee1d9cb4b1effde0be145042b71bb

URL: https://github.com/llvm/llvm-project/commit/4bfe4108022ee1d9cb4b1effde0be145042b71bb
DIFF: https://github.com/llvm/llvm-project/commit/4bfe4108022ee1d9cb4b1effde0be145042b71bb.diff

LOG: [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

Added: 
    llvm/test/TableGen/StartAtCycle.td

Modified: 
    llvm/include/llvm/MC/MCSchedule.h
    llvm/include/llvm/Target/TargetSchedule.td
    llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
    llvm/utils/TableGen/SubtargetEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCSchedule.h b/llvm/include/llvm/MC/MCSchedule.h
index 6dffc158af500..83cd89a54c2a3 100644
--- a/llvm/include/llvm/MC/MCSchedule.h
+++ b/llvm/include/llvm/MC/MCSchedule.h
@@ -63,9 +63,14 @@ struct MCProcResourceDesc {
 struct MCWriteProcResEntry {
   uint16_t ProcResourceIdx;
   uint16_t Cycles;
+  // Cycle at which the resource will be grabbed by an instruction,
+  // relatively to the cycle in which the instruction is issued
+  // (assuming no stalls inbetween).
+  uint16_t StartAtCycle;
 
   bool operator==(const MCWriteProcResEntry &Other) const {
-    return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles;
+    return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles &&
+           StartAtCycle == Other.StartAtCycle;
   }
 };
 

diff  --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td
index 3bc467fbbfb0a..d0742c2adb781 100644
--- a/llvm/include/llvm/Target/TargetSchedule.td
+++ b/llvm/include/llvm/Target/TargetSchedule.td
@@ -250,6 +250,7 @@ class WriteSequence<list<SchedWrite> writes, int rep = 1> : SchedWrite {
 class ProcWriteResources<list<ProcResourceKind> resources> {
   list<ProcResourceKind> ProcResources = resources;
   list<int> ResourceCycles = [];
+  list<int> StartAtCycles = [];
   int Latency = 1;
   int NumMicroOps = 1;
   bit BeginGroup = false;

diff  --git a/llvm/test/TableGen/StartAtCycle.td b/llvm/test/TableGen/StartAtCycle.td
new file mode 100644
index 0000000000000..d3d642ddf69a9
--- /dev/null
+++ b/llvm/test/TableGen/StartAtCycle.td
@@ -0,0 +1,86 @@
+// RUN: llvm-tblgen -gen-subtarget -DCORRECT -I %p/../../include %s 2>&1 | \
+// RUN:   FileCheck %s  --check-prefix=CORRECT
+
+// RUN: not llvm-tblgen -gen-subtarget -DWRONG_SIZE -I %p/../../include %s 2>&1 | \
+// RUN:   FileCheck %s --check-prefix=WRONG_SIZE
+
+// RUN: not llvm-tblgen -gen-subtarget -DWRONG_VALUE -I %p/../../include %s 2>&1 | \
+// RUN:   FileCheck %s --check-prefix=WRONG_VALUE
+
+// RUN: not llvm-tblgen -gen-subtarget -DNEGATIVE_INVALID -I %p/../../include %s 2>&1 | \
+// RUN:   FileCheck %s --check-prefix=NEGATIVE_INVALID
+
+// Make sure that StartAtCycle in WriteRes is used to generate the
+// correct data.
+
+include "llvm/Target/Target.td"
+
+def MyTarget : Target;
+
+let BufferSize = 0 in {
+def ResX0 : ProcResource<1>; // X0
+def ResX1 : ProcResource<1>; // X1
+def ResX2 : ProcResource<1>; // X2
+}
+
+let OutOperandList = (outs), InOperandList = (ins) in {
+  def Inst_A : Instruction;
+  def Inst_B : Instruction;
+}
+
+let CompleteModel = 0 in {
+  def SchedModel_A: SchedMachineModel;
+}
+
+def WriteInst_A : SchedWrite;
+def WriteInst_B : SchedWrite;
+
+let SchedModel = SchedModel_A in {
+// Check the generated data when there are no semantic issues.
+#ifdef CORRECT
+// CORRECT-LABEL: llvm::MCWriteProcResEntry MyTargetWriteProcResTable[] = {
+// CORRECT-NEXT: { 0, 0, 0 }, // Invalid
+def : WriteRes<WriteInst_A, [ResX0, ResX1, ResX2]> {
+// CORRECT-NEXT: { 1, 2, 0}, // #1
+// CORRECT-NEXT: { 2, 4, 1}, // #2
+// CORRECT-NEXT: { 3, 3, 2}, // #3
+    let ResourceCycles = [2, 4, 3];
+    let StartAtCycles = [0, 1, 2];
+}
+def : WriteRes<WriteInst_B, [ResX2]> {
+// If unspecified, StartAtCycle is set to 0.
+// CORRECT-NEXT: { 3, 1, 0} // #4
+    let ResourceCycles = [1];
+}
+#endif // CORRECT
+
+#ifdef WRONG_SIZE
+// WRONG_SIZE: StartAtCycle.td:[[@LINE+1]]:1: error: Inconsistent resource cycles: size(StartAtCycles) != size(ProcResources): 2 vs 3
+def : WriteRes<WriteInst_A, [ResX0, ResX1, ResX2]> {
+    let ResourceCycles = [2, 4, 3];
+    let StartAtCycles = [0, 1];
+}
+#endif
+
+#ifdef WRONG_VALUE
+// WRONG_VALUE: StartAtCycle.td:[[@LINE+1]]:1: error: Inconsistent resource cycles: StartAtCycles < Cycles must hold
+def : WriteRes<WriteInst_A, [ResX0, ResX1, ResX2]> {
+    let ResourceCycles = [2, 4, 3];
+    let StartAtCycles = [0, 1, 8];
+}
+#endif
+
+#ifdef NEGATIVE_INVALID
+// NEGATIVE_INVALID: StartAtCycle.td:[[@LINE+1]]:1: error: Invalid value: StartAtCycle must be a non-negative value.
+def : WriteRes<WriteInst_A, [ResX0]> {
+    let ResourceCycles = [2];
+    let StartAtCycles = [-1];
+}
+#endif
+
+def : InstRW<[WriteInst_A], (instrs Inst_A)>;
+def : InstRW<[WriteInst_B], (instrs Inst_B)>;
+}
+
+def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
+

diff  --git a/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp b/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
index bd4e54290ea97..6b768c8e08288 100644
--- a/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SchedClassResolution.cpp
@@ -83,9 +83,14 @@ getNonRedundantWriteProcRes(const MCSchedClassDesc &SCDesc,
     const MCWriteProcResEntry *WPR = Entry.second;
     const MCProcResourceDesc *const ProcResDesc =
         SM.getProcResource(WPR->ProcResourceIdx);
+    // TODO: Handle StartAtCycle in llvm-exegesis and llvm-mca. See
+    // https://github.com/llvm/llvm-project/issues/62680 and
+    // https://github.com/llvm/llvm-project/issues/62681
+    assert(WPR->StartAtCycle == 0 &&
+           "`llvm-exegesis` does not handle StartAtCycle > 0");
     if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
       // This is a ProcResUnit.
-      Result.push_back({WPR->ProcResourceIdx, WPR->Cycles});
+      Result.push_back({WPR->ProcResourceIdx, WPR->Cycles, WPR->StartAtCycle});
       ProcResUnitUsage[WPR->ProcResourceIdx] += WPR->Cycles;
     } else {
       // This is a ProcResGroup. First see if it contributes any cycles or if
@@ -102,7 +107,8 @@ getNonRedundantWriteProcRes(const MCSchedClassDesc &SCDesc,
       }
       // The ProcResGroup contributes `RemainingCycles` cycles of its own.
       Result.push_back({WPR->ProcResourceIdx,
-                        static_cast<uint16_t>(std::round(RemainingCycles))});
+                        static_cast<uint16_t>(std::round(RemainingCycles)),
+                        WPR->StartAtCycle});
       // Spread the remaining cycles over all subunits.
       for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
            SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;

diff  --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 9bbf7cd673a09..69884a050852e 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -111,6 +111,7 @@ class SubtargetEmitter {
   Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
                           const CodeGenProcModel &ProcModel);
   void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
+                           std::vector<int64_t> &StartAtCycles,
                            const CodeGenProcModel &ProcModel);
   void GenSchedClassTables(const CodeGenProcModel &ProcModel,
                            SchedClassTables &SchedTables);
@@ -968,6 +969,7 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
 // resource groups and super resources that cover them.
 void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
                                            std::vector<int64_t> &Cycles,
+                                           std::vector<int64_t> &StartAtCycles,
                                            const CodeGenProcModel &PM) {
   assert(PRVec.size() == Cycles.size() && "failed precondition");
   for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
@@ -990,6 +992,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
                                          SubDef->getLoc());
         PRVec.push_back(SuperDef);
         Cycles.push_back(Cycles[i]);
+        StartAtCycles.push_back(StartAtCycles[i]);
         SubDef = SuperDef;
       }
     }
@@ -1006,6 +1009,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
       if (SubI == SubE) {
         PRVec.push_back(PR);
         Cycles.push_back(Cycles[i]);
+        StartAtCycles.push_back(StartAtCycles[i]);
       }
     }
   }
@@ -1140,22 +1144,48 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
         std::vector<int64_t> Cycles =
           WriteRes->getValueAsListOfInts("ResourceCycles");
 
-        if (Cycles.empty()) {
-          // If ResourceCycles is not provided, default to one cycle per
-          // resource.
-          Cycles.resize(PRVec.size(), 1);
-        } else if (Cycles.size() != PRVec.size()) {
+        std::vector<int64_t> StartAtCycles =
+            WriteRes->getValueAsListOfInts("StartAtCycles");
+
+        // Check consistency of the two vectors carrying the start and
+        // stop cycles of the resources.
+        if (!Cycles.empty() && Cycles.size() != PRVec.size()) {
           // If ResourceCycles is provided, check consistency.
           PrintFatalError(
               WriteRes->getLoc(),
-              Twine("Inconsistent resource cycles: !size(ResourceCycles) != "
-                    "!size(ProcResources): ")
+              Twine("Inconsistent resource cycles: size(ResourceCycles) != "
+                    "size(ProcResources): ")
                   .concat(Twine(PRVec.size()))
                   .concat(" vs ")
                   .concat(Twine(Cycles.size())));
         }
 
-        ExpandProcResources(PRVec, Cycles, ProcModel);
+        if (!StartAtCycles.empty() && StartAtCycles.size() != PRVec.size()) {
+          PrintFatalError(
+              WriteRes->getLoc(),
+              Twine("Inconsistent resource cycles: size(StartAtCycles) != "
+                    "size(ProcResources): ")
+                  .concat(Twine(StartAtCycles.size()))
+                  .concat(" vs ")
+                  .concat(Twine(PRVec.size())));
+        }
+
+        if (Cycles.empty()) {
+          // If ResourceCycles is not provided, default to one cycle
+          // per resource.
+          Cycles.resize(PRVec.size(), 1);
+        }
+
+        if (StartAtCycles.empty()) {
+          // If StartAtCycles is not provided, reserve the resource
+          // starting from cycle 0.
+          StartAtCycles.resize(PRVec.size(), 0);
+        }
+
+        assert(StartAtCycles.size() == Cycles.size());
+
+        ExpandProcResources(PRVec, Cycles, StartAtCycles, ProcModel);
+        assert(StartAtCycles.size() == Cycles.size());
 
         for (unsigned PRIdx = 0, PREnd = PRVec.size();
              PRIdx != PREnd; ++PRIdx) {
@@ -1163,6 +1193,17 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
           WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
           assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
           WPREntry.Cycles = Cycles[PRIdx];
+          WPREntry.StartAtCycle = StartAtCycles[PRIdx];
+          if (StartAtCycles[PRIdx] > Cycles[PRIdx]) {
+            PrintFatalError(WriteRes->getLoc(),
+                            Twine("Inconsistent resource cycles: StartAtCycles "
+                                  "< Cycles must hold."));
+          }
+          if (StartAtCycles[PRIdx] < 0) {
+            PrintFatalError(WriteRes->getLoc(),
+                            Twine("Invalid value: StartAtCycle "
+                                  "must be a non-negative value."));
+          }
           // If this resource is already used in this sequence, add the current
           // entry's cycles so that the same resource appears to be used
           // serially, rather than multiple parallel uses. This is important for
@@ -1171,6 +1212,15 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
           for( ; WPRIdx != WPREnd; ++WPRIdx) {
             if (WriteProcResources[WPRIdx].ProcResourceIdx
                 == WPREntry.ProcResourceIdx) {
+              // TODO: multiple use of the same resources would
+              // require either 1. thinking of how to handle multiple
+              // intervals for the same resource in
+              // `<Target>WriteProcResTable` (see
+              // `SubtargetEmitter::EmitSchedClassTables`), or
+              // 2. thinking how to merge multiple intervals into a
+              // single interval.
+              assert(WPREntry.StartAtCycle == 0 &&
+                     "multiple use ofthe same resource is not yet handled");
               WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
               break;
             }
@@ -1275,15 +1325,16 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
 void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
                                             raw_ostream &OS) {
   // Emit global WriteProcResTable.
-  OS << "\n// {ProcResourceIdx, Cycles}\n"
-     << "extern const llvm::MCWriteProcResEntry "
-     << Target << "WriteProcResTable[] = {\n"
-     << "  { 0,  0}, // Invalid\n";
+  OS << "\n// {ProcResourceIdx, Cycles, StartAtCycle}\n"
+     << "extern const llvm::MCWriteProcResEntry " << Target
+     << "WriteProcResTable[] = {\n"
+     << "  { 0,  0,  0 }, // Invalid\n";
   for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size();
        WPRIdx != WPREnd; ++WPRIdx) {
     MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx];
     OS << "  {" << format("%2d", WPREntry.ProcResourceIdx) << ", "
-       << format("%2d", WPREntry.Cycles) << "}";
+       << format("%2d", WPREntry.Cycles) << ",  "
+       << format("%2d", WPREntry.StartAtCycle) << "}";
     if (WPRIdx + 1 < WPREnd)
       OS << ',';
     OS << " // #" << WPRIdx << '\n';


        


More information about the llvm-commits mailing list