Skip to content

Commit 45d6613

Browse files
ita-scMark Wielaard
authored andcommitted
riscv64: Fix nan-boxing for single-precision calculations
For float values, for arithmetics we expect to have canonical nan if used double register is not currectly nan-boxed. https://bugs.kde.org/show_bug.cgi?id=503098 (cherry picked from commit 9dd24c9)
1 parent 02de597 commit 45d6613

4 files changed

Lines changed: 31 additions & 7 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Branch 3.25
55

66
The following bugs have been fixed or resolved on this branch.
77

8+
503098 Incorrect NAN-boxing for float registers in RISC-V
89
503641 close_range syscalls started failing with 3.25.0
910
503914 mount syscall param filesystemtype may be NULL
1011
504177 FILE DESCRIPTORS banner shows when closing some inherited fds

VEX/priv/guest_riscv64_toIR.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

none/tests/riscv64/float32.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,12 @@ static void test_float32_additions(void)
15781578
TESTINST_1_1_FI(4, "fcvt.s.lu fa0, a0", 0x0000000001000001, 0x60, fa0, a0);
15791579
/* 2**24+1 (DYN-RMM) -> 2**24+2 (NX) */
15801580
TESTINST_1_1_FI(4, "fcvt.s.lu fa0, a0", 0x0000000001000001, 0x80, fa0, a0);
1581+
1582+
// check nan-boxing
1583+
/* fabs.s rd, rs1 */
1584+
TESTINST_1_2_F(4, "fsgnjx.s fa0, fa1, fa1", 0xfaffffff3f800000,
1585+
0xfaffffff3f800000, 0x00, fa0, fa1, fa1);
1586+
15811587
}
15821588

15831589
int main(void)

none/tests/riscv64/float32.stdout.exp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,3 +1554,6 @@ fcvt.s.lu fa0, a0 ::
15541554
fcvt.s.lu fa0, a0 ::
15551555
inputs: a0=0x0000000001000001, fcsr=0x00000080
15561556
output: fa0=0xffffffff4b800001, fcsr=0x00000081
1557+
fsgnjx.s fa0, fa1, fa1 ::
1558+
inputs: fa1=0xfaffffff3f800000, fa1=0xfaffffff3f800000, fcsr=0x00000000
1559+
output: fa0=0xffffffff7fc00000, fcsr=0x00000000

0 commit comments

Comments
 (0)