Skip to content

Commit c8af85b

Browse files
jsm28bonzini
authored andcommitted
target/i386: fix fisttpl, fisttpll handling of out-of-range values
The fist / fistt family of instructions should all store the most negative integer in the destination format when the rounded / truncated integer result is out of range or the input is an invalid encoding, infinity or NaN. The fisttpl and fisttpll implementations (32-bit and 64-bit results, truncate towards zero) failed to do this, producing the most positive integer in some cases instead. Fix this by copying the code used to handle this issue for fistpl and fistpll, adjusted to use the _round_to_zero functions for the actual conversion (but without any other changes to that code). Signed-off-by: Joseph Myers <joseph@codesourcery.com> Message-Id: <alpine.DEB.2.21.2005152119160.3469@digraph.polyomino.org.uk> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 374ff4d commit c8af85b

File tree

2 files changed

+126
-2
lines changed

2 files changed

+126
-2
lines changed

target/i386/fpu_helper.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,36 @@ int32_t helper_fistt_ST0(CPUX86State *env)
338338

339339
int32_t helper_fisttl_ST0(CPUX86State *env)
340340
{
341-
return floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
341+
int32_t val;
342+
signed char old_exp_flags;
343+
344+
old_exp_flags = get_float_exception_flags(&env->fp_status);
345+
set_float_exception_flags(0, &env->fp_status);
346+
347+
val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
348+
if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
349+
val = 0x80000000;
350+
}
351+
set_float_exception_flags(get_float_exception_flags(&env->fp_status)
352+
| old_exp_flags, &env->fp_status);
353+
return val;
342354
}
343355

344356
int64_t helper_fisttll_ST0(CPUX86State *env)
345357
{
346-
return floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
358+
int64_t val;
359+
signed char old_exp_flags;
360+
361+
old_exp_flags = get_float_exception_flags(&env->fp_status);
362+
set_float_exception_flags(0, &env->fp_status);
363+
364+
val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
365+
if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
366+
val = 0x8000000000000000ULL;
367+
}
368+
set_float_exception_flags(get_float_exception_flags(&env->fp_status)
369+
| old_exp_flags, &env->fp_status);
370+
return val;
347371
}
348372

349373
void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)

tests/tcg/i386/test-i386-fisttp.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* Test fisttpl and fisttpll instructions. */
2+
3+
#include <stdint.h>
4+
#include <stdio.h>
5+
#include <string.h>
6+
7+
union u {
8+
struct { uint64_t sig; uint16_t sign_exp; } s;
9+
long double ld;
10+
};
11+
12+
volatile union u ld_invalid_1 = { .s = { 1, 1234 } };
13+
14+
int main(void)
15+
{
16+
int ret = 0;
17+
int32_t res_32;
18+
int64_t res_64;
19+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (0x1p100L) : "st");
20+
if (res_32 != INT32_MIN) {
21+
printf("FAIL: fisttpl 0x1p100\n");
22+
ret = 1;
23+
}
24+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-0x1p100L) : "st");
25+
if (res_32 != INT32_MIN) {
26+
printf("FAIL: fisttpl -0x1p100\n");
27+
ret = 1;
28+
}
29+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (__builtin_infl()) :
30+
"st");
31+
if (res_32 != INT32_MIN) {
32+
printf("FAIL: fisttpl inf\n");
33+
ret = 1;
34+
}
35+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-__builtin_infl()) :
36+
"st");
37+
if (res_32 != INT32_MIN) {
38+
printf("FAIL: fisttpl -inf\n");
39+
ret = 1;
40+
}
41+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (__builtin_nanl("")) :
42+
"st");
43+
if (res_32 != INT32_MIN) {
44+
printf("FAIL: fisttpl nan\n");
45+
ret = 1;
46+
}
47+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) :
48+
"t" (-__builtin_nanl("")) : "st");
49+
if (res_32 != INT32_MIN) {
50+
printf("FAIL: fisttpl -nan\n");
51+
ret = 1;
52+
}
53+
__asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) :
54+
"st");
55+
if (res_32 != INT32_MIN) {
56+
printf("FAIL: fisttpl invalid\n");
57+
ret = 1;
58+
}
59+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (0x1p100L) : "st");
60+
if (res_64 != INT64_MIN) {
61+
printf("FAIL: fisttpll 0x1p100\n");
62+
ret = 1;
63+
}
64+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-0x1p100L) : "st");
65+
if (res_64 != INT64_MIN) {
66+
printf("FAIL: fisttpll -0x1p100\n");
67+
ret = 1;
68+
}
69+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (__builtin_infl()) :
70+
"st");
71+
if (res_64 != INT64_MIN) {
72+
printf("FAIL: fisttpll inf\n");
73+
ret = 1;
74+
}
75+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-__builtin_infl()) :
76+
"st");
77+
if (res_64 != INT64_MIN) {
78+
printf("FAIL: fisttpll -inf\n");
79+
ret = 1;
80+
}
81+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) :
82+
"t" (__builtin_nanl("")) : "st");
83+
if (res_64 != INT64_MIN) {
84+
printf("FAIL: fisttpll nan\n");
85+
ret = 1;
86+
}
87+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) :
88+
"t" (-__builtin_nanl("")) : "st");
89+
if (res_64 != INT64_MIN) {
90+
printf("FAIL: fisttpll -nan\n");
91+
ret = 1;
92+
}
93+
__asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) :
94+
"st");
95+
if (res_64 != INT64_MIN) {
96+
printf("FAIL: fisttpll invalid\n");
97+
ret = 1;
98+
}
99+
return ret;
100+
}

0 commit comments

Comments
 (0)