From f3d63f3c7ef636cba3fef175e75d00f47ffab9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 19 Sep 2026 13:21:35 -0600 Subject: [PATCH] RISC-V: mask the register number in the compressed encoders EncodeCR, EncodeCI and EncodeCSS shifted the RiscVReg enum value straight into the instruction without DecodeReg(), which every 32-bit encoder in the file uses. FPRs are 0x20..0x3F in that enum, so bit 5 is set for all of them and spilled into a neighbouring field - for the CI format, into bit 12, which holds imm[5]. The visible effect: the dispatcher's epilogue restores the callee-saved FP registers with c.fldsp, and every offset whose bit 5 was clear came out 32 bytes too high. fs3-fs6 were restored from the wrong slots and fs11 from 224(sp), past the 208-byte frame. So the native JIT corrupted whatever the C++ caller had in those registers - which, in the headless test runner, was the wall-clock deadline, making every test report an instant TIMEOUT. pspautotests on riscv64 under qemu goes from 0/342 to 338/342 with this, matching the IR interpreter exactly. Found with the disassembly the enableDisasm flag in RiscVAsm.cpp emits - the save offsets and the restore offsets simply didn't match. Co-Authored-By: Claude Opus 5 (1M context) --- Common/RiscVEmitter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/RiscVEmitter.cpp b/Common/RiscVEmitter.cpp index 17dda6ffed..8232eb1d51 100644 --- a/Common/RiscVEmitter.cpp +++ b/Common/RiscVEmitter.cpp @@ -842,7 +842,7 @@ static inline u32 EncodeFVF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm static inline u16 EncodeCR(Opcode16 op, RiscVReg rs2, RiscVReg rd, Funct4 funct4) { _assert_msg_(SupportsCompressed(), "Compressed instructions unsupported"); - return (u16)op | ((u16)rs2 << 2) | ((u16)rd << 7) | ((u16)funct4 << 12); + return (u16)op | ((u16)DecodeReg(rs2) << 2) | ((u16)DecodeReg(rd) << 7) | ((u16)funct4 << 12); } static inline u16 EncodeCI(Opcode16 op, u8 uimm6, RiscVReg rd, Funct3 funct3) { @@ -850,13 +850,13 @@ static inline u16 EncodeCI(Opcode16 op, u8 uimm6, RiscVReg rd, Funct3 funct3) { _assert_msg_(uimm6 <= 0x3F, "CI immediate overflow: %04x", uimm6); u16 imm4_0 = ImmBits16(uimm6, 0, 5); u16 imm5 = ImmBit16(uimm6, 5); - return (u16)op | (imm4_0 << 2) | ((u16)rd << 7) | (imm5 << 12) | ((u16)funct3 << 13); + return (u16)op | (imm4_0 << 2) | ((u16)DecodeReg(rd) << 7) | (imm5 << 12) | ((u16)funct3 << 13); } static inline u16 EncodeCSS(Opcode16 op, RiscVReg rs2, u8 uimm6, Funct3 funct3) { _assert_msg_(SupportsCompressed(), "Compressed instructions unsupported"); _assert_msg_(uimm6 <= 0x3F, "CI immediate overflow: %04x", uimm6); - return (u16)op | ((u16)rs2 << 2) | ((u16)uimm6 << 7) | ((u16)funct3 << 13); + return (u16)op | ((u16)DecodeReg(rs2) << 2) | ((u16)uimm6 << 7) | ((u16)funct3 << 13); } static inline u16 EncodeCIW(Opcode16 op, RiscCReg rd, u8 uimm8, Funct3 funct3) {