From c535d68755576bfa33be7aef7bd294a601f776e0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 7 May 2020 00:46:28 +0000 Subject: target/i386: fix fscale handling of rounding precision The fscale implementation uses floatx80_scalbn for the final scaling operation. floatx80_scalbn ends up rounding the result using the dynamic rounding precision configured for the FPU. But only a limited set of x87 floating-point instructions are supposed to respect the dynamic rounding precision, and fscale is not in that set. Fix the implementation to save and restore the rounding precision around the call to floatx80_scalbn. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- tests/tcg/i386/test-i386-fscale.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tests/tcg/i386/test-i386-fscale.c') diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c index b953e7c..d23b3cf 100644 --- a/tests/tcg/i386/test-i386-fscale.c +++ b/tests/tcg/i386/test-i386-fscale.c @@ -8,6 +8,8 @@ union u { long double ld; }; +volatile long double ld_third = 1.0L / 3.0L; +volatile long double ld_four_thirds = 4.0L / 3.0L; volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; @@ -91,5 +93,16 @@ int main(void) printf("FAIL: fscale finite down inf\n"); ret = 1; } + /* Set round-to-nearest with single-precision rounding. */ + cw = cw & ~0xf00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (ld_third), "u" (2.0L)); + cw = cw | 0x300; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + if (ld_res != ld_four_thirds) { + printf("FAIL: fscale single-precision\n"); + ret = 1; + } return ret; } -- cgit v1.1