@@ -522,9 +522,13 @@ static IRExpr* getFReg32(UInt fregNo)
522522 vassert (fregNo < 32 );
523523 /* Note that the following access depends on the host being little-endian
524524 which is checked in disInstr_RISCV64(). */
525- /* TODO Check that the value is correctly NaN-boxed. If not then return
526- the 32-bit canonical qNaN, as mandated by the RISC-V ISA. */
527- return IRExpr_Get (offsetFReg (fregNo ), Ity_F32 );
525+ IRExpr * f64 = getFReg64 (fregNo );
526+ IRExpr * high_half = unop (Iop_64HIto32 , unop (Iop_ReinterpF64asI64 , f64 ));
527+ IRExpr * cond = binop (Iop_CmpEQ32 , high_half , mkU32 (0xffffffff ));
528+ IRExpr * res = IRExpr_ITE (
529+ cond , IRExpr_Get (offsetFReg (fregNo ), Ity_F32 ),
530+ /* canonical nan */ unop (Iop_ReinterpI32asF32 , mkU32 (0x7fc00000 )));
531+ return res ;
528532}
529533
530534/* Write a 32-bit value into a guest floating-point register. */
@@ -2162,8 +2166,10 @@ static Bool dis_RV64F(/*MB_OUT*/ DisResult* dres,
21622166 UInt rs2 = INSN (24 , 20 );
21632167 UInt imm11_0 = INSN (31 , 25 ) << 5 | INSN (11 , 7 );
21642168 ULong simm = vex_sx_to_64 (imm11_0 , 12 );
2165- storeLE (irsb , binop (Iop_Add64 , getIReg64 (rs1 ), mkU64 (simm )),
2166- getFReg32 (rs2 ));
2169+ // do not modify the bits being transferred;
2170+ IRExpr * f64 = getFReg64 (rs2 );
2171+ IRExpr * i32 = unop (Iop_64to32 , unop (Iop_ReinterpF64asI64 , f64 ));
2172+ storeLE (irsb , binop (Iop_Add64 , getIReg64 (rs1 ), mkU64 (simm )), i32 );
21672173 DIP ("fsw %s, %lld(%s)\n" , nameFReg (rs2 ), (Long )simm , nameIReg (rs1 ));
21682174 return True ;
21692175 }
@@ -2458,8 +2464,16 @@ static Bool dis_RV64F(/*MB_OUT*/ DisResult* dres,
24582464 INSN (24 , 20 ) == 0b00000 && INSN (31 , 25 ) == 0b1110000 ) {
24592465 UInt rd = INSN (11 , 7 );
24602466 UInt rs1 = INSN (19 , 15 );
2461- if (rd != 0 )
2462- putIReg32 (irsb , rd , unop (Iop_ReinterpF32asI32 , getFReg32 (rs1 )));
2467+ if (rd != 0 ) {
2468+ // For RV64, the higher 32 bits of the destination register are filled
2469+ // with copies of the floating-point number’s sign bit.
2470+ IRExpr * freg = getFReg64 (rs1 );
2471+ IRExpr * low_half = unop (Iop_64to32 , unop (Iop_ReinterpF64asI64 , freg ));
2472+ IRExpr * sign = binop (Iop_And32 , low_half , mkU32 (1u << 31 ));
2473+ IRExpr * cond = binop (Iop_CmpEQ32 , sign , mkU32 (1u << 31 ));
2474+ IRExpr * high_part = IRExpr_ITE (cond , mkU32 (0xffffffff ), mkU32 (0 ));
2475+ putIReg64 (irsb , rd , binop (Iop_32HLto64 , high_part , low_half ));
2476+ }
24632477 DIP ("fmv.x.w %s, %s\n" , nameIReg (rd ), nameFReg (rs1 ));
24642478 return True ;
24652479 }
0 commit comments