[MC][NFC] Store RegBitSet more compact - #218701
Conversation
Created using spr 1.3.8-wip
|
@llvm/pr-subscribers-tablegen @llvm/pr-subscribers-llvm-mc Author: Alexis Engelke (aengelke) ChangesMost register bit sets have their first register at a large offset,
This also opens up deduplication potential for the future -- in addition Full diff: https://github.com/llvm/llvm-project/pull/218701.diff 3 Files Affected:
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";
}
|
You can test this locally with the following command:git-clang-format --diff origin/main HEAD --extensions cpp,h -- llvm/include/llvm/MC/MCRegisterInfo.h llvm/unittests/CodeGen/MachineInstrTest.cpp llvm/utils/TableGen/RegisterInfoEmitter.cpp --diff_from_common_commit
View the diff from clang-format here.diff --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp
index 8ac5ad175..ff06bb13f 100644
--- a/llvm/unittests/CodeGen/MachineInstrTest.cpp
+++ b/llvm/unittests/CodeGen/MachineInstrTest.cpp
@@ -592,9 +592,28 @@ TEST(MachineInstrTest, SpliceOperands) {
EXPECT_EQ(MI->getOperand(8).getImm(), MachineOperand::CreateImm(4).getImm());
// test tied operands
- MCRegisterClass RC{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true,
- 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+ MCRegisterClass RC{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.
assert(RC.isAllocatable() && "unusable TargetRegisterClass");
|
|
... going to ignore clang-format here. |
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).
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:
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).