fix(asm): carry the riscv64 U-type immediate raw

The toolchain writes the source immediate straight into imm[31:12]
(riscv64.s: AUIPC 24287, X10 encodes 7ffff517), and rejects values
beyond the signed 20-bit span; the encoder divided by 4096 instead and
truncated silently, so the high bits of every large AUIPC and LUI were
lost.

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 02:12:21 +02:00
1 parent a829b8f321
commit 0cfed5516c
2 files changed
+36 -2

No files matched your search

+8 -2
View File
@@ -1751,7 +1751,10 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
// The Go assembler never compresses branches to C.BEQZ/C.BNEZ.
word = riscvBType(enc, rs1, rs2, offset)
// U-type: rd, imm (or the toolchain testdata's INSTR $imm, rd).
// U-type: rd, imm (or the toolchain testdata's INSTR $imm, rd). The
// immediate rides the field raw (riscv64.s: AUIPC $524287, X10 encodes
// 7ffff517), so it shifts into imm[31:12] here, and the span is the
// signed 20-bit range the toolchain checks.
case len(ops) == 2 && isUTypeInstr(mnem):
var rd int
var imm int32
@@ -1763,7 +1766,10 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
if rd < 0 {
return nil, fmt.Errorf("invalid register in %s", mnem)
}
word = riscvUType(enc, rd, imm)
if imm < -(1<<19) || imm > (1<<19)-1 {
return nil, fmt.Errorf("%s: signed immediate 0x%x must be in range [-0x80000, 0x7ffff] (20 bits)", mnem, imm)
}
word = riscvUType(enc, rd, imm<<12)
default:
return nil, fmt.Errorf("cannot encode %s with %d operands", mnem, len(ops))