[llvm] [MC][NFC] Store RegBitSet more compact (PR #218701)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 07:53:23 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-mc

Author: Alexis Engelke (aengelke)

<details>
<summary>Changes</summary>

Most register bit sets have their first register at a large offset,
causing a lot of 0 bytes to be stored in the RegBitSets. Avoid this by
storing the number of the lowest register in the MCRegisterClass. This
substantially reduces the size of the bit sets:

- AArch64: 35010 -> 1356
- AMDGPU: 1500754 -> 118320
- PowerPC: 2202 -> 610
- RISCV: 5700 -> 429
- X86: 2329 -> 927

This also opens up deduplication potential for the future -- in addition
to duplicates, a common pattern is a streak of the first N bits. To ease
future deduplication, store the maximum register offset instead of the
bitset size in bytes (so the bitset 0xff,0xff could absorb the bitsets
0xff,0x3f and 0x01).


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


3 Files Affected:

- (modified) llvm/include/llvm/MC/MCRegisterInfo.h (+6-4) 
- (modified) llvm/unittests/CodeGen/MachineInstrTest.cpp (+1-1) 
- (modified) llvm/utils/TableGen/RegisterInfoEmitter.cpp (+20-10) 


``````````diff
diff --git a/llvm/include/llvm/MC/MCRegisterInfo.h b/llvm/include/llvm/MC/MCRegisterInfo.h
index 9b894f5b6bf37..76c72bb08007d 100644
--- a/llvm/include/llvm/MC/MCRegisterInfo.h
+++ b/llvm/include/llvm/MC/MCRegisterInfo.h
@@ -45,6 +45,8 @@ class MCRegisterClass {
   const uint32_t NameIdx;
   const uint32_t RegSizeInBits;
   const uint16_t RegsSize;
+  /// Register denoted by first bit in RegSet.
+  const MCPhysReg RegSetBegin;
   const uint16_t RegSetSize;
   const uint16_t ID;
   const uint8_t CopyCost;
@@ -102,11 +104,11 @@ class MCRegisterClass {
   /// contains - Return true if the specified register is included in this
   /// register class.  This does not include virtual registers.
   bool contains(MCRegister Reg) const {
-    unsigned RegNo = Reg.id();
-    unsigned InByte = RegNo % 8;
-    unsigned Byte = RegNo / 8;
-    if (Byte >= RegSetSize)
+    unsigned RegSetIdx = Reg.id() - RegSetBegin;
+    if (RegSetIdx >= RegSetSize)
       return false;
+    unsigned InByte = RegSetIdx % 8;
+    unsigned Byte = RegSetIdx / 8;
     const uint8_t *RegSet = reinterpret_cast<const uint8_t *>(this) + RegSetOff;
     return (RegSet[Byte] & (1 << InByte)) != 0;
   }
diff --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp
index 03f4077ea55ac..8ac5ad175a3b5 100644
--- a/llvm/unittests/CodeGen/MachineInstrTest.cpp
+++ b/llvm/unittests/CodeGen/MachineInstrTest.cpp
@@ -593,7 +593,7 @@ TEST(MachineInstrTest, SpliceOperands) {
 
   // test tied operands
   MCRegisterClass RC{
-      0, 0, 0,  0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true,
       0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
   // MachineRegisterInfo will be very upset if these registers aren't
   // allocatable.
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index 6c64330c1f374..c57345d020708 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1145,10 +1145,13 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
     unsigned BitSetIdx;
     unsigned SubClassMaskIdx;
     unsigned SuperClassIdx;
+    // Not strictly an index, but to avoid recomputation: cache reg set range.
+    unsigned MinRegVal;
+    unsigned RegSetSize;
   };
   SmallVector<StartIndex> StartIndices;
   StartIndices.reserve(RegisterClasses.size() + 1);
-  StartIndices.push_back(StartIndex{0, 0, 0, 0});
+  StartIndices.push_back(StartIndex{0, 0, 0, 0, 0, 0});
 
   // For compressing the sub-reg index lists.
   using IdxList = std::vector<const CodeGenSubRegIndex *>;
@@ -1159,9 +1162,11 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
     ArrayRef<const Record *> Order = RC.getOrder();
     RegClassStrings.add(RC.getName());
 
-    unsigned MaxRegVal = 0;
-    for (const Record *Reg : Order)
+    unsigned MinRegVal = UINT_MAX, MaxRegVal = 0;
+    for (const Record *Reg : Order) {
+      MinRegVal = std::min(MinRegVal, RegBank.getReg(Reg)->EnumValue);
       MaxRegVal = std::max(MaxRegVal, RegBank.getReg(Reg)->EnumValue);
+    }
 
     unsigned SubClassMaskSize = (RC.getSubClasses().size() + 31) / 32;
     IdxList &SRIList = SuperRegIdxLists[RC.EnumValue];
@@ -1175,13 +1180,18 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
     }
     SuperRegIdxSeqs.add(SRIList);
 
-    const auto &Last = StartIndices.back();
+    auto &Last = StartIndices.back();
+    Last.MinRegVal = Order.empty() ? 0 : MinRegVal;
+    Last.RegSetSize = Order.empty() ? 0 : MaxRegVal - MinRegVal + 1;
     StartIndices.push_back(StartIndex{
         Last.RegIdx + unsigned(Order.size()),
         // Round to next byte size.
-        Last.BitSetIdx + (Order.empty() ? 0 : (MaxRegVal / 8) + 1),
+        Last.BitSetIdx +
+            (Order.empty() ? 0 : ((MaxRegVal - MinRegVal) / 8) + 1),
         Last.SubClassMaskIdx + SubClassMaskSize,
         Last.SuperClassIdx + unsigned(RC.getSuperClasses().size()),
+        0, // MinRegVal for next RegClass.
+        0, // RegSetSize for next RegClass.
     });
   }
 
@@ -1219,13 +1229,13 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
           .str();
     };
 
-    unsigned BitSetSize =
-        StartIndices[It.index() + 1].BitSetIdx - RCIndices.BitSetIdx;
     OS << "    {\n      " << GetOff("Regs", RCIndices.RegIdx) << ",\n      "
        << GetOff("BitSets", RCIndices.BitSetIdx) << ",\n      "
        << RegClassStrings.get(RC.getName()) << ",\n      " << RegSize
-       << ",\n      " << RC.getOrder().size() << ",\n      " << BitSetSize
-       << ",\n      " << RC.getQualifiedIdName() << ",\n      "
+       << ",\n      " << RC.getOrder().size() << ",\n      "
+       << RCIndices.MinRegVal << ", /* MinRegVal */\n      "
+       << RCIndices.RegSetSize << ", /* RegSetSize */\n      "
+       << RC.getQualifiedIdName() << ",\n      "
        << static_cast<unsigned>(RC.CopyCost) << ", /* CopyCost */\n      "
        << (RC.Allocatable ? "true" : "false") << ", /* Allocatable */\n      "
        << (RC.getBaseClassOrder() ? "true" : "false") << ",\n      "
@@ -1269,7 +1279,7 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS,
       OS << "    /* " << StartIndices[Idx].BitSetIdx << " */ ";
       BitVectorEmitter BVE;
       for (const Record *Reg : Order)
-        BVE.add(RegBank.getReg(Reg)->EnumValue);
+        BVE.add(RegBank.getReg(Reg)->EnumValue - StartIndices[Idx].MinRegVal);
       BVE.print(OS);
       OS << "\n";
     }

``````````

</details>


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


More information about the llvm-commits mailing list