[LLVM][MC] Introduce OrFail variants of MCD ops (#138614)

Introduce `OrFail` variants for all MCD Decoder Ops that have
`NumToSKip` encoded with them. This is intended to capture the common
case of jumps to the end of the decoder table which has a `OP_Fail` at
the end. Using the `OrFail` variants of these ops avoid encoding the
`NumToSkip` jump offset for these cases, resulting in a reduction in the
size of the decoder tables (from 5 - 17%). Additionally, for the AArch64
target, the table size reduces enough to switch to using 2-byte
`NumToSkip` encoding instead of existing 3-bytes, resulting in a net 30%
reduction in the size of the decoder table.

The total reduction in the size of the decoder tables for different
targets is as follows (computed using the following command: `for i in
*.inc; do echo -n ``basename $i: ``; grep "MCD::OPC_Fail," $i | awk
'{sum += $2} END { print sum}'; done`)

```
Target         Old Size   New Size   % Reduction
================================================
AArch64           153268     106987       30.20
AMDGPU            412056     340856       17.28
ARC                 5061       4605        9.01
ARM                73831      60847       17.59
AVR                 1306       1158       11.33
BPF                 1927       1795        6.85
CSKY                8692       6922       20.36
Hexagon            41965      34759       17.17
Lanai                982        924        5.91
LoongArch          21629      20035        7.37
M68k               13461      11689       13.16
MSP430              3716       3384        8.93
Mips               31415      25771       17.97
PPC                28931      24771       14.38
RISCV              34800      28352       18.53
Sparc               7432       6236       16.09
SystemZ            32248      29716        7.85
VE                 42873      36923       13.88
XCore               2316       2196        5.18
Xtensa              3443       2793       18.88
```
This commit is contained in:
Rahul Joshi 2025-06-05 06:17:50 -07:00 committed by GitHub
parent 43bc5ea7fd
commit e53ccb78e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 248 additions and 153 deletions

View File

@ -10,24 +10,29 @@
#ifndef LLVM_MC_MCDECODEROPS_H
#define LLVM_MC_MCDECODEROPS_H
namespace llvm {
namespace llvm::MCD {
namespace MCD {
// Disassembler state machine opcodes.
// nts_t is either uint16_t or uint24_t based on whether large decoder table is
// enabled.
enum DecoderOps {
OPC_ExtractField = 1, // OPC_ExtractField(uleb128 Start, uint8_t Len)
OPC_FilterValue, // OPC_FilterValue(uleb128 Val, uint16_t NumToSkip)
OPC_FilterValue, // OPC_FilterValue(uleb128 Val, nts_t NumToSkip)
OPC_FilterValueOrFail, // OPC_FilterValueOrFail(uleb128 Val)
OPC_CheckField, // OPC_CheckField(uleb128 Start, uint8_t Len,
// uleb128 Val, uint16_t NumToSkip)
OPC_CheckPredicate, // OPC_CheckPredicate(uleb128 PIdx, uint16_t NumToSkip)
// uleb128 Val, nts_t NumToSkip)
OPC_CheckFieldOrFail, // OPC_CheckFieldOrFail(uleb128 Start, uint8_t Len,
// uleb128 Val)
OPC_CheckPredicate, // OPC_CheckPredicate(uleb128 PIdx, nts_t NumToSkip)
OPC_CheckPredicateOrFail, // OPC_CheckPredicateOrFail(uleb128 PIdx)
OPC_Decode, // OPC_Decode(uleb128 Opcode, uleb128 DIdx)
OPC_TryDecode, // OPC_TryDecode(uleb128 Opcode, uleb128 DIdx,
// uint16_t NumToSkip)
// nts_t NumToSkip)
OPC_TryDecodeOrFail, // OPC_TryDecodeOrFail(uleb128 Opcode, uleb128 DIdx)
OPC_SoftFail, // OPC_SoftFail(uleb128 PMask, uleb128 NMask)
OPC_Fail // OPC_Fail()
};
} // namespace MCD
} // namespace llvm
} // namespace llvm::MCD
#endif

View File

@ -7,8 +7,7 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1)
tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv)
tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel)
tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler
--large-decoder-table)
tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel)
tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel)
tablegen(LLVM AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner

View File

@ -47,19 +47,19 @@ def FOO32 : MyVarInst<MemOp32> {
);
}
// CHECK-SMALL: MCD::OPC_ExtractField, 3, 5, // Inst{7-3} ...
// CHECK-SMALL-NEXT: MCD::OPC_FilterValue, 8, 4, 0, // Skip to: 11
// CHECK-SMALL-NEXT: MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
// CHECK-SMALL-NEXT: MCD::OPC_FilterValue, 9, 4, 0, // Skip to: 19
// CHECK-SMALL-NEXT: MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
// CHECK-SMALL-NEXT: MCD::OPC_Fail,
// CHECK-SMALL: /* 0 */ MCD::OPC_ExtractField, 3, 5, // Inst{7-3} ...
// CHECK-SMALL-NEXT: /* 3 */ MCD::OPC_FilterValue, 8, 4, 0, // Skip to: 11
// CHECK-SMALL-NEXT: /* 7 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
// CHECK-SMALL-NEXT: /* 11 */ MCD::OPC_FilterValueOrFail, 9,
// CHECK-SMALL-NEXT: /* 13 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
// CHECK-SMALL-NEXT: /* 17 */ MCD::OPC_Fail,
// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 3, 5, // Inst{7-3} ...
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValue, 8, 4, 0, 0, // Skip to: 12
// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
// CHECK-LARGE-NEXT: /* 12 */ MCD::OPC_FilterValue, 9, 4, 0, 0, // Skip to: 21
// CHECK-LARGE-NEXT: /* 17 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
// CHECK-LARGE-NEXT: /* 21 */ MCD::OPC_Fail,
// CHECK-LARGE-NEXT: /* 12 */ MCD::OPC_FilterValueOrFail, 9,
// CHECK-LARGE-NEXT: /* 14 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
// CHECK-LARGE-NEXT: /* 18 */ MCD::OPC_Fail,
// Instruction length table
// CHECK: 27,
@ -88,7 +88,8 @@ def FOO32 : MyVarInst<MemOp32> {
// CHECK-LABEL: case MCD::OPC_ExtractField: {
// CHECK: makeUp(insn, Start + Len);
// CHECK-LABEL: case MCD::OPC_CheckField: {
// CHECK-LABEL: case MCD::OPC_CheckField:
// CHECK-NEXT: case MCD::OPC_CheckFieldOrFail: {
// CHECK: makeUp(insn, Start + Len);
// CHECK-LABEL: case MCD::OPC_Decode: {

View File

@ -35,11 +35,11 @@ def InstB : TestInstruction {
}
// CHECK: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 16, 0, // Skip to: 23
// CHECK-NEXT: /* 7 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 19
// CHECK-NEXT: /* 13 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 19
// CHECK-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: /* 23 */ MCD::OPC_Fail,
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
// CHECK-NEXT: /* 11 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 17
// CHECK-NEXT: /* 17 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: /* 21 */ MCD::OPC_Fail,
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
@ -48,11 +48,11 @@ def InstB : TestInstruction {
// CHECK-NEXT: return NumToSkip;
// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 18, 0, 0, // Skip to: 26
// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 22
// CHECK-LARGE-NEXT: /* 15 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 22
// CHECK-LARGE-NEXT: /* 22 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-LARGE-NEXT: /* 26 */ MCD::OPC_Fail,
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
// CHECK-LARGE-NEXT: /* 12 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 19
// CHECK-LARGE-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-LARGE-NEXT: /* 23 */ MCD::OPC_Fail,
// CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }

View File

@ -32,27 +32,27 @@ def InstB : TestInstruction {
}
// CHECK: /* 0 */ MCD::OPC_ExtractField, 2, 1, // Inst{2} ...
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 31, 0, // Skip to: 38
// CHECK-NEXT: /* 7 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
// CHECK-NEXT: /* 10 */ MCD::OPC_FilterValue, 0, 24, 0, // Skip to: 38
// CHECK-NEXT: /* 14 */ MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 26
// CHECK-NEXT: /* 20 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 26
// CHECK-NEXT: /* 26 */ MCD::OPC_CheckField, 3, 2, 0, 6, 0, // Skip to: 38
// CHECK-NEXT: /* 32 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 1, 0, 0, // Opcode: InstA, skip to: 38
// CHECK-NEXT: /* 38 */ MCD::OPC_Fail,
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-NEXT: /* 5 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
// CHECK-NEXT: /* 8 */ MCD::OPC_FilterValueOrFail, 0
// CHECK-NEXT: /* 10 */ MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 22
// CHECK-NEXT: /* 16 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 22
// CHECK-NEXT: /* 22 */ MCD::OPC_CheckFieldOrFail, 3, 2, 0,
// CHECK-NEXT: /* 26 */ MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
// CHECK-NEXT: /* 30 */ MCD::OPC_Fail,
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
// CHECK: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 2, 1, // Inst{2} ...
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 36, 0, 0, // Skip to: 44
// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
// CHECK-LARGE-NEXT: /* 11 */ MCD::OPC_FilterValue, 0, 28, 0, 0, // Skip to: 44
// CHECK-LARGE-NEXT: /* 16 */ MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 30
// CHECK-LARGE-NEXT: /* 23 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 30
// CHECK-LARGE-NEXT: /* 30 */ MCD::OPC_CheckField, 3, 2, 0, 7, 0, 0, // Skip to: 44
// CHECK-LARGE-NEXT: /* 37 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 1, 0, 0, 0, // Opcode: InstA, skip to: 44
// CHECK-LARGE-NEXT: /* 44 */ MCD::OPC_Fail,
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-LARGE-NEXT: /* 10 */ MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 24
// CHECK-LARGE-NEXT: /* 17 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 24
// CHECK-LARGE-NEXT: /* 24 */ MCD::OPC_CheckFieldOrFail, 3, 2, 0,
// CHECK-LARGE-NEXT: /* 28 */ MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
// CHECK-LARGE-NEXT: /* 32 */ MCD::OPC_Fail,
// CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
// CHECK-LARGE: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }

View File

@ -36,19 +36,19 @@ def InstB : TestInstruction {
}
// CHECK: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 16, 0, // Skip to: 23
// CHECK-NEXT: /* 7 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 19
// CHECK-NEXT: /* 13 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 19
// CHECK-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: /* 23 */ MCD::OPC_Fail,
// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
// CHECK-NEXT: /* 11 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 17
// CHECK-NEXT: /* 17 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: /* 21 */ MCD::OPC_Fail,
// CHECK: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValue, 0, 18, 0, 0, // Skip to: 26
// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 22
// CHECK-LARGE-NEXT: /* 15 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 22
// CHECK-LARGE-NEXT: /* 22 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-LARGE-NEXT: /* 26 */ MCD::OPC_Fail,
// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
// CHECK-LARGE-NEXT: /* 12 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 19
// CHECK-LARGE-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-LARGE-NEXT: /* 23 */ MCD::OPC_Fail,
// CHECK-LARGE: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }

View File

@ -34,21 +34,21 @@ def InstB : TestInstruction {
}
// CHECK: /* 0 */ MCD::OPC_ExtractField, 250, 3, 4, // Inst{509-506} ...
// CHECK-NEXT: /* 4 */ MCD::OPC_FilterValue, 0, 17, 0, // Skip to: 25
// CHECK-NEXT: /* 8 */ MCD::OPC_CheckField, 248, 3, 2, 0, 6, 0, // Skip to: 21
// CHECK-NEXT: /* 15 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 21
// CHECK-NEXT: /* 21 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: /* 25 */ MCD::OPC_Fail,
// CHECK-NEXT: /* 4 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-NEXT: /* 6 */ MCD::OPC_CheckField, 248, 3, 2, 0, 6, 0, // Skip to: 19
// CHECK-NEXT: /* 13 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 19
// CHECK-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: /* 23 */ MCD::OPC_Fail,
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 250, 3, 4, // Inst{509-506} ...
// CHECK-LARGE-NEXT: /* 4 */ MCD::OPC_FilterValue, 0, 19, 0, 0, // Skip to: 28
// CHECK-LARGE-NEXT: /* 9 */ MCD::OPC_CheckField, 248, 3, 2, 0, 7, 0, 0, // Skip to: 24
// CHECK-LARGE-NEXT: /* 17 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 24
// CHECK-LARGE-NEXT: /* 24 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-LARGE-NEXT: /* 28 */ MCD::OPC_Fail,
// CHECK-LARGE-NEXT: /* 4 */ MCD::OPC_FilterValueOrFail, 0,
// CHECK-LARGE-NEXT: /* 6 */ MCD::OPC_CheckField, 248, 3, 2, 0, 7, 0, 0, // Skip to: 21
// CHECK-LARGE-NEXT: /* 14 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 21
// CHECK-LARGE-NEXT: /* 21 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-LARGE-NEXT: /* 25 */ MCD::OPC_Fail,
// CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }

View File

@ -90,9 +90,9 @@ STATISTIC(NumInstructions, "Number of instructions considered");
STATISTIC(NumEncodingsSupported, "Number of encodings supported");
STATISTIC(NumEncodingsOmitted, "Number of encodings omitted");
namespace {
static unsigned getNumToSkipInBytes() { return LargeTable ? 3 : 2; }
unsigned getNumToSkipInBytes() { return LargeTable ? 3 : 2; }
namespace {
struct EncodingField {
unsigned Base, Width, Offset;
@ -182,6 +182,8 @@ struct DecoderTableInfo {
FixupScopeList FixupStack;
PredicateSet Predicates;
DecoderSet Decoders;
bool isOutermostScope() const { return FixupStack.size() == 1; }
};
struct EncodingAndInst {
@ -777,11 +779,21 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
PrevFilter = 0; // Don't re-process the filter's fallthrough.
} else {
Table.push_back(MCD::OPC_FilterValue);
// The last filtervalue emitted can be OPC_FilterValue if we are at
// outermost scope.
const uint8_t DecoderOp =
FilterVal == LastFilter && TableInfo.isOutermostScope()
? MCD::OPC_FilterValueOrFail
: MCD::OPC_FilterValue;
Table.push_back(DecoderOp);
Table.insertULEB128(FilterVal);
if (DecoderOp == MCD::OPC_FilterValue) {
// Reserve space for the NumToSkip entry. We'll backpatch the value
// later.
PrevFilter = Table.insertNumToSkip();
} else {
PrevFilter = 0;
}
}
// We arrive at a category of instructions with the same segment value.
@ -796,9 +808,10 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
Table.patchNumToSkip(PrevFilter, Table.size());
}
// If there is no fallthrough, then the final filter should get fixed
// up according to the enclosing scope rather than the current position.
if (!HasFallthrough)
// If there is no fallthrough and the final filter was not in the outermost
// scope, then it must be fixed up according to the enclosing scope rather
// than the current position.
if (PrevFilter)
TableInfo.FixupStack.back().push_back(PrevFilter);
}
@ -863,6 +876,15 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
DecoderTable::const_iterator I = Table.begin();
DecoderTable::const_iterator E = Table.end();
const uint8_t *const EndPtr = Table.data() + Table.size();
auto emitNumToSkipComment = [&](uint32_t NumToSkip, bool InComment = false) {
uint32_t Index = ((I - Table.begin()) + NumToSkip);
OS << (InComment ? ", " : "// ");
OS << "Skip to: " << Index;
if (*(I + NumToSkip) == MCD::OPC_Fail)
OS << " (Fail)";
};
while (I != E) {
assert(I < E && "incomplete decode table entry!");
@ -873,7 +895,8 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
const uint8_t DecoderOp = *I++;
switch (DecoderOp) {
default:
PrintFatalError("Invalid decode table opcode: " + Twine(DecoderOp));
PrintFatalError("Invalid decode table opcode: " + Twine((int)DecoderOp) +
" at index " + Twine(Pos));
case MCD::OPC_ExtractField: {
OS << Indent << "MCD::OPC_ExtractField, ";
@ -890,17 +913,24 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
OS << Start << "} ...\n";
break;
}
case MCD::OPC_FilterValue: {
OS << Indent << "MCD::OPC_FilterValue, ";
case MCD::OPC_FilterValue:
case MCD::OPC_FilterValueOrFail: {
bool IsFail = DecoderOp == MCD::OPC_FilterValueOrFail;
OS << Indent << "MCD::OPC_FilterValue" << (IsFail ? "OrFail, " : ", ");
// The filter value is ULEB128 encoded.
emitULEB128(I, OS);
if (!IsFail) {
uint32_t NumToSkip = emitNumToSkip(I, OS);
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
emitNumToSkipComment(NumToSkip);
}
OS << '\n';
break;
}
case MCD::OPC_CheckField: {
OS << Indent << "MCD::OPC_CheckField, ";
case MCD::OPC_CheckField:
case MCD::OPC_CheckFieldOrFail: {
bool IsFail = DecoderOp == MCD::OPC_CheckFieldOrFail;
OS << Indent << "MCD::OPC_CheckField" << (IsFail ? "OrFail, " : ", ");
// ULEB128 encoded start value.
emitULEB128(I, OS);
// 8-bit length.
@ -909,27 +939,39 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
// ULEB128 encoded field value.
emitULEB128(I, OS);
if (!IsFail) {
uint32_t NumToSkip = emitNumToSkip(I, OS);
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
emitNumToSkipComment(NumToSkip);
}
OS << '\n';
break;
}
case MCD::OPC_CheckPredicate: {
OS << Indent << "MCD::OPC_CheckPredicate, ";
case MCD::OPC_CheckPredicate:
case MCD::OPC_CheckPredicateOrFail: {
bool IsFail = DecoderOp == MCD::OPC_CheckPredicateOrFail;
OS << Indent << "MCD::OPC_CheckPredicate" << (IsFail ? "OrFail, " : ", ");
emitULEB128(I, OS);
if (!IsFail) {
uint32_t NumToSkip = emitNumToSkip(I, OS);
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
emitNumToSkipComment(NumToSkip);
}
OS << '\n';
break;
}
case MCD::OPC_Decode:
case MCD::OPC_TryDecode: {
bool IsTry = DecoderOp == MCD::OPC_TryDecode;
case MCD::OPC_TryDecode:
case MCD::OPC_TryDecodeOrFail: {
bool IsFail = DecoderOp == MCD::OPC_TryDecodeOrFail;
bool IsTry = DecoderOp == MCD::OPC_TryDecode || IsFail;
// Decode the Opcode value.
const char *ErrMsg = nullptr;
unsigned Opc = decodeULEB128(&*I, nullptr, EndPtr, &ErrMsg);
assert(ErrMsg == nullptr && "ULEB128 value too large!");
OS << Indent << "MCD::OPC_" << (IsTry ? "Try" : "") << "Decode, ";
OS << Indent << "MCD::OPC_" << (IsTry ? "Try" : "") << "Decode"
<< (IsFail ? "OrFail, " : ", ");
emitULEB128(I, OS);
// Decoder index.
@ -946,10 +988,14 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
// Fallthrough for OPC_TryDecode.
if (!IsFail) {
uint32_t NumToSkip = emitNumToSkip(I, OS);
OS << "// Opcode: " << NumberedEncodings[EncodingID]
<< ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
OS << "// Opcode: " << NumberedEncodings[EncodingID];
emitNumToSkipComment(NumToSkip, /*InComment=*/true);
} else {
OS << "// Opcode: " << NumberedEncodings[EncodingID];
}
OS << '\n';
break;
}
case MCD::OPC_SoftFail: {
@ -971,12 +1017,11 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
OS << '\n';
break;
}
case MCD::OPC_Fail: {
case MCD::OPC_Fail:
OS << Indent << "MCD::OPC_Fail,\n";
break;
}
}
}
OS << Indent << "0\n";
Indent -= 2;
@ -1337,12 +1382,17 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo,
// computed.
unsigned PIdx = getPredicateIndex(TableInfo, PS.str());
TableInfo.Table.push_back(MCD::OPC_CheckPredicate);
const uint8_t DecoderOp = TableInfo.isOutermostScope()
? MCD::OPC_CheckPredicateOrFail
: MCD::OPC_CheckPredicate;
TableInfo.Table.push_back(DecoderOp);
TableInfo.Table.insertULEB128(PIdx);
if (DecoderOp == MCD::OPC_CheckPredicate) {
// Push location for NumToSkip backpatching.
TableInfo.FixupStack.back().push_back(TableInfo.Table.insertNumToSkip());
}
}
void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo,
unsigned Opc) const {
@ -1411,18 +1461,23 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
for (const Island &Ilnd : reverse(Islands)) {
unsigned NumBits = Ilnd.NumBits;
assert(isUInt<8>(NumBits) && "NumBits overflowed uint8 table entry!");
TableInfo.Table.push_back(MCD::OPC_CheckField);
const uint8_t DecoderOp = TableInfo.isOutermostScope()
? MCD::OPC_CheckFieldOrFail
: MCD::OPC_CheckField;
TableInfo.Table.push_back(DecoderOp);
TableInfo.Table.insertULEB128(Ilnd.StartBit);
TableInfo.Table.push_back(NumBits);
TableInfo.Table.insertULEB128(Ilnd.FieldVal);
if (DecoderOp == MCD::OPC_CheckField) {
// Allocate space in the table for fixup so all our relative position
// calculations work OK even before we fully resolve the real value here.
// Push location for NumToSkip backpatching.
TableInfo.FixupStack.back().push_back(TableInfo.Table.insertNumToSkip());
}
}
// Check for soft failure of the match.
emitSoftFailTableEntry(TableInfo, Opc.EncodingID);
@ -1439,13 +1494,16 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
// decoder method indicates that additional processing should be done to see
// if there is any other instruction that also matches the bitpattern and
// can decode it.
TableInfo.Table.push_back(HasCompleteDecoder ? MCD::OPC_Decode
const uint8_t DecoderOp = HasCompleteDecoder ? MCD::OPC_Decode
: (TableInfo.isOutermostScope()
? MCD::OPC_TryDecodeOrFail
: MCD::OPC_TryDecode);
TableInfo.Table.push_back(DecoderOp);
NumEncodingsSupported++;
TableInfo.Table.insertULEB128(Opc.Opcode);
TableInfo.Table.insertULEB128(DIdx);
if (!HasCompleteDecoder) {
if (DecoderOp == MCD::OPC_TryDecode) {
// Push location for NumToSkip backpatching.
TableInfo.FixupStack.back().push_back(TableInfo.Table.insertNumToSkip());
}
@ -2188,7 +2246,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
DecodeStatus S = MCDisassembler::Success;
while (true) {
ptrdiff_t Loc = Ptr - DecodeTable;
switch (*Ptr++) {
const uint8_t DecoderOp = *Ptr++;
switch (DecoderOp) {
default:
errs() << Loc << ": Unexpected decode table opcode!\n";
return MCDisassembler::Fail;
@ -2204,22 +2263,34 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
<< Len << "): " << CurFieldValue << "\n");
break;
}
case MCD::OPC_FilterValue: {
case MCD::OPC_FilterValue:
case MCD::OPC_FilterValueOrFail: {
bool IsFail = DecoderOp == MCD::OPC_FilterValueOrFail;
// Decode the field value.
uint64_t Val = decodeULEB128AndIncUnsafe(Ptr);
bool Failed = Val != CurFieldValue;
unsigned NumToSkip = decodeNumToSkip(Ptr);
unsigned NumToSkip = IsFail ? 0 : decodeNumToSkip(Ptr);
// Note: Print NumToSkip even for OPC_FilterValueOrFail to simplify debug
// prints.
LLVM_DEBUG({
StringRef OpName = IsFail ? "OPC_FilterValueOrFail" : "OPC_FilterValue";
dbgs() << Loc << ": " << OpName << '(' << Val << ", " << NumToSkip
<< ") " << (Failed ? "FAIL:" : "PASS:")
<< " continuing at " << (Ptr - DecodeTable) << '\n';
});
// Perform the filter operation.
if (Failed)
if (Failed) {
if (IsFail)
return MCDisassembler::Fail;
Ptr += NumToSkip;
LLVM_DEBUG(dbgs() << Loc << ": OPC_FilterValue(" << Val << ", " << NumToSkip
<< "): " << (Failed ? "FAIL:" : "PASS:")
<< " continuing at " << (Ptr - DecodeTable) << "\n");
}
break;
}
case MCD::OPC_CheckField: {
case MCD::OPC_CheckField:
case MCD::OPC_CheckFieldOrFail: {
bool IsFail = DecoderOp == MCD::OPC_CheckFieldOrFail;
// Decode the start value.
unsigned Start = decodeULEB128AndIncUnsafe(Ptr);
unsigned Len = *Ptr;)";
@ -2232,29 +2303,44 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);
Ptr += PtrLen;
bool Failed = ExpectedValue != FieldValue;
unsigned NumToSkip = decodeNumToSkip(Ptr);
unsigned NumToSkip = IsFail ? 0 : decodeNumToSkip(Ptr);
// If the actual and expected values don't match, skip.
if (Failed)
LLVM_DEBUG({
StringRef OpName = IsFail ? "OPC_CheckFieldOrFail" : "OPC_CheckField";
dbgs() << Loc << ": " << OpName << '(' << Start << ", " << Len << ", "
<< ExpectedValue << ", " << NumToSkip << "): FieldValue = "
<< FieldValue << ", ExpectedValue = " << ExpectedValue << ": "
<< (Failed ? "FAIL\n" : "PASS\n");
});
// If the actual and expected values don't match, skip or fail.
if (Failed) {
if (IsFail)
return MCDisassembler::Fail;
Ptr += NumToSkip;
LLVM_DEBUG(dbgs() << Loc << ": OPC_CheckField(" << Start << ", "
<< Len << ", " << ExpectedValue << ", " << NumToSkip
<< "): FieldValue = " << FieldValue << ", ExpectedValue = "
<< ExpectedValue << ": "
<< (Failed ? "FAIL\n" : "PASS\n"));
}
break;
}
case MCD::OPC_CheckPredicate: {
case MCD::OPC_CheckPredicate:
case MCD::OPC_CheckPredicateOrFail: {
bool IsFail = DecoderOp == MCD::OPC_CheckPredicateOrFail;
// Decode the Predicate Index value.
unsigned PIdx = decodeULEB128AndIncUnsafe(Ptr);
unsigned NumToSkip = decodeNumToSkip(Ptr);
unsigned NumToSkip = IsFail ? 0 : decodeNumToSkip(Ptr);
// Check the predicate.
bool Failed = !checkDecoderPredicate(PIdx, Bits);
if (Failed)
Ptr += NumToSkip;
LLVM_DEBUG(dbgs() << Loc << ": OPC_CheckPredicate(" << PIdx << "): "
<< (Failed ? "FAIL\n" : "PASS\n"));
LLVM_DEBUG({
StringRef OpName = IsFail ? "OPC_CheckPredicateOrFail" : "OPC_CheckPredicate";
dbgs() << Loc << ": " << OpName << '(' << PIdx << ", " << NumToSkip
<< "): " << (Failed ? "FAIL\n" : "PASS\n");
});
if (Failed) {
if (IsFail)
return MCDisassembler::Fail;
Ptr += NumToSkip;
}
break;
}
case MCD::OPC_Decode: {
@ -2275,14 +2361,16 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
LLVM_DEBUG(dbgs() << Loc << ": OPC_Decode: opcode " << Opc
<< ", using decoder " << DecodeIdx << ": "
<< (S != MCDisassembler::Fail ? "PASS" : "FAIL") << "\n");
<< (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
return S;
}
case MCD::OPC_TryDecode: {
case MCD::OPC_TryDecode:
case MCD::OPC_TryDecodeOrFail: {
bool IsFail = DecoderOp == MCD::OPC_TryDecodeOrFail;
// Decode the Opcode value.
unsigned Opc = decodeULEB128AndIncUnsafe(Ptr);
unsigned DecodeIdx = decodeULEB128AndIncUnsafe(Ptr);
unsigned NumToSkip = decodeNumToSkip(Ptr);
unsigned NumToSkip = IsFail ? 0 : decodeNumToSkip(Ptr);
// Perform the decode operation.
MCInst TmpMI;
@ -2294,28 +2382,31 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
if (DecodeComplete) {
// Decoding complete.
LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS" : "FAIL") << "\n");
LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
MI = TmpMI;
return S;
} else {
}
assert(S == MCDisassembler::Fail);
if (IsFail) {
LLVM_DEBUG(dbgs() << "FAIL: returning FAIL\n");
return MCDisassembler::Fail;
}
// If the decoding was incomplete, skip.
Ptr += NumToSkip;
LLVM_DEBUG(dbgs() << "FAIL: continuing at " << (Ptr - DecodeTable) << "\n");
// Reset decode status. This also drops a SoftFail status that could be
// set before the decode attempt.
S = MCDisassembler::Success;
}
break;
}
case MCD::OPC_SoftFail: {
// Decode the mask values.
uint64_t PositiveMask = decodeULEB128AndIncUnsafe(Ptr);
uint64_t NegativeMask = decodeULEB128AndIncUnsafe(Ptr);
bool Fail = (insn & PositiveMask) != 0 || (~insn & NegativeMask) != 0;
if (Fail)
bool Failed = (insn & PositiveMask) != 0 || (~insn & NegativeMask) != 0;
if (Failed)
S = MCDisassembler::SoftFail;
LLVM_DEBUG(dbgs() << Loc << ": OPC_SoftFail: " << (Fail ? "FAIL\n" : "PASS\n"));
LLVM_DEBUG(dbgs() << Loc << ": OPC_SoftFail: " << (Failed ? "FAIL\n" : "PASS\n"));
break;
}
case MCD::OPC_Fail: {

View File

@ -2116,7 +2116,6 @@ llvm_target_lib_list = [lib for lib in [
"lib/Target/AArch64/AArch64GenSubtargetInfo.inc": ["-gen-subtarget"],
"lib/Target/AArch64/AArch64GenDisassemblerTables.inc": [
"-gen-disassembler",
"--large-decoder-table",
],
"lib/Target/AArch64/AArch64GenSystemOperands.inc": ["-gen-searchable-tables"],
"lib/Target/AArch64/AArch64GenExegesis.inc": ["-gen-exegesis"],