[llvm] [TableGen][DecoderEmitter] Add option to emit type-specialized code (PR #146593)
Rahul Joshi via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 20 13:32:13 PDT 2025
jurahul wrote:
Here's what the code looks like with a single impl function:
```
static DecodeStatus decodeInstructionImpl(const uint8_t DecodeTable[], MCInst &MI, const std::bitset<128> &Insn, uint64_t Address, const MCDisassembler *DisAsm, const MCSubtargetInfo &STI, function_ref<DecodeStatus(unsigned, DecodeStatus, MCInst &, uint64_t, const MCDisassembler *, bool &)> decodeToMCInstPtr) {
const FeatureBitset &Bits = STI.getFeatureBits();
const uint8_t *Ptr = DecodeTable;
uint64_t CurFieldValue = 0;
DecodeStatus S = MCDisassembler::Success;
while (true) {
ptrdiff_t Loc = Ptr - DecodeTable;
const uint8_t DecoderOp = *Ptr++;
switch (DecoderOp) {
default:
errs() << Loc << ": Unexpected decode table opcode: "
<< (int)DecoderOp << '\n';
return MCDisassembler::Fail;
case MCD::OPC_ExtractField: {
...
case MCD::OPC_Decode: {
// Decode the Opcode value.
unsigned Opc = decodeULEB128AndIncUnsafe(Ptr);
unsigned DecodeIdx = decodeULEB128AndIncUnsafe(Ptr);
MI.clear();
MI.setOpcode(Opc);
bool DecodeComplete;
S = decodeToMCInstPtr(DecodeIdx, S, MI, Address, DisAsm, DecodeComplete);
...
}
static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
uint32_t Insn, uint64_t Address, const MCDisassembler *DisAsm,
const MCSubtargetInfo &STI) {
std::bitset<128> InsnMaxWidth = Insn;
auto DecodeToMCInst = [Insn](unsigned DecodeIdx, DecodeStatus S, MCInst &MI,
uint64_t Address, const MCDisassembler *DisAsm,
bool &DecodeComplete) {
return decodeToMCInst32(DecodeIdx, S, Insn, MI, Address, DisAsm, DecodeComplete);
};
return decodeInstructionImpl(DecodeTable, MI, InsnMaxWidth, Address, DisAsm, STI, DecodeToMCInst);
}
static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
uint64_t Insn, uint64_t Address, const MCDisassembler *DisAsm,
const MCSubtargetInfo &STI) {
std::bitset<128> InsnMaxWidth = Insn;
auto DecodeToMCInst = [Insn](unsigned DecodeIdx, DecodeStatus S, MCInst &MI,
uint64_t Address, const MCDisassembler *DisAsm,
bool &DecodeComplete) {
return decodeToMCInst64(DecodeIdx, S, Insn, MI, Address, DisAsm, DecodeComplete);
};
return decodeInstructionImpl(DecodeTable, MI, InsnMaxWidth, Address, DisAsm, STI, DecodeToMCInst);
}
static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
const std::bitset<96> &Insn, uint64_t Address, const MCDisassembler *DisAsm,
const MCSubtargetInfo &STI) {
const std::bitset<96> Mask(maskTrailingOnes<uint64_t>(64));
std::bitset<128> InsnMaxWidth((Insn & Mask).to_ullong());
InsnMaxWidth |= std::bitset<128>(((Insn >> 64) & Mask).to_ullong()) << 64;
auto DecodeToMCInst = [&Insn](unsigned DecodeIdx, DecodeStatus S, MCInst &MI,
uint64_t Address, const MCDisassembler *DisAsm,
bool &DecodeComplete) {
return decodeToMCInst96(DecodeIdx, S, Insn, MI, Address, DisAsm, DecodeComplete);
};
return decodeInstructionImpl(DecodeTable, MI, InsnMaxWidth, Address, DisAsm, STI, DecodeToMCInst);
}
static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
const std::bitset<128> &Insn, uint64_t Address, const MCDisassembler *DisAsm,
const MCSubtargetInfo &STI) {
std::bitset<128> InsnMaxWidth = Insn;
auto DecodeToMCInst = [&Insn](unsigned DecodeIdx, DecodeStatus S, MCInst &MI,
uint64_t Address, const MCDisassembler *DisAsm,
bool &DecodeComplete) {
return decodeToMCInst128(DecodeIdx, S, Insn, MI, Address, DisAsm, DecodeComplete);
};
return decodeInstructionImpl(DecodeTable, MI, InsnMaxWidth, Address, DisAsm, STI, DecodeToMCInst);
}
```
So each bit-width specific `decodeInstruction` up-converts the inst bits to max-width and then calls `decodeInstructionImpl`. In the final decode step (handling of OPC_Decode, we call the passed in lambda, so that code still operates on the native smaller instruction woidth).
https://github.com/llvm/llvm-project/pull/146593
More information about the llvm-commits
mailing list