[llvm] [TableGen] Make DFA packetizer resource numbering deterministic (PR #207203)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 2 08:01:19 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Michal Rostecki (vadorovsky)

<details>
<summary>Changes</summary>

`DFAPacketizerEmitter` grouped packetizer namespaces in a `StringMap`, so emission order depended on bucket order.

It also reassigned functional unit bits every time a FU name was seen, so duplicate FU names appearing at different positions in different itinerary lists could overwrite earlier assignments and collide with other resources.

This made generated packetizer tables non-reproducible for R600. In AMDGPU's R600 itineraries, `ALU_NULL` appears in both VLIW5 and VLIW4 models at different positions; depending on iteration order it could be assigned either its own bit or collide with `TRANS`.

Fix the emission order by using `std::map`. Make sure that resource bits are assigned once per FU name.

Fixes: https://github.com/llvm/llvm-project/issues/206904
Assisted-by: qwen-code + llama.cpp + hf.co/unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M

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


2 Files Affected:

- (modified) llvm/test/TableGen/DFAPacketizer.td (+61-2) 
- (modified) llvm/utils/TableGen/DFAPacketizerEmitter.cpp (+15-9) 


``````````diff
diff --git a/llvm/test/TableGen/DFAPacketizer.td b/llvm/test/TableGen/DFAPacketizer.td
index 6237bfbea9a0f..081e71f1bc7b8 100644
--- a/llvm/test/TableGen/DFAPacketizer.td
+++ b/llvm/test/TableGen/DFAPacketizer.td
@@ -2,7 +2,11 @@
 
 include "llvm/Target/Target.td"
 
-def TestTarget : Target;
+def TestTargetInstrInfo : InstrInfo;
+
+def TestTarget : Target {
+  let InstructionSet = TestTargetInstrInfo;
+}
 
 def TestSchedModel : SchedMachineModel {
   let CompleteModel = 0;
@@ -15,6 +19,18 @@ def FU1 : FuncUnit;
 
 def OP0 : InstrItinClass;
 def OP1 : InstrItinClass;
+def UniqueFUClass : InstrItinClass;
+def SharedFUClass : InstrItinClass;
+
+class TestInst<InstrItinClass Itin> : Instruction {
+  let OutOperandList = (outs);
+  let InOperandList = (ins);
+  let AsmString = "";
+  let Itinerary = Itin;
+}
+
+def INST_UNIQUE : TestInst<UniqueFUClass>;
+def INST_SHARED : TestInst<SharedFUClass>;
 
 def Itin {
   list<InstrItinData> ItinList = [
@@ -23,9 +39,32 @@ def Itin {
   ];
 }
 
+def FU_A : FuncUnit;
+def FU_B : FuncUnit;
+def FU_C : FuncUnit;
+def FU_D : FuncUnit;
+def UNIQUE_FU : FuncUnit;
+def SHARED_FU : FuncUnit;
+
+def WideFUList {
+  list<InstrItinData> ItinList = [
+    InstrItinData<UniqueFUClass, [InstrStage<1, [UNIQUE_FU]>]>,
+    InstrItinData<SharedFUClass, [InstrStage<1, [SHARED_FU]>]>
+  ];
+}
+
+def NarrowFUList {
+  list<InstrItinData> ItinList = [
+    InstrItinData<UniqueFUClass, [InstrStage<1, [SHARED_FU]>]>,
+    InstrItinData<SharedFUClass, [InstrStage<1, [SHARED_FU]>]>
+  ];
+}
+
 // CHECK:      int TestTargetGetResourceIndex(unsigned ProcID) {
 // CHECK-NEXT:   static const unsigned TestTargetProcIdToProcResourceIdxTable[][2] = {
-// CHECK-NEXT:     { 2,  1 }, // TestItinerariesModel
+// CHECK-NEXT:     { {{[0-9]+}},  1 }, // TestNarrowItinerariesModel
+// CHECK-NEXT:     { {{[0-9]+}},  2 }, // TestWideItinerariesModel
+// CHECK-NEXT:     { {{[0-9]+}},  3 }, // TestItinerariesModel
 // CHECK-NEXT:   };
 // CHECK-NEXT:   auto It = llvm::lower_bound(TestTargetProcIdToProcResourceIdxTable, ProcID,
 // CHECK-NEXT:       [](const unsigned LHS[], unsigned Val) { return LHS[0] < Val; });
@@ -33,7 +72,27 @@ def Itin {
 // CHECK-NEXT:   return (*It)[1];
 // CHECK-NEXT: }
 
+// Check that duplicate functional unit names keep their first assigned bit.
+// If `SHARED_FU` was reassigned while processing `TestNarrowItineraries`, it
+// would collide with `UNIQUE_FU` and the generated automaton would not contain
+// the distinct 0x10, 0x20, and 0x30 resource masks below.
+// CHECK: const std::array<NfaStatePair, 8> TestTargetTransitionInfo
+// CHECK:   /* 0 */ {0, 16}, {0, 0},
+// CHECK-NEXT:   /* 2 */ {0, 32}, {0, 0},
+// CHECK:   /* 4 */ {16, 48}, {0, 0},
+// CHECK:   /* 6 */ {32, 48}, {0, 0},
+
 // CHECK:  unsigned Index = TestTargetGetResourceIndex(IID->SchedModel.ProcID);
 
 def TestItineraries: ProcessorItineraries<[], [], Itin.ItinList>;
 def TestProcessor2 : Processor<"testprocessor2", TestItineraries, []>;
+
+def TestWideItineraries :
+    ProcessorItineraries<[FU_A, FU_B, FU_C, FU_D, UNIQUE_FU, SHARED_FU],
+                         [], WideFUList.ItinList>;
+def TestWideProcessor : Processor<"test-wide", TestWideItineraries, []>;
+
+def TestNarrowItineraries :
+    ProcessorItineraries<[FU_A, FU_B, FU_C, FU_D, SHARED_FU],
+                         [], NarrowFUList.ItinList>;
+def TestNarrowProcessor : Processor<"test-narrow", TestNarrowItineraries, []>;
diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
index 334aeef70ff51..0421cc8622dbc 100644
--- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -18,7 +18,6 @@
 #include "Common/CodeGenTarget.h"
 #include "DFAEmitter.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Record.h"
@@ -118,14 +117,20 @@ int DFAPacketizerEmitter::collectAllFuncUnits(
     // Convert macros to bits for each stage.
     unsigned numFUs = FUs.size();
     for (unsigned j = 0; j < numFUs; ++j) {
-      assert((j < DFA_MAX_RESOURCES) &&
-             "Exceeded maximum number of representable resources");
-      uint64_t FuncResources = 1ULL << j;
-      FUNameToBitsMap[FUs[j]->getName().str()] = FuncResources;
+      std::string FuncName = FUs[j]->getName().str();
+      auto It = FUNameToBitsMap.find(FuncName);
+      uint64_t FuncResources;
+      if (It != FUNameToBitsMap.end()) {
+        FuncResources = It->second;
+      } else {
+        assert((TotalFUs < DFA_MAX_RESOURCES) &&
+               "Exceeded maximum number of representable resources");
+        FuncResources = 1ULL << TotalFUs++;
+        FUNameToBitsMap[FuncName] = FuncResources;
+      }
       LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x"
                         << Twine::utohexstr(FuncResources));
     }
-    TotalFUs += numFUs;
     LLVM_DEBUG(dbgs() << "\n");
   }
   return TotalFUs;
@@ -217,16 +222,17 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) {
   CodeGenTarget CGT(Records);
   CodeGenSchedModels CGS(Records, CGT);
 
-  StringMap<std::vector<const CodeGenProcModel *>> ItinsByNamespace;
+  std::map<std::string, std::vector<const CodeGenProcModel *>>
+      ItinsByNamespace;
   for (const CodeGenProcModel &ProcModel : CGS.procModels()) {
     if (ProcModel.hasItineraries()) {
       auto NS = ProcModel.ItinsDef->getValueAsString("PacketizerNamespace");
-      ItinsByNamespace[NS].push_back(&ProcModel);
+      ItinsByNamespace[NS.str()].push_back(&ProcModel);
     }
   }
 
   for (auto &KV : ItinsByNamespace)
-    emitForItineraries(OS, KV.second, KV.first().str());
+    emitForItineraries(OS, KV.second, KV.first);
   OS << "} // end namespace llvm\n";
 }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/207203


More information about the llvm-commits mailing list