Skip to content

Commit 598ec8c

Browse files
authored
[LLVM][TableGen] Parameterize NumToSkip in DecoderEmitter (#135882)
- Add command line option `num-to-skip-size` to parameterize the size of `NumToSkip` bytes in the decoder table. Default value will be 2, and targets that need larger size can use 3. - Keep all existing targets, except AArch64, to use size 2, and change AArch64 to use size 3 since it run into the "disassembler decoding table too large" error with size 2. - Following is a rough reduction in size for the decoder tables by switching to size 2. ``` Target Old Size New Size % Reduction ================================================ AArch64 153254 153254 0.00 AMDGPU 471566 412805 12.46 ARC 5724 5061 11.58 ARM 84936 73831 13.07 AVR 1497 1306 12.76 BPF 2172 1927 11.28 CSKY 10064 8692 13.63 Hexagon 47967 41965 12.51 Lanai 1108 982 11.37 LoongArch 24446 21621 11.56 MSP430 4200 3716 11.52 Mips 36330 31415 13.53 PPC 31897 28098 11.91 RISCV 37979 32790 13.66 Sparc 8331 7252 12.95 SystemZ 36722 32248 12.18 VE 48296 42873 11.23 XCore 2590 2316 10.58 Xtensa 3827 3316 13.35 ```
1 parent d338bdc commit 598ec8c

File tree

7 files changed

+83
-68
lines changed

7 files changed

+83
-68
lines changed

llvm/lib/Target/AArch64/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer)
77
tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1)
88
tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv)
99
tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel)
10-
tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler)
10+
tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler --num-to-skip-size=3)
1111
tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel)
1212
tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel)
1313
tablegen(LLVM AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner

llvm/test/TableGen/VarLenDecoder.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ def FOO32 : MyVarInst<MemOp32> {
4747
}
4848

4949
// CHECK: MCD::OPC_ExtractField, 3, 5, // Inst{7-3} ...
50-
// CHECK-NEXT: MCD::OPC_FilterValue, 8, 4, 0, 0, // Skip to: 12
50+
// CHECK-NEXT: MCD::OPC_FilterValue, 8, 4, 0, // Skip to: 11
5151
// CHECK-NEXT: MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
52-
// CHECK-NEXT: MCD::OPC_FilterValue, 9, 4, 0, 0, // Skip to: 21
52+
// CHECK-NEXT: MCD::OPC_FilterValue, 9, 4, 0, // Skip to: 19
5353
// CHECK-NEXT: MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
5454
// CHECK-NEXT: MCD::OPC_Fail,
5555

llvm/test/TableGen/trydecode-emission.td

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ def InstB : TestInstruction {
3434
}
3535

3636
// CHECK: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
37-
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 18, 0, 0, // Skip to: 26
38-
// CHECK-NEXT: /* 8 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 22
39-
// CHECK-NEXT: /* 15 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 22
40-
// CHECK-NEXT: /* 22 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
41-
// CHECK-NEXT: /* 26 */ MCD::OPC_Fail,
37+
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 16, 0, // Skip to: 23
38+
// CHECK-NEXT: /* 7 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 19
39+
// CHECK-NEXT: /* 13 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 19
40+
// CHECK-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
41+
// CHECK-NEXT: /* 23 */ MCD::OPC_Fail,
4242

4343
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }

llvm/test/TableGen/trydecode-emission2.td

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ def InstB : TestInstruction {
3131
}
3232

3333
// CHECK: /* 0 */ MCD::OPC_ExtractField, 2, 1, // Inst{2} ...
34-
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 36, 0, 0, // Skip to: 44
35-
// CHECK-NEXT: /* 8 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
36-
// CHECK-NEXT: /* 11 */ MCD::OPC_FilterValue, 0, 28, 0, 0, // Skip to: 44
37-
// CHECK-NEXT: /* 16 */ MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 30
38-
// CHECK-NEXT: /* 23 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 30
39-
// CHECK-NEXT: /* 30 */ MCD::OPC_CheckField, 3, 2, 0, 7, 0, 0, // Skip to: 44
40-
// CHECK-NEXT: /* 37 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 1, 0, 0, 0, // Opcode: InstA, skip to: 44
41-
// CHECK-NEXT: /* 44 */ MCD::OPC_Fail,
34+
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 31, 0, // Skip to: 38
35+
// CHECK-NEXT: /* 7 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
36+
// CHECK-NEXT: /* 10 */ MCD::OPC_FilterValue, 0, 24, 0, // Skip to: 38
37+
// CHECK-NEXT: /* 14 */ MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 26
38+
// CHECK-NEXT: /* 20 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 26
39+
// CHECK-NEXT: /* 26 */ MCD::OPC_CheckField, 3, 2, 0, 6, 0, // Skip to: 38
40+
// CHECK-NEXT: /* 32 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 1, 0, 0, // Opcode: InstA, skip to: 38
41+
// CHECK-NEXT: /* 38 */ MCD::OPC_Fail,
4242

4343
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
4444
// CHECK: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }

llvm/test/TableGen/trydecode-emission3.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | FileCheck %s
1+
// RUN: llvm-tblgen -gen-disassembler --num-to-skip-size=3 -I %p/../../include %s | FileCheck %s
22

33
include "llvm/Target/Target.td"
44

llvm/test/TableGen/trydecode-emission4.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | FileCheck %s
1+
// RUN: llvm-tblgen -gen-disassembler --num-to-skip-size=3 -I %p/../../include %s | FileCheck %s
22

33
// Test for OPC_ExtractField/OPC_CheckField with start bit > 255.
44
// These large start values may arise for architectures with long instruction

llvm/utils/TableGen/DecoderEmitter.cpp

Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
#include "llvm/Support/CommandLine.h"
3333
#include "llvm/Support/Debug.h"
3434
#include "llvm/Support/ErrorHandling.h"
35+
#include "llvm/Support/FormatVariadic.h"
3536
#include "llvm/Support/FormattedStream.h"
3637
#include "llvm/Support/LEB128.h"
38+
#include "llvm/Support/MathExtras.h"
3739
#include "llvm/Support/raw_ostream.h"
3840
#include "llvm/TableGen/Error.h"
3941
#include "llvm/TableGen/Record.h"
@@ -76,6 +78,12 @@ static cl::opt<SuppressLevel> DecoderEmitterSuppressDuplicates(
7678
"significantly reducing Table Duplications")),
7779
cl::init(SUPPRESSION_DISABLE), cl::cat(DisassemblerEmitterCat));
7880

81+
static cl::opt<uint32_t>
82+
NumToSkipSizeInBytes("num-to-skip-size",
83+
cl::desc("number of bytes to use for num-to-skip "
84+
"entries in the decoder table (2 or 3)"),
85+
cl::init(2), cl::cat(DisassemblerEmitterCat));
86+
7987
STATISTIC(NumEncodings, "Number of encodings considered");
8088
STATISTIC(NumEncodingsLackingDisasm,
8189
"Number of encodings without disassembler info");
@@ -130,10 +138,29 @@ struct DecoderTable : public std::vector<uint8_t> {
130138
// in the table for patching.
131139
size_t insertNumToSkip() {
132140
size_t Size = size();
133-
insert(end(), 3, 0);
141+
insert(end(), NumToSkipSizeInBytes, 0);
134142
return Size;
135143
}
144+
145+
void patchNumToSkip(size_t FixupIdx, uint32_t DestIdx) {
146+
// Calculate the distance from the byte following the fixup entry byte
147+
// to the destination. The Target is calculated from after the
148+
// `NumToSkipSizeInBytes`-byte NumToSkip entry itself, so subtract
149+
// `NumToSkipSizeInBytes` from the displacement here to account for that.
150+
assert(DestIdx > FixupIdx + NumToSkipSizeInBytes &&
151+
"Expecting a forward jump in the decoding table");
152+
uint32_t Delta = DestIdx - FixupIdx - NumToSkipSizeInBytes;
153+
if (!isUIntN(8 * NumToSkipSizeInBytes, Delta))
154+
PrintFatalError(
155+
"disassembler decoding table too large, try --num-to-skip-size=3");
156+
157+
(*this)[FixupIdx] = static_cast<uint8_t>(Delta);
158+
(*this)[FixupIdx + 1] = static_cast<uint8_t>(Delta >> 8);
159+
if (NumToSkipSizeInBytes == 3)
160+
(*this)[FixupIdx + 2] = static_cast<uint8_t>(Delta >> 16);
161+
}
136162
};
163+
137164
struct DecoderTableInfo {
138165
DecoderTable Table;
139166
FixupScopeList FixupStack;
@@ -690,19 +717,8 @@ static void resolveTableFixups(DecoderTable &Table, const FixupList &Fixups,
690717
uint32_t DestIdx) {
691718
// Any NumToSkip fixups in the current scope can resolve to the
692719
// current location.
693-
for (uint32_t FixupIdx : reverse(Fixups)) {
694-
// Calculate the distance from the byte following the fixup entry byte
695-
// to the destination. The Target is calculated from after the 24-bit
696-
// NumToSkip entry itself, so subtract three from the displacement here
697-
// to account for that.
698-
uint32_t Delta = DestIdx - FixupIdx - 3;
699-
// Our NumToSkip entries are 24-bits. Make sure our table isn't too
700-
// big.
701-
assert(isUInt<24>(Delta));
702-
Table[FixupIdx] = (uint8_t)Delta;
703-
Table[FixupIdx + 1] = (uint8_t)(Delta >> 8);
704-
Table[FixupIdx + 2] = (uint8_t)(Delta >> 16);
705-
}
720+
for (uint32_t FixupIdx : Fixups)
721+
Table.patchNumToSkip(FixupIdx, DestIdx);
706722
}
707723

708724
// Emit table entries to decode instructions given a segment or segments
@@ -759,15 +775,9 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
759775
Delegate->emitTableEntries(TableInfo);
760776

761777
// Now that we've emitted the body of the handler, update the NumToSkip
762-
// of the filter itself to be able to skip forward when false. Subtract
763-
// three as to account for the width of the NumToSkip field itself.
764-
if (PrevFilter) {
765-
uint32_t NumToSkip = Table.size() - PrevFilter - 3;
766-
assert(isUInt<24>(NumToSkip) && "disassembler decoding table too large!");
767-
Table[PrevFilter] = (uint8_t)NumToSkip;
768-
Table[PrevFilter + 1] = (uint8_t)(NumToSkip >> 8);
769-
Table[PrevFilter + 2] = (uint8_t)(NumToSkip >> 16);
770-
}
778+
// of the filter itself to be able to skip forward when false.
779+
if (PrevFilter)
780+
Table.patchNumToSkip(PrevFilter, Table.size());
771781
}
772782

773783
// If there is no fallthrough, then the final filter should get fixed
@@ -814,7 +824,8 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
814824
OS << (unsigned)*I++ << ", ";
815825
};
816826

817-
// Emit 24-bit numtoskip value to OS, returning the NumToSkip value.
827+
// Emit `NumToSkipSizeInBytes`-byte numtoskip value to OS, returning the
828+
// NumToSkip value.
818829
auto emitNumToSkip = [](DecoderTable::const_iterator &I,
819830
formatted_raw_ostream &OS) {
820831
uint8_t Byte = *I++;
@@ -823,9 +834,11 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
823834
Byte = *I++;
824835
OS << (unsigned)Byte << ", ";
825836
NumToSkip |= Byte << 8;
826-
Byte = *I++;
827-
OS << (unsigned)(Byte) << ", ";
828-
NumToSkip |= Byte << 16;
837+
if (NumToSkipSizeInBytes == 3) {
838+
Byte = *I++;
839+
OS << (unsigned)(Byte) << ", ";
840+
NumToSkip |= Byte << 16;
841+
}
829842
return NumToSkip;
830843
};
831844

@@ -867,7 +880,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
867880
// The filter value is ULEB128 encoded.
868881
emitULEB128(I, OS);
869882

870-
// 24-bit numtoskip value.
883+
// numtoskip value.
871884
uint32_t NumToSkip = emitNumToSkip(I, OS);
872885
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
873886
break;
@@ -883,7 +896,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
883896
// ULEB128 encoded field value.
884897
emitULEB128(I, OS);
885898

886-
// 24-bit numtoskip value.
899+
// numtoskip value.
887900
uint32_t NumToSkip = emitNumToSkip(I, OS);
888901
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
889902
break;
@@ -893,7 +906,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
893906
OS << Indent << "MCD::OPC_CheckPredicate, ";
894907
emitULEB128(I, OS);
895908

896-
// 24-bit numtoskip value.
909+
// numtoskip value.
897910
uint32_t NumToSkip = emitNumToSkip(I, OS);
898911
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
899912
break;
@@ -925,7 +938,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
925938

926939
// Fallthrough for OPC_TryDecode.
927940

928-
// 24-bit numtoskip value.
941+
// numtoskip value.
929942
uint32_t NumToSkip = emitNumToSkip(I, OS);
930943

931944
OS << "// Opcode: " << NumberedEncodings[EncodingID]
@@ -1411,9 +1424,9 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
14111424
TableInfo.Table.push_back(NumBits);
14121425
TableInfo.Table.insertULEB128(Ilnd.FieldVal);
14131426

1414-
// The fixup is always 24-bits, so go ahead and allocate the space
1415-
// in the table so all our relative position calculations work OK even
1416-
// before we fully resolve the real value here.
1427+
// Allocate space in the table for fixup (NumToSkipSizeInBytes) so all
1428+
// our relative position calculations work OK even before we fully
1429+
// resolve the real value here.
14171430

14181431
// Push location for NumToSkip backpatching.
14191432
TableInfo.FixupStack.back().push_back(TableInfo.Table.insertNumToSkip());
@@ -2157,7 +2170,18 @@ insertBits(InsnType &field, uint64_t bits, unsigned startBit, unsigned numBits)
21572170
// decodeInstruction().
21582171
static void emitDecodeInstruction(formatted_raw_ostream &OS,
21592172
bool IsVarLenInst) {
2173+
OS << formatv("\nconstexpr unsigned NumToSkipSizeInBytes = {};\n",
2174+
NumToSkipSizeInBytes);
2175+
21602176
OS << R"(
2177+
inline unsigned decodeNumToSkip(const uint8_t *&Ptr) {
2178+
unsigned NumToSkip = *Ptr++;
2179+
NumToSkip |= (*Ptr++) << 8;
2180+
if constexpr (NumToSkipSizeInBytes == 3)
2181+
NumToSkip |= (*Ptr++) << 16;
2182+
return NumToSkip;
2183+
}
2184+
21612185
template <typename InsnType>
21622186
static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
21632187
InsnType insn, uint64_t Address,
@@ -2195,10 +2219,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
21952219
// Decode the field value.
21962220
uint64_t Val = decodeULEB128AndIncUnsafe(++Ptr);
21972221
bool Failed = Val != CurFieldValue;
2198-
// NumToSkip is a plain 24-bit integer.
2199-
unsigned NumToSkip = *Ptr++;
2200-
NumToSkip |= (*Ptr++) << 8;
2201-
NumToSkip |= (*Ptr++) << 16;
2222+
unsigned NumToSkip = decodeNumToSkip(Ptr);
22022223
22032224
// Perform the filter operation.
22042225
if (Failed)
@@ -2222,10 +2243,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
22222243
uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);
22232244
Ptr += PtrLen;
22242245
bool Failed = ExpectedValue != FieldValue;
2225-
// NumToSkip is a plain 24-bit integer.
2226-
unsigned NumToSkip = *Ptr++;
2227-
NumToSkip |= (*Ptr++) << 8;
2228-
NumToSkip |= (*Ptr++) << 16;
2246+
unsigned NumToSkip = decodeNumToSkip(Ptr);
22292247
22302248
// If the actual and expected values don't match, skip.
22312249
if (Failed)
@@ -2240,10 +2258,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
22402258
case MCD::OPC_CheckPredicate: {
22412259
// Decode the Predicate Index value.
22422260
unsigned PIdx = decodeULEB128AndIncUnsafe(++Ptr);
2243-
// NumToSkip is a plain 24-bit integer.
2244-
unsigned NumToSkip = *Ptr++;
2245-
NumToSkip |= (*Ptr++) << 8;
2246-
NumToSkip |= (*Ptr++) << 16;
2261+
unsigned NumToSkip = decodeNumToSkip(Ptr);
22472262
// Check the predicate.
22482263
bool Failed = !checkDecoderPredicate(PIdx, Bits);
22492264
if (Failed)
@@ -2278,10 +2293,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
22782293
// Decode the Opcode value.
22792294
unsigned Opc = decodeULEB128AndIncUnsafe(++Ptr);
22802295
unsigned DecodeIdx = decodeULEB128AndIncUnsafe(Ptr);
2281-
// NumToSkip is a plain 24-bit integer.
2282-
unsigned NumToSkip = *Ptr++;
2283-
NumToSkip |= (*Ptr++) << 8;
2284-
NumToSkip |= (*Ptr++) << 16;
2296+
unsigned NumToSkip = decodeNumToSkip(Ptr);
22852297
22862298
// Perform the decode operation.
22872299
MCInst TmpMI;
@@ -2406,6 +2418,9 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr,
24062418

24072419
// Emits disassembler code for instruction decoding.
24082420
void DecoderEmitter::run(raw_ostream &o) {
2421+
if (NumToSkipSizeInBytes != 2 && NumToSkipSizeInBytes != 3)
2422+
PrintFatalError("Invalid value for num-to-skip-size, must be 2 or 3");
2423+
24092424
formatted_raw_ostream OS(o);
24102425
OS << R"(
24112426
#include "llvm/MC/MCInst.h"

0 commit comments

Comments
 (0)