[llvm] decb0ee - [TableGen] Handle the non-`CoveredBySubRegs` case in `computeRegUnitLaneMasks` (#223653)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 07:15:23 PDT 2026


Author: Igor Wodiany
Date: 2026-09-23T15:15:15+01:00
New Revision: decb0ee138505e73d0eced11a36ec4fee6c0a1ce

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

LOG: [TableGen] Handle the non-`CoveredBySubRegs` case in `computeRegUnitLaneMasks` (#223653)

Currently `computeRegUnitLaneMasks` ignores non-leaf subregisters as
"their lane masks are fully covered by the leaf subregisters". However
this only holds when `CoveredBySubRegs` is set to true. Otherwise it
causes subregisters with `CoveredBySubRegs` set to false to have missing
lanes.

For example removing `hi16` from SGPR in AMDGPU causes `sub1` to have a
lane mask of `0x8`, which is equal to `sub1_lo16`, whereas the correct
mask should be `0xC` as although `hi16` is not addressable `sub1` covers
both halves.

This patch adds a logic that identifies unclaimed lanes and backfills
them into appropriate subregister units.

Assisted-by: Claude Code

Added: 
    llvm/test/TableGen/RegisterInfoEmitter-noncovered-subreg-lanemask.td

Modified: 
    llvm/utils/TableGen/Common/CodeGenRegisters.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/TableGen/RegisterInfoEmitter-noncovered-subreg-lanemask.td b/llvm/test/TableGen/RegisterInfoEmitter-noncovered-subreg-lanemask.td
new file mode 100644
index 0000000000000..4b7bf18447276
--- /dev/null
+++ b/llvm/test/TableGen/RegisterInfoEmitter-noncovered-subreg-lanemask.td
@@ -0,0 +1,71 @@
+// RUN: llvm-tblgen -gen-register-info -I %p/../../include %s | FileCheck %s
+
+// Checks that computeRegUnitLaneMasks() handles noncovered subregs correctly.
+include "llvm/Target/Target.td"
+
+def TestTarget : Target;
+
+def lo16 : SubRegIndex<16, 0>;
+def hi16 : SubRegIndex<16, 16>;
+def sub0 : SubRegIndex<32, 0>;
+def sub1 : SubRegIndex<32, 32>;
+
+// Fully-covered 32-bit register. This forces sub0/sub1 to be assigned
+// lanes wide enough to cover both lo16 and hi16 of a 32-bit slot.
+def R2_LO16 : Register<"r2l">;
+def R2_HI16 : Register<"r2h">;
+def R2 : RegisterWithSubRegs<"r2", [R2_LO16, R2_HI16]> {
+  let SubRegIndices = [lo16, hi16];
+  let CoveredBySubRegs = 1;
+}
+
+def R3_LO16 : Register<"r3l">;
+def R3_HI16 : Register<"r3h">;
+def R3 : RegisterWithSubRegs<"r3", [R3_LO16, R3_HI16]> {
+  let SubRegIndices = [lo16, hi16];
+  let CoveredBySubRegs = 1;
+}
+
+def R2R3 : RegisterWithSubRegs<"r2r3", [R2, R3]> {
+  let SubRegIndices = [sub0, sub1];
+  let CoveredBySubRegs = 1;
+}
+
+// Case with hi16 removed
+def R0_LO16 : Register<"r0l">;
+def R0 : RegisterWithSubRegs<"r0", [R0_LO16]> {
+  let SubRegIndices = [lo16];
+  let CoveredBySubRegs = 0;
+}
+
+def R1_LO16 : Register<"r1l">;
+def R1 : RegisterWithSubRegs<"r1", [R1_LO16]> {
+  let SubRegIndices = [lo16];
+  let CoveredBySubRegs = 0;
+}
+
+def R0R1 : RegisterWithSubRegs<"r0r1", [R0, R1]> {
+  let SubRegIndices = [sub0, sub1];
+  let CoveredBySubRegs = 1;
+}
+
+def TestRC32 : RegisterClass<"Test", [i32], 32, (add R0, R1, R2, R3)>;
+def TestRC64 : RegisterClass<"Test", [i64], 64, (add R0R1, R2R3)>;
+
+// CHECK: extern const LaneBitmask TestTargetLaneMaskLists[] = {
+// CHECK-NEXT: /* 0 */ LaneBitmask(0x0000000000000002), LaneBitmask(0x0000000000000001),
+// CHECK-NEXT: /* 2 */ LaneBitmask(0x0000000000000002),
+// CHECK-NEXT: /* 3 */ LaneBitmask(0x0000000000000002), LaneBitmask(0x0000000000000001), LaneBitmask(0x0000000000000004), LaneBitmask(0x0000000000000008),
+// CHECK-NEXT: /* 7 */ LaneBitmask(0x0000000000000003), LaneBitmask(0x000000000000000C),
+// CHECK-NEXT: /* 9 */ LaneBitmask(0xFFFFFFFFFFFFFFFF),
+// CHECK-NEXT: };
+
+// CHECK: extern const MCRegisterDesc TestTargetRegDesc[] = {
+// CHECK: { 3, 26, 6, 3, 36864, 7, 0, 0 },
+
+// CHECK: static const LaneBitmask TestTargetSubRegIndexLaneMaskTable[] = {
+// CHECK-NEXT: LaneBitmask::getAll(),
+// CHECK-NEXT: LaneBitmask(0x0000000000000001), // hi16
+// CHECK-NEXT: LaneBitmask(0x0000000000000002), // lo16
+// CHECK-NEXT: LaneBitmask(0x0000000000000003), // sub0
+// CHECK-NEXT: LaneBitmask(0x000000000000000C), // sub1

diff  --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 10a5a16feef78..e1675ab68d20c 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -2378,7 +2378,8 @@ void CodeGenRegBank::computeRegUnitLaneMasks() {
     const SubRegMap &SubRegs = Register.getSubRegs();
     for (auto [SubRegIndex, SubReg] : SubRegs) {
       // Ignore non-leaf subregisters, their lane masks are fully covered by
-      // the leaf subregisters anyway.
+      // the leaf subregisters, unless the subregister is not CoveredBySubRegs -
+      // this is dealt with by the loop below.
       if (!SubReg->getSubRegs().empty())
         continue;
       LaneBitmask LaneMask = SubRegIndex->LaneMask;
@@ -2398,6 +2399,32 @@ void CodeGenRegBank::computeRegUnitLaneMasks() {
         assert(Found);
       }
     }
+
+    auto UnitMaskIdx = [&](unsigned SUI) {
+      unsigned U = 0;
+      for (unsigned RU : RegUnits) {
+        if (SUI == RU)
+          return U;
+        ++U;
+      }
+      llvm_unreachable("unit is not part of the register");
+    };
+
+    // A sub-register that is not CoveredBySubRegs may be missing lanes that
+    // none of its leaves account for. If left unclaimed, those lanes would
+    // not appear in any register unit's mask, making them invisible to
+    // interference and liveness queries. Backfill the missing lanes onto the
+    // sub-register's own native units.
+    for (auto [SubRegIndex, SubReg] : SubRegs) {
+      if (SubReg->CoveredBySubRegs || SubReg->getSubRegs().empty())
+        continue;
+      LaneBitmask Unclaimed = SubRegIndex->LaneMask;
+      for (unsigned SUI : SubReg->getNativeRegUnits())
+        Unclaimed &= ~RegUnitLaneMasks[UnitMaskIdx(SUI)];
+      for (unsigned SUI : SubReg->getNativeRegUnits())
+        RegUnitLaneMasks[UnitMaskIdx(SUI)] |= Unclaimed;
+    }
+
     Register.setRegUnitLaneMasks(RegUnitLaneMasks);
   }
 }


        


More information about the llvm-commits mailing list