[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