diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 72d1e77eb0..4d14c1ca24 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1001,7 +1001,10 @@ void helper_fscale(CPUX86State *env) } } else { int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); + signed char save = env->fp_status.floatx80_rounding_precision; + env->fp_status.floatx80_rounding_precision = 80; ST0 = floatx80_scalbn(ST0, n, &env->fp_status); + env->fp_status.floatx80_rounding_precision = save; } } diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c index b953e7c563..d23b3cfeec 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; }