From f8dbd4f0171805dd90cf5b1c05dedf56665a43e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Wed, 7 Oct 2026 13:18:58 +0200 Subject: [PATCH] fix(asm): lower the riscv64 immediate CSR pseudos onto their opcode forms Assisted-by: GLM 5.3 --- asm/riscv_assemble.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/asm/riscv_assemble.go b/asm/riscv_assemble.go index f95b3db..d073e68 100644 --- a/asm/riscv_assemble.go +++ b/asm/riscv_assemble.go @@ -1532,6 +1532,21 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv csrOp, srcOp = ops[1], ops[0] } rdOp = nil + // The toolchain picks the opcode form from the source's kind: + // CSRW $2, csr assembles as CSRRWI exactly as CSRWI does, and + // the register spellings stay on CSRRW. + if isImmOperand(srcOp) { + csrMnem = map[string]string{ + "CSRS": "CSRRSI", "CSRW": "CSRRWI", "CSRC": "CSRRCI", + "CSRSI": "CSRRSI", "CSRWI": "CSRRWI", "CSRCI": "CSRRCI", + }[mnem] + } else { + csrMnem = map[string]string{ + "CSRS": "CSRRS", "CSRW": "CSRRW", "CSRC": "CSRRC", + "CSRSI": "CSRRSI", "CSRWI": "CSRRWI", "CSRCI": "CSRRCI", + }[mnem] + } + csrEnc = riscvCsrTable[csrMnem] default: // Either src, csr, rd or csr, src, rd: a CSR *name* in the // second operand marks the toolchain's order. @@ -1541,6 +1556,17 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv csrOp, srcOp = ops[1], ops[0] } } + // An immediate source selects the immediate opcode (CSRRW $2, + // c, rd encodes CSRRWI, byte-identical to the explicit form), + // mirroring the toolchain's constant rewrite. + if isImmOperand(srcOp) { + csrMnem = map[string]string{ + "CSRRW": "CSRRWI", "CSRRS": "CSRRSI", "CSRRC": "CSRRCI", + }[csrMnem] + if csrMnem != "" { + csrEnc = riscvCsrTable[csrMnem] + } + } } csr, ok := riscvCSRAddress(csrOp) if !ok && csrFix == 0 {