[RISCV] Correctly Decode Unsigned Immediates with Ranges (#128584)

We currently have two operands upstream that are an unsigned immediate
with a range constraint - `uimm8ge32` (for `cm.jalt`) and `uimm5gt3`
(for `qc.shladd`).

Both of these were using `decodeUImmOperand<N>` for decoding. For `Zcmt`
this worked, because the generated decoder automatically checked for
`cm.jt` first because the 8 undefined bits in `cm.jalt` are `000?????`
in `cm.jt` (this is to do with the range lower-bound being a
power-of-two). For Zcmt, this patch is NFC.

We have less luck with `Xqciac` - `qc.shladd` is being decoded where the
`uimm5` field is 3 or lower. This patch fixes this by introducing a
`decodeUImmOperandGE<Width, LowerBound>` helper, which will corretly
return `MCDisassembler::Fail` when the immediate is below the lower
bound.

I have added a test to show the encoding where `uimm5` is equal to 3 is
no longer disassembled as `qc.shladd`.
This commit is contained in:
Sam Elliott 2025-02-25 11:12:08 -08:00 committed by GitHub
parent 9102afcd01
commit c8136da26c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 25 additions and 2 deletions

View File

@ -328,6 +328,19 @@ static DecodeStatus decodeUImmOperand(MCInst &Inst, uint32_t Imm,
return MCDisassembler::Success;
}
template <unsigned Width, unsigned LowerBound>
static DecodeStatus decodeUImmOperandGE(MCInst &Inst, uint32_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {
assert(isUInt<Width>(Imm) && "Invalid immediate");
if (Imm < LowerBound)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createImm(Imm));
return MCDisassembler::Success;
}
static DecodeStatus decodeUImmLog2XLenOperand(MCInst &Inst, uint32_t Imm,
int64_t Address,
const MCDisassembler *Decoder) {

View File

@ -24,7 +24,7 @@ def uimm5nonzero : RISCVOp<XLenVT>,
def uimm5gt3 : RISCVOp<XLenVT>, ImmLeaf<XLenVT,
[{return (Imm > 3) && isUInt<5>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<5, "GT3">;
let DecoderMethod = "decodeUImmOperand<5>";
let DecoderMethod = "decodeUImmOperandGE<5, 4>";
let OperandType = "OPERAND_UIMM5_GT3";
}

View File

@ -31,7 +31,7 @@ def uimm2_lsb0 : RISCVOp,
def uimm8ge32 : RISCVOp {
let ParserMatchClass = UImmAsmOperand<8, "GE32">;
let DecoderMethod = "decodeUImmOperand<8>";
let DecoderMethod = "decodeUImmOperandGE<8, 32>";
let OperandType = "OPERAND_UIMM8_GE32";
}

View File

@ -0,0 +1,10 @@
# RUN: not llvm-mc -disassemble -triple=riscv32 -mattr=+experimental-xqciac %s | FileCheck %s
[0x00,0x00]
# CHECK: unimp
[0x8b,0x30,0x31,0x46]
# CHECK-NOT: qc.shladd x1, x2, x3, {{[0-9]+}}
[0x00,0x00]
# CHECK: unimp