[llvm] [TableGen] Allow targets to enforce regunits assignment as intervals (PR #175823)
Ryan Mitchell via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 20 15:47:30 PST 2026
https://github.com/RyanRio updated https://github.com/llvm/llvm-project/pull/175823
>From f824fe8d90df41d16e6cc1398433cce959c95fa7 Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Tue, 13 Jan 2026 12:14:31 -0800
Subject: [PATCH 1/7] [TableGen] Allow targets to enforce regunits assignment
as intervals
---
llvm/include/llvm/MC/MCRegisterInfo.h | 18 +++-
llvm/include/llvm/Target/Target.td | 5 +
.../TableGen/regunit-intervals-impossible.td | 35 ++++++
llvm/test/TableGen/regunit-intervals.td | 73 +++++++++++++
.../TableGen/Common/CodeGenRegisters.cpp | 100 ++++++++++++++++++
llvm/utils/TableGen/Common/CodeGenRegisters.h | 9 ++
llvm/utils/TableGen/RegisterInfoEmitter.cpp | 17 +++
7 files changed, 256 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/TableGen/regunit-intervals-impossible.td
create mode 100644 llvm/test/TableGen/regunit-intervals.td
diff --git a/llvm/include/llvm/MC/MCRegisterInfo.h b/llvm/include/llvm/MC/MCRegisterInfo.h
index f4897b6a406fb..76ef62da3d35b 100644
--- a/llvm/include/llvm/MC/MCRegisterInfo.h
+++ b/llvm/include/llvm/MC/MCRegisterInfo.h
@@ -180,6 +180,7 @@ class LLVM_ABI MCRegisterInfo {
unsigned NumSubRegIndices; // Number of subreg indices.
const uint16_t *RegEncodingTable; // Pointer to array of register
// encodings.
+ const unsigned (*RegUnitIntervals)[2]; // Pointer to regunit interval table.
unsigned L2DwarfRegsSize;
unsigned EHL2DwarfRegsSize;
@@ -286,7 +287,8 @@ class LLVM_ABI MCRegisterInfo {
const int16_t *DL, const LaneBitmask *RUMS,
const char *Strings, const char *ClassStrings,
const uint16_t *SubIndices, unsigned NumIndices,
- const uint16_t *RET) {
+ const uint16_t *RET,
+ const unsigned (*RUI)[2] = nullptr) {
Desc = D;
NumRegs = NR;
RAReg = RA;
@@ -302,6 +304,7 @@ class LLVM_ABI MCRegisterInfo {
SubRegIndices = SubIndices;
NumSubRegIndices = NumIndices;
RegEncodingTable = RET;
+ RegUnitIntervals = RUI;
// Initialize DWARF register mapping variables
EHL2DwarfRegs = nullptr;
@@ -511,6 +514,19 @@ class LLVM_ABI MCRegisterInfo {
/// Returns true if the two registers are equal or alias each other.
bool regsOverlap(MCRegister RegA, MCRegister RegB) const;
+
+ /// Returns true if this target uses regunit intervals.
+ bool hasRegUnitIntervals() const { return RegUnitIntervals != nullptr; }
+
+ /// Returns an iterator range over all native regunits in the RegUnitInterval
+ /// table for \p Reg.
+ iota_range<unsigned> regunits_interval(MCRegister Reg) const {
+ assert(hasRegUnitIntervals() &&
+ "Target does not support regunit intervals");
+ assert(Reg.id() < NumRegs && "Invalid register number");
+ return seq<unsigned>(RegUnitIntervals[Reg.id()][0],
+ RegUnitIntervals[Reg.id()][1]);
+ }
};
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 315de55b75510..45ed2a674860b 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1935,6 +1935,11 @@ class Target {
// setting hasExtraDefRegAllocReq and hasExtraSrcRegAllocReq to 1
// for all opcodes if this flag is set to 0.
int AllowRegisterRenaming = 0;
+
+ // RegistersAreIntervals - Controls whether this target requires
+ // all Registers to have RegUnit intervals. Will attempt to reorder
+ // RegUnits to enforce this, and if a solution is not found, will error.
+ bit RegistersAreIntervals = 0;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/TableGen/regunit-intervals-impossible.td b/llvm/test/TableGen/regunit-intervals-impossible.td
new file mode 100644
index 0000000000000..9b4f6561178b7
--- /dev/null
+++ b/llvm/test/TableGen/regunit-intervals-impossible.td
@@ -0,0 +1,35 @@
+// RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s 2>&1 | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def TestInstrInfo : InstrInfo;
+def TestTarget : Target {
+ let InstructionSet = TestInstrInfo;
+ let RegistersAreIntervals = 1;
+}
+
+def sub_lo : SubRegIndex<32>;
+def sub_hi : SubRegIndex<32, 32>;
+
+let Namespace = "Test" in {
+ def R1 : Register<"r1">; // unit 0
+ def R2 : Register<"r2">; // unit 1
+ def R3 : Register<"r3">; // unit 2
+
+ // First composite: units {0, 1} - contiguous, OK
+ def R1_R2 : Register<"r1_r2"> {
+ let SubRegs = [R1, R2];
+ let SubRegIndices = [sub_lo, sub_hi];
+ }
+
+ // Second composite: units {0, 2} - non-contiguous!
+ // Algorithm will swap 1 and 2, making R1_R2 not contiguous
+ def R1_R3 : Register<"r1_r3"> {
+ let SubRegs = [R1, R3];
+ let SubRegIndices = [sub_lo, sub_hi];
+ }
+}
+
+def GPR32 : RegisterClass<"Test", [i32], 32, (add R1, R2, R3, R4)>;
+
+// CHECK: error: Cannot enforce regunit intervals, final renumbering did not produce contiguous units for register R10_R11
diff --git a/llvm/test/TableGen/regunit-intervals.td b/llvm/test/TableGen/regunit-intervals.td
new file mode 100644
index 0000000000000..3d5dcd7c404dc
--- /dev/null
+++ b/llvm/test/TableGen/regunit-intervals.td
@@ -0,0 +1,73 @@
+// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def TestInstrInfo : InstrInfo;
+def TestTarget : Target {
+ let InstructionSet = TestInstrInfo;
+ let RegistersAreIntervals = 1;
+}
+
+def sub_lo : SubRegIndex<32>;
+def sub_hi : SubRegIndex<32, 32>;
+
+let Namespace = "Test" in {
+ // Simple 32-bit registers (each gets 1 regunit)
+ def R0 : Register<"r0">;
+ def R1 : Register<"r1">;
+ def R2 : Register<"r2">;
+ def R3 : Register<"r3">;
+
+ // 64-bit register composed of R0:R1 (gets 2 regunits)
+ def R0_R1 : Register<"r0_r1"> {
+ let SubRegs = [R0, R1];
+ let SubRegIndices = [sub_lo, sub_hi];
+ }
+
+ // 64-bit register composed of R2:R3 (gets 2 regunits)
+ def R2_R3 : Register<"r2_r3"> {
+ let SubRegs = [R2, R3];
+ let SubRegIndices = [sub_lo, sub_hi];
+ }
+}
+
+// CHECK: extern const uint16_t TestRegUnitIntervals[][2] = {
+// CHECK-NEXT: { 0, 1 },
+// CHECK-NEXT: { 1, 2 },
+// CHECK-NEXT: { 2, 3 },
+// CHECK-NEXT: { 3, 4 },
+
+let Namespace = "Test" in {
+ def R4 : Register<"r4">; // Gets unit 4
+ def R5 : Register<"r5">; // Gets unit 5
+ def R6 : Register<"r6">; // Gets unit 6
+ def R7 : Register<"r7">; // Gets unit 7
+
+ // This register skips R5, creating non-contiguous units {4, 6}
+ def R4_R6 : Register<"r4_r6"> {
+ let SubRegs = [R4, R6];
+ let SubRegIndices = [sub_lo, sub_hi];
+ }
+
+ // This register skips R6, creating non-contiguous units {5, 7}
+ def R5_R7 : Register<"r4_r6"> {
+ let SubRegs = [R5, R7];
+ let SubRegIndices = [sub_lo, sub_hi];
+ }
+}
+
+
+def GPR32 : RegisterClass<"Test", [i32], 32, (add R0, R1, R2, R3)>;
+def GPR64 : RegisterClass<"Test", [i64], 64, (add R0_R1, R2_R3)>;
+
+// Note R5 is assigned 6,7 so that R6 gets 5,6
+// CHECK-NEXT: { 4, 5 },
+// CHECK-NEXT: { 6, 7 },
+// CHECK-NEXT: { 5, 6 },
+// CHECK-NEXT: { 7, 8 },
+// All contiguous
+// CHECK-NEXT: { 0, 2 },
+// CHECK-NEXT: { 2, 4 },
+// CHECK-NEXT: { 4, 6 },
+// CHECK-NEXT: { 6, 8 },
+// CHECK-NEXT: };
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 65a2594859e69..bf1a2e767370d 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -1929,6 +1929,101 @@ void CodeGenRegBank::computeRegUnitWeights() {
}
}
+// Enforce that all registers are intervals of regunits if the target
+// requests this property. This will renumber regunits to ensure the
+// interval property holds, or error out if it cannot be satisfied.
+void CodeGenRegBank::enforceRegUnitIntervals() {
+ std::vector<const Record *> Targets =
+ Records.getAllDerivedDefinitions("Target");
+
+ if (Targets.empty())
+ return;
+
+ const Record *Target = Targets[0];
+ if (!Target->getValueAsBit("RegistersAreIntervals"))
+ return;
+
+ LLVM_DEBUG(dbgs() << "Enforcing regunit intervals for target\n");
+ std::vector<unsigned> RegUnitRenumbering(RegUnits.size(), ~0u);
+
+ // RegUnits that have been renumbered from X -> Y. Y is what is marked so that
+ // it doesn't create a chain of swaps.
+ SparseBitVector DontRenumberUnits;
+
+ auto GetRenumberedUnit = [&](unsigned RegUnit) -> unsigned {
+ if (RegUnitRenumbering[RegUnit] != ~0u)
+ return RegUnitRenumbering[RegUnit];
+ return RegUnit;
+ };
+
+ auto IsContiguous = [&](CodeGenRegister::RegUnitList &Units) -> bool {
+ unsigned LastUnit = Units.find_first();
+ for (auto ThisUnit : llvm::make_range(++Units.begin(), Units.end())) {
+ if (ThisUnit != LastUnit + 1)
+ return false;
+ LastUnit = ThisUnit;
+ }
+ return true;
+ };
+
+ // Process registers in definition order
+ for (CodeGenRegister &Reg : Registers) {
+ LLVM_DEBUG(dbgs() << "Processing register " << Reg.getName() << "\n");
+ const auto &Units = Reg.getNativeRegUnits();
+ if (Units.empty())
+ continue;
+ SparseBitVector RenumberedUnits;
+ // First renumber all the units for this register according to previous
+ // renumbering.
+ LLVM_DEBUG(dbgs() << " Original (Renumbered) units:");
+ for (unsigned U : Units) {
+ LLVM_DEBUG(dbgs() << " " << U << "(" << GetRenumberedUnit(U) << "), ");
+ RenumberedUnits.set(GetRenumberedUnit(U));
+ }
+ LLVM_DEBUG(dbgs() << "\n");
+
+ unsigned LastUnit = RenumberedUnits.find_first();
+ for (auto ThisUnit :
+ llvm::make_range(++RenumberedUnits.begin(), RenumberedUnits.end())) {
+ if (ThisUnit != LastUnit + 1) {
+ if (DontRenumberUnits.test(LastUnit + 1)) {
+ PrintFatalError(
+ "Cannot enforce regunit intervals for register " + Reg.getName() +
+ ": unit " + Twine(LastUnit + 1) +
+ " (root: " + RegUnits[LastUnit + 1].Roots[0]->getName() +
+ ") has already been renumbered and cannot be swapped");
+ }
+ LLVM_DEBUG(dbgs() << " Renumbering unit " << ThisUnit << " to "
+ << (LastUnit + 1) << "\n");
+ RegUnitRenumbering[LastUnit + 1] = ThisUnit;
+ RegUnitRenumbering[ThisUnit] = LastUnit + 1;
+ DontRenumberUnits.set(LastUnit + 1);
+ ThisUnit = LastUnit + 1;
+ }
+ LastUnit = ThisUnit;
+ }
+ }
+
+ // Apply the renumbering to all registers
+ for (CodeGenRegister &Reg : Registers) {
+ CodeGenRegister::RegUnitList NewRegUnits;
+ for (unsigned OldUnit : Reg.getRegUnits())
+ NewRegUnits.set(GetRenumberedUnit(OldUnit));
+ Reg.setNewRegUnits(NewRegUnits);
+
+ CodeGenRegister::RegUnitList NewNativeUnits;
+ for (unsigned OldUnit : Reg.getNativeRegUnits())
+ NewNativeUnits.set(GetRenumberedUnit(OldUnit));
+ if (!IsContiguous(NewNativeUnits)) {
+ reportFatalInternalError("Cannot enforce regunit intervals, final "
+ "renumbering did not produce contiguous units "
+ "for register " +
+ Reg.getName() + "\n");
+ }
+ Reg.NativeRegUnits = NewNativeUnits;
+ }
+}
+
// Find a set in UniqueSets with the same elements as Set.
// Return an iterator into UniqueSets.
static std::vector<RegUnitSet>::const_iterator
@@ -2209,6 +2304,11 @@ void CodeGenRegBank::computeDerivedInfo() {
computeRegUnitWeights();
Records.getTimer().stopTimer();
+ // Enforce regunit intervals if requested by the target.
+ Records.getTimer().startTimer("Enforce regunit intervals");
+ enforceRegUnitIntervals();
+ Records.getTimer().stopTimer();
+
// Compute a unique set of RegUnitSets. One for each RegClass and inferred
// supersets for the union of overlapping sets.
computeRegUnitSets();
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.h b/llvm/utils/TableGen/Common/CodeGenRegisters.h
index a3ad0b797a704..176cb9dafd22b 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.h
@@ -169,6 +169,8 @@ class CodeGenSubRegIndex {
/// CodeGenRegister - Represents a register definition.
class CodeGenRegister {
+ friend class CodeGenRegBank;
+
public:
const Record *TheDef;
unsigned EnumValue;
@@ -257,6 +259,10 @@ class CodeGenRegister {
// This is only valid after computeSubRegs() completes.
const RegUnitList &getRegUnits() const { return RegUnits; }
+ void setNewRegUnits(const RegUnitList &NewRegUnits) {
+ RegUnits = NewRegUnits;
+ }
+
ArrayRef<LaneBitmask> getRegUnitLaneMasks() const {
return ArrayRef(RegUnitLaneMasks).slice(0, NativeRegUnits.count());
}
@@ -693,6 +699,9 @@ class CodeGenRegBank {
// Compute a weight for each register unit created during getSubRegs.
void computeRegUnitWeights();
+ // Enforce that all registers are intervals of regunits if requested.
+ void enforceRegUnitIntervals();
+
// Create a RegUnitSet for each RegClass and infer superclasses.
void computeRegUnitSets();
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index 02fd8648302f1..552b32736509c 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1044,6 +1044,23 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
}
OS << "};\n\n";
+ // Emit the table of register unit intervals.
+ if (Target.getTargetRecord()->getValueAsBit("RegistersAreIntervals")) {
+ OS << "extern const unsigned " << TargetName
+ << "RegUnitIntervals[][2] = {\n";
+ for (const auto &Reg : Regs) {
+ const auto &Units = Reg.getNativeRegUnits();
+ if (Units.empty()) {
+ OS << " { 0, 0 },\n";
+ } else {
+ unsigned First = Units.find_first();
+ unsigned Last = Units.find_last();
+ OS << " { " << First << ", " << Last + 1 << " },\n";
+ }
+ }
+ OS << "};\n\n";
+ }
+
const auto &RegisterClasses = RegBank.getRegClasses();
// Loop over all of the register classes... emitting each one.
>From 436b2ea38832ffee800358d99fe6ddc4679a0605 Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Mon, 19 Jan 2026 12:23:32 -0800
Subject: [PATCH 2/7] Test and build fixes
---
llvm/test/TableGen/regunit-intervals-impossible.td | 2 +-
llvm/test/TableGen/regunit-intervals.td | 2 +-
llvm/utils/TableGen/Common/CodeGenRegisters.cpp | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/test/TableGen/regunit-intervals-impossible.td b/llvm/test/TableGen/regunit-intervals-impossible.td
index 9b4f6561178b7..ded63e183fd6a 100644
--- a/llvm/test/TableGen/regunit-intervals-impossible.td
+++ b/llvm/test/TableGen/regunit-intervals-impossible.td
@@ -30,6 +30,6 @@ let Namespace = "Test" in {
}
}
-def GPR32 : RegisterClass<"Test", [i32], 32, (add R1, R2, R3, R4)>;
+def GPR32 : RegisterClass<"Test", [i32], 32, (add R1, R2, R3)>;
// CHECK: error: Cannot enforce regunit intervals, final renumbering did not produce contiguous units for register R10_R11
diff --git a/llvm/test/TableGen/regunit-intervals.td b/llvm/test/TableGen/regunit-intervals.td
index 3d5dcd7c404dc..906dcd71b9ebe 100644
--- a/llvm/test/TableGen/regunit-intervals.td
+++ b/llvm/test/TableGen/regunit-intervals.td
@@ -31,7 +31,7 @@ let Namespace = "Test" in {
}
}
-// CHECK: extern const uint16_t TestRegUnitIntervals[][2] = {
+// CHECK: extern const uint16_t TestTargetRegUnitIntervals[][2] = {
// CHECK-NEXT: { 0, 1 },
// CHECK-NEXT: { 1, 2 },
// CHECK-NEXT: { 2, 3 },
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index bf1a2e767370d..f7b085d285f38 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -1948,7 +1948,7 @@ void CodeGenRegBank::enforceRegUnitIntervals() {
// RegUnits that have been renumbered from X -> Y. Y is what is marked so that
// it doesn't create a chain of swaps.
- SparseBitVector DontRenumberUnits;
+ SparseBitVector<> DontRenumberUnits;
auto GetRenumberedUnit = [&](unsigned RegUnit) -> unsigned {
if (RegUnitRenumbering[RegUnit] != ~0u)
@@ -1972,7 +1972,7 @@ void CodeGenRegBank::enforceRegUnitIntervals() {
const auto &Units = Reg.getNativeRegUnits();
if (Units.empty())
continue;
- SparseBitVector RenumberedUnits;
+ SparseBitVector<> RenumberedUnits;
// First renumber all the units for this register according to previous
// renumbering.
LLVM_DEBUG(dbgs() << " Original (Renumbered) units:");
>From 596009cf8f04326b6f4f90a5a321eaa6e4478926 Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Mon, 19 Jan 2026 21:22:27 -0800
Subject: [PATCH 3/7] Use CodeGenTarget to access bool
---
llvm/include/llvm/Target/Target.td | 14 +++++++++++---
.../TableGen/regunit-intervals-impossible.td | 2 +-
llvm/test/TableGen/regunit-intervals.td | 2 +-
.../TableGen/Common/CodeGenRegisters.cpp | 19 +++++++------------
llvm/utils/TableGen/Common/CodeGenTarget.cpp | 4 ++++
llvm/utils/TableGen/Common/CodeGenTarget.h | 5 +++++
6 files changed, 29 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 45ed2a674860b..c06d7885a4cea 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1936,9 +1936,17 @@ class Target {
// for all opcodes if this flag is set to 0.
int AllowRegisterRenaming = 0;
- // RegistersAreIntervals - Controls whether this target requires
- // all Registers to have RegUnit intervals. Will attempt to reorder
- // RegUnits to enforce this, and if a solution is not found, will error.
+ // RegistersAreIntervals - Controls whether registers units must form
+ // contiguous intervals for each register.
+ //
+ // Specifically, for each register, its register units must be numbered
+ // consecutively (e.g, units 5,6,7 rather than 5,7,9). If enabled,
+ // CodeGenRegisters will enforce this property and attempt to fix violations
+ // that can be resolved by rearranging regunits. Unresolved violations will
+ // result in a fatal error.
+ //
+ // This enables interval-based representation of register units, which can
+ // improve data structure representations in target backends.
bit RegistersAreIntervals = 0;
}
diff --git a/llvm/test/TableGen/regunit-intervals-impossible.td b/llvm/test/TableGen/regunit-intervals-impossible.td
index ded63e183fd6a..5d40b3bc512ef 100644
--- a/llvm/test/TableGen/regunit-intervals-impossible.td
+++ b/llvm/test/TableGen/regunit-intervals-impossible.td
@@ -32,4 +32,4 @@ let Namespace = "Test" in {
def GPR32 : RegisterClass<"Test", [i32], 32, (add R1, R2, R3)>;
-// CHECK: error: Cannot enforce regunit intervals, final renumbering did not produce contiguous units for register R10_R11
+// CHECK: LLVM ERROR: Cannot enforce regunit intervals, final renumbering did not produce contiguous units for register R1_R2
diff --git a/llvm/test/TableGen/regunit-intervals.td b/llvm/test/TableGen/regunit-intervals.td
index 906dcd71b9ebe..a78f62836a7bc 100644
--- a/llvm/test/TableGen/regunit-intervals.td
+++ b/llvm/test/TableGen/regunit-intervals.td
@@ -31,7 +31,7 @@ let Namespace = "Test" in {
}
}
-// CHECK: extern const uint16_t TestTargetRegUnitIntervals[][2] = {
+// CHECK: extern const unsigned TestTargetRegUnitIntervals[][2] = {
// CHECK-NEXT: { 0, 1 },
// CHECK-NEXT: { 1, 2 },
// CHECK-NEXT: { 2, 3 },
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index f7b085d285f38..226f2178a066f 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
@@ -1933,14 +1934,8 @@ void CodeGenRegBank::computeRegUnitWeights() {
// requests this property. This will renumber regunits to ensure the
// interval property holds, or error out if it cannot be satisfied.
void CodeGenRegBank::enforceRegUnitIntervals() {
- std::vector<const Record *> Targets =
- Records.getAllDerivedDefinitions("Target");
-
- if (Targets.empty())
- return;
-
- const Record *Target = Targets[0];
- if (!Target->getValueAsBit("RegistersAreIntervals"))
+ CodeGenTarget Target(Records);
+ if (!Target.getRegistersAreIntervals())
return;
LLVM_DEBUG(dbgs() << "Enforcing regunit intervals for target\n");
@@ -2015,10 +2010,10 @@ void CodeGenRegBank::enforceRegUnitIntervals() {
for (unsigned OldUnit : Reg.getNativeRegUnits())
NewNativeUnits.set(GetRenumberedUnit(OldUnit));
if (!IsContiguous(NewNativeUnits)) {
- reportFatalInternalError("Cannot enforce regunit intervals, final "
- "renumbering did not produce contiguous units "
- "for register " +
- Reg.getName() + "\n");
+ PrintFatalError("Cannot enforce regunit intervals, final "
+ "renumbering did not produce contiguous units "
+ "for register " +
+ Reg.getName() + "\n");
}
Reg.NativeRegUnits = NewNativeUnits;
}
diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.cpp b/llvm/utils/TableGen/Common/CodeGenTarget.cpp
index cca318a6e2047..eb271507bd6cb 100644
--- a/llvm/utils/TableGen/Common/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenTarget.cpp
@@ -119,6 +119,10 @@ bool CodeGenTarget::getAllowRegisterRenaming() const {
return TargetRec->getValueAsInt("AllowRegisterRenaming");
}
+bool CodeGenTarget::getRegistersAreIntervals() const {
+ return TargetRec->getValueAsInt("RegistersAreIntervals");
+}
+
/// getAsmParser - Return the AssemblyParser definition for this target.
///
const Record *CodeGenTarget::getAsmParser() const {
diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.h b/llvm/utils/TableGen/Common/CodeGenTarget.h
index dc1740b174148..482816f774df9 100644
--- a/llvm/utils/TableGen/Common/CodeGenTarget.h
+++ b/llvm/utils/TableGen/Common/CodeGenTarget.h
@@ -100,6 +100,11 @@ class CodeGenTarget {
///
bool getAllowRegisterRenaming() const;
+ /// getRegistersAreIntervals - Return the RegistersAreIntervals flag value for
+ /// this target.
+ ///
+ bool getRegistersAreIntervals() const;
+
/// getAsmParser - Return the AssemblyParser definition for this target.
///
const Record *getAsmParser() const;
>From 95dda86274dc3621d64b8af21532e96160c5d5ef Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Mon, 19 Jan 2026 21:35:19 -0800
Subject: [PATCH 4/7] Make field int to match other fields
---
llvm/include/llvm/Target/Target.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index c06d7885a4cea..abe3a7d1701ee 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1947,7 +1947,7 @@ class Target {
//
// This enables interval-based representation of register units, which can
// improve data structure representations in target backends.
- bit RegistersAreIntervals = 0;
+ int RegistersAreIntervals = 0;
}
//===----------------------------------------------------------------------===//
>From dd6d7867b6b2ca741f7e78818e7cda118504ecc8 Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Mon, 19 Jan 2026 21:52:51 -0800
Subject: [PATCH 5/7] Fix missed use of getRegistersAreIntervals
---
llvm/utils/TableGen/RegisterInfoEmitter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index 552b32736509c..530a075a793ba 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1045,7 +1045,7 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
OS << "};\n\n";
// Emit the table of register unit intervals.
- if (Target.getTargetRecord()->getValueAsBit("RegistersAreIntervals")) {
+ if (Target.getRegistersAreIntervals()) {
OS << "extern const unsigned " << TargetName
<< "RegUnitIntervals[][2] = {\n";
for (const auto &Reg : Regs) {
>From bfd01267c8e92745d1deaca9b98d054ec7c76789 Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Mon, 19 Jan 2026 23:15:39 -0800
Subject: [PATCH 6/7] Fix imposssible case test
---
llvm/test/TableGen/regunit-intervals-impossible.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/TableGen/regunit-intervals-impossible.td b/llvm/test/TableGen/regunit-intervals-impossible.td
index 5d40b3bc512ef..44c5fba0f7043 100644
--- a/llvm/test/TableGen/regunit-intervals-impossible.td
+++ b/llvm/test/TableGen/regunit-intervals-impossible.td
@@ -32,4 +32,4 @@ let Namespace = "Test" in {
def GPR32 : RegisterClass<"Test", [i32], 32, (add R1, R2, R3)>;
-// CHECK: LLVM ERROR: Cannot enforce regunit intervals, final renumbering did not produce contiguous units for register R1_R2
+// CHECK: error: Cannot enforce regunit intervals, final renumbering did not produce contiguous units for register R1_R2
>From b49102a2ccebe9788de07a19fb3c8dd64c335cca Mon Sep 17 00:00:00 2001
From: Ryan Mitchell <Ryan.Mitchell at amd.com>
Date: Tue, 20 Jan 2026 15:47:14 -0800
Subject: [PATCH 7/7] Pass bool from target
---
.../TableGen/Common/CodeGenRegisters.cpp | 43 ++++++++++---------
llvm/utils/TableGen/Common/CodeGenRegisters.h | 5 ++-
llvm/utils/TableGen/Common/CodeGenTarget.cpp | 3 +-
llvm/utils/TableGen/RegisterInfoEmitter.cpp | 2 +-
4 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 226f2178a066f..2c878ee0d7bf7 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "CodeGenRegisters.h"
-#include "CodeGenTarget.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
@@ -1126,8 +1125,10 @@ CodeGenRegisterCategory::CodeGenRegisterCategory(CodeGenRegBank &RegBank,
//===----------------------------------------------------------------------===//
CodeGenRegBank::CodeGenRegBank(const RecordKeeper &Records,
- const CodeGenHwModes &Modes)
- : Records(Records), CGH(Modes) {
+ const CodeGenHwModes &Modes,
+ const bool RegistersAreIntervals)
+ : Records(Records), CGH(Modes),
+ RegistersAreIntervals(RegistersAreIntervals) {
// Configure register Sets to understand register classes and tuples.
Sets.addFieldExpander("RegisterClass", "MemberList");
Sets.addFieldExpander("CalleeSavedRegs", "SaveList");
@@ -1930,12 +1931,23 @@ void CodeGenRegBank::computeRegUnitWeights() {
}
}
+// isContiguous is a enforceRegUnitIntervals helper that returns true if all
+// units in Units form a contiguous interval.
+static bool isContiguous(const CodeGenRegister::RegUnitList &Units) {
+ unsigned LastUnit = Units.find_first();
+ for (auto ThisUnit : llvm::make_range(++Units.begin(), Units.end())) {
+ if (ThisUnit != LastUnit + 1)
+ return false;
+ LastUnit = ThisUnit;
+ }
+ return true;
+}
+
// Enforce that all registers are intervals of regunits if the target
// requests this property. This will renumber regunits to ensure the
// interval property holds, or error out if it cannot be satisfied.
void CodeGenRegBank::enforceRegUnitIntervals() {
- CodeGenTarget Target(Records);
- if (!Target.getRegistersAreIntervals())
+ if (!RegistersAreIntervals)
return;
LLVM_DEBUG(dbgs() << "Enforcing regunit intervals for target\n");
@@ -1946,21 +1958,12 @@ void CodeGenRegBank::enforceRegUnitIntervals() {
SparseBitVector<> DontRenumberUnits;
auto GetRenumberedUnit = [&](unsigned RegUnit) -> unsigned {
- if (RegUnitRenumbering[RegUnit] != ~0u)
- return RegUnitRenumbering[RegUnit];
+ if (unsigned RenumberedUnit = RegUnitRenumbering[RegUnit];
+ RenumberedUnit != ~0u)
+ return RenumberedUnit;
return RegUnit;
};
- auto IsContiguous = [&](CodeGenRegister::RegUnitList &Units) -> bool {
- unsigned LastUnit = Units.find_first();
- for (auto ThisUnit : llvm::make_range(++Units.begin(), Units.end())) {
- if (ThisUnit != LastUnit + 1)
- return false;
- LastUnit = ThisUnit;
- }
- return true;
- };
-
// Process registers in definition order
for (CodeGenRegister &Reg : Registers) {
LLVM_DEBUG(dbgs() << "Processing register " << Reg.getName() << "\n");
@@ -1983,7 +1986,7 @@ void CodeGenRegBank::enforceRegUnitIntervals() {
if (ThisUnit != LastUnit + 1) {
if (DontRenumberUnits.test(LastUnit + 1)) {
PrintFatalError(
- "Cannot enforce regunit intervals for register " + Reg.getName() +
+ "cannot enforce regunit intervals for register " + Reg.getName() +
": unit " + Twine(LastUnit + 1) +
" (root: " + RegUnits[LastUnit + 1].Roots[0]->getName() +
") has already been renumbered and cannot be swapped");
@@ -2009,8 +2012,8 @@ void CodeGenRegBank::enforceRegUnitIntervals() {
CodeGenRegister::RegUnitList NewNativeUnits;
for (unsigned OldUnit : Reg.getNativeRegUnits())
NewNativeUnits.set(GetRenumberedUnit(OldUnit));
- if (!IsContiguous(NewNativeUnits)) {
- PrintFatalError("Cannot enforce regunit intervals, final "
+ if (!isContiguous(NewNativeUnits)) {
+ PrintFatalError("cannot enforce regunit intervals, final "
"renumbering did not produce contiguous units "
"for register " +
Reg.getName() + "\n");
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.h b/llvm/utils/TableGen/Common/CodeGenRegisters.h
index 176cb9dafd22b..1e9a5feb96bd1 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.h
@@ -618,6 +618,8 @@ class CodeGenRegBank {
const CodeGenHwModes &CGH;
+ const bool RegistersAreIntervals;
+
std::deque<CodeGenSubRegIndex> SubRegIndices;
DenseMap<const Record *, CodeGenSubRegIndex *> Def2SubRegIdx;
@@ -723,7 +725,8 @@ class CodeGenRegBank {
void printRegUnitNames(ArrayRef<unsigned> Units) const;
public:
- CodeGenRegBank(const RecordKeeper &, const CodeGenHwModes &);
+ CodeGenRegBank(const RecordKeeper &, const CodeGenHwModes &,
+ const bool RegistersAreIntervals);
CodeGenRegBank(CodeGenRegBank &) = delete;
SetTheory &getSets() { return Sets; }
diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.cpp b/llvm/utils/TableGen/Common/CodeGenTarget.cpp
index eb271507bd6cb..bce115cafaab2 100644
--- a/llvm/utils/TableGen/Common/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenTarget.cpp
@@ -166,7 +166,8 @@ const Record *CodeGenTarget::getAsmWriter() const {
CodeGenRegBank &CodeGenTarget::getRegBank() const {
if (!RegBank)
- RegBank = std::make_unique<CodeGenRegBank>(Records, getHwModes());
+ RegBank = std::make_unique<CodeGenRegBank>(Records, getHwModes(),
+ getRegistersAreIntervals());
return *RegBank;
}
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index 530a075a793ba..548c1503f4647 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1048,7 +1048,7 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
if (Target.getRegistersAreIntervals()) {
OS << "extern const unsigned " << TargetName
<< "RegUnitIntervals[][2] = {\n";
- for (const auto &Reg : Regs) {
+ for (const CodeGenRegister &Reg : Regs) {
const auto &Units = Reg.getNativeRegUnits();
if (Units.empty()) {
OS << " { 0, 0 },\n";
More information about the llvm-commits
mailing list