Commit 8422b1133739343c1b35d0bba30c3209649e43e1

Authored by bellard
1 parent b7a100da

NaN support in FPU comparisons


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1341 c046a42c-6fe2-441c-8c8c-71466251a162
target-i386/exec.h
@@ -325,6 +325,8 @@ static inline void stfl(target_ulong ptr, float v) @@ -325,6 +325,8 @@ static inline void stfl(target_ulong ptr, float v)
325 #define floatx_abs floatx80_abs 325 #define floatx_abs floatx80_abs
326 #define floatx_chs floatx80_chs 326 #define floatx_chs floatx80_chs
327 #define floatx_round_to_int floatx80_round_to_int 327 #define floatx_round_to_int floatx80_round_to_int
  328 +#define floatx_compare floatx80_compare
  329 +#define floatx_compare_quiet floatx80_compare_quiet
328 #define sin sinl 330 #define sin sinl
329 #define cos cosl 331 #define cos cosl
330 #define sqrt sqrtl 332 #define sqrt sqrtl
@@ -340,6 +342,8 @@ static inline void stfl(target_ulong ptr, float v) @@ -340,6 +342,8 @@ static inline void stfl(target_ulong ptr, float v)
340 #define floatx_abs float64_abs 342 #define floatx_abs float64_abs
341 #define floatx_chs float64_chs 343 #define floatx_chs float64_chs
342 #define floatx_round_to_int float64_round_to_int 344 #define floatx_round_to_int float64_round_to_int
  345 +#define floatx_compare float64_compare
  346 +#define floatx_compare_quiet float64_compare_quiet
343 #endif 347 #endif
344 348
345 extern CPU86_LDouble sin(CPU86_LDouble x); 349 extern CPU86_LDouble sin(CPU86_LDouble x);
@@ -547,8 +551,6 @@ void restore_native_fp_state(CPUState *env); @@ -547,8 +551,6 @@ void restore_native_fp_state(CPUState *env);
547 void save_native_fp_state(CPUState *env); 551 void save_native_fp_state(CPUState *env);
548 float approx_rsqrt(float a); 552 float approx_rsqrt(float a);
549 float approx_rcp(float a); 553 float approx_rcp(float a);
550 -double helper_sqrt(double a);  
551 -int fpu_isnan(double a);  
552 void update_fp_status(void); 554 void update_fp_status(void);
553 555
554 extern const uint8_t parity_table[256]; 556 extern const uint8_t parity_table[256];
target-i386/helper.c
@@ -3223,12 +3223,6 @@ void helper_idivq_EAX_T0(void) @@ -3223,12 +3223,6 @@ void helper_idivq_EAX_T0(void)
3223 3223
3224 #endif 3224 #endif
3225 3225
3226 -/* XXX: do it */  
3227 -int fpu_isnan(double a)  
3228 -{  
3229 - return 0;  
3230 -}  
3231 -  
3232 float approx_rsqrt(float a) 3226 float approx_rsqrt(float a)
3233 { 3227 {
3234 return 1.0 / sqrt(a); 3228 return 1.0 / sqrt(a);
target-i386/op.c
@@ -1952,52 +1952,94 @@ void OPPROTO op_fxchg_ST0_STN(void) @@ -1952,52 +1952,94 @@ void OPPROTO op_fxchg_ST0_STN(void)
1952 1952
1953 /* FPU operations */ 1953 /* FPU operations */
1954 1954
1955 -/* XXX: handle nans */  
1956 void OPPROTO op_fcom_ST0_FT0(void) 1955 void OPPROTO op_fcom_ST0_FT0(void)
1957 { 1956 {
1958 - env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */  
1959 - if (ST0 < FT0)  
1960 - env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */  
1961 - else if (ST0 == FT0)  
1962 - env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ 1957 + int cc;
  1958 + switch(floatx_compare(ST0, FT0, &env->fp_status)) {
  1959 + case -1:
  1960 + cc = 0x0100;
  1961 + break;
  1962 + case 0:
  1963 + cc = 0x4000;
  1964 + break;
  1965 + case 1:
  1966 + cc = 0x0000;
  1967 + break;
  1968 + case 2:
  1969 + default:
  1970 + cc = 0x4500;
  1971 + break;
  1972 + }
  1973 + env->fpus = (env->fpus & ~0x4500) | cc;
1963 FORCE_RET(); 1974 FORCE_RET();
1964 } 1975 }
1965 1976
1966 -/* XXX: handle nans */  
1967 void OPPROTO op_fucom_ST0_FT0(void) 1977 void OPPROTO op_fucom_ST0_FT0(void)
1968 { 1978 {
1969 - env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */  
1970 - if (ST0 < FT0)  
1971 - env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */  
1972 - else if (ST0 == FT0)  
1973 - env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ 1979 + int cc;
  1980 + switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) {
  1981 + case -1:
  1982 + cc = 0x0100;
  1983 + break;
  1984 + case 0:
  1985 + cc = 0x4000;
  1986 + break;
  1987 + case 1:
  1988 + cc = 0x0000;
  1989 + break;
  1990 + case 2:
  1991 + default:
  1992 + cc = 0x4500;
  1993 + break;
  1994 + }
  1995 + env->fpus = (env->fpus & ~0x4500) | cc;
1974 FORCE_RET(); 1996 FORCE_RET();
1975 } 1997 }
1976 1998
1977 -/* XXX: handle nans */  
1978 void OPPROTO op_fcomi_ST0_FT0(void) 1999 void OPPROTO op_fcomi_ST0_FT0(void)
1979 { 2000 {
1980 - int eflags; 2001 + int eflags, cc;
  2002 + switch(floatx_compare(ST0, FT0, &env->fp_status)) {
  2003 + case -1:
  2004 + cc = CC_C;
  2005 + break;
  2006 + case 0:
  2007 + cc = CC_Z;
  2008 + break;
  2009 + case 1:
  2010 + cc = 0;
  2011 + break;
  2012 + case 2:
  2013 + default:
  2014 + cc = CC_Z | CC_P | CC_C;
  2015 + break;
  2016 + }
1981 eflags = cc_table[CC_OP].compute_all(); 2017 eflags = cc_table[CC_OP].compute_all();
1982 - eflags &= ~(CC_Z | CC_P | CC_C);  
1983 - if (ST0 < FT0)  
1984 - eflags |= CC_C;  
1985 - else if (ST0 == FT0)  
1986 - eflags |= CC_Z; 2018 + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc;
1987 CC_SRC = eflags; 2019 CC_SRC = eflags;
1988 FORCE_RET(); 2020 FORCE_RET();
1989 } 2021 }
1990 2022
1991 -/* XXX: handle nans */  
1992 void OPPROTO op_fucomi_ST0_FT0(void) 2023 void OPPROTO op_fucomi_ST0_FT0(void)
1993 { 2024 {
1994 - int eflags; 2025 + int eflags, cc;
  2026 + switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) {
  2027 + case -1:
  2028 + cc = CC_C;
  2029 + break;
  2030 + case 0:
  2031 + cc = CC_Z;
  2032 + break;
  2033 + case 1:
  2034 + cc = 0;
  2035 + break;
  2036 + case 2:
  2037 + default:
  2038 + cc = CC_Z | CC_P | CC_C;
  2039 + break;
  2040 + }
1995 eflags = cc_table[CC_OP].compute_all(); 2041 eflags = cc_table[CC_OP].compute_all();
1996 - eflags &= ~(CC_Z | CC_P | CC_C);  
1997 - if (ST0 < FT0)  
1998 - eflags |= CC_C;  
1999 - else if (ST0 == FT0)  
2000 - eflags |= CC_Z; 2042 + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc;
2001 CC_SRC = eflags; 2043 CC_SRC = eflags;
2002 FORCE_RET(); 2044 FORCE_RET();
2003 } 2045 }
target-i386/ops_sse.h
@@ -704,7 +704,7 @@ SSE_OP_S(sqrt, FPU_SQRT) @@ -704,7 +704,7 @@ SSE_OP_S(sqrt, FPU_SQRT)
704 /* float to float conversions */ 704 /* float to float conversions */
705 void OPPROTO op_cvtps2pd(void) 705 void OPPROTO op_cvtps2pd(void)
706 { 706 {
707 - float s0, s1; 707 + float32 s0, s1;
708 Reg *d, *s; 708 Reg *d, *s;
709 d = (Reg *)((char *)env + PARAM1); 709 d = (Reg *)((char *)env + PARAM1);
710 s = (Reg *)((char *)env + PARAM2); 710 s = (Reg *)((char *)env + PARAM2);
@@ -1031,10 +1031,10 @@ void OPPROTO op_ ## name ## ps (void)\ @@ -1031,10 +1031,10 @@ void OPPROTO op_ ## name ## ps (void)\
1031 Reg *d, *s;\ 1031 Reg *d, *s;\
1032 d = (Reg *)((char *)env + PARAM1);\ 1032 d = (Reg *)((char *)env + PARAM1);\
1033 s = (Reg *)((char *)env + PARAM2);\ 1033 s = (Reg *)((char *)env + PARAM2);\
1034 - d->XMM_L(0) = F(d->XMM_S(0), s->XMM_S(0));\  
1035 - d->XMM_L(1) = F(d->XMM_S(1), s->XMM_S(1));\  
1036 - d->XMM_L(2) = F(d->XMM_S(2), s->XMM_S(2));\  
1037 - d->XMM_L(3) = F(d->XMM_S(3), s->XMM_S(3));\ 1034 + d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
  1035 + d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1));\
  1036 + d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2));\
  1037 + d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3));\
1038 }\ 1038 }\
1039 \ 1039 \
1040 void OPPROTO op_ ## name ## ss (void)\ 1040 void OPPROTO op_ ## name ## ss (void)\
@@ -1042,15 +1042,15 @@ void OPPROTO op_ ## name ## ss (void)\ @@ -1042,15 +1042,15 @@ void OPPROTO op_ ## name ## ss (void)\
1042 Reg *d, *s;\ 1042 Reg *d, *s;\
1043 d = (Reg *)((char *)env + PARAM1);\ 1043 d = (Reg *)((char *)env + PARAM1);\
1044 s = (Reg *)((char *)env + PARAM2);\ 1044 s = (Reg *)((char *)env + PARAM2);\
1045 - d->XMM_L(0) = F(d->XMM_S(0), s->XMM_S(0));\ 1045 + d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
1046 }\ 1046 }\
1047 void OPPROTO op_ ## name ## pd (void)\ 1047 void OPPROTO op_ ## name ## pd (void)\
1048 {\ 1048 {\
1049 Reg *d, *s;\ 1049 Reg *d, *s;\
1050 d = (Reg *)((char *)env + PARAM1);\ 1050 d = (Reg *)((char *)env + PARAM1);\
1051 s = (Reg *)((char *)env + PARAM2);\ 1051 s = (Reg *)((char *)env + PARAM2);\
1052 - d->XMM_Q(0) = F(d->XMM_D(0), s->XMM_D(0));\  
1053 - d->XMM_Q(1) = F(d->XMM_D(1), s->XMM_D(1));\ 1052 + d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
  1053 + d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1));\
1054 }\ 1054 }\
1055 \ 1055 \
1056 void OPPROTO op_ ## name ## sd (void)\ 1056 void OPPROTO op_ ## name ## sd (void)\
@@ -1058,17 +1058,17 @@ void OPPROTO op_ ## name ## sd (void)\ @@ -1058,17 +1058,17 @@ void OPPROTO op_ ## name ## sd (void)\
1058 Reg *d, *s;\ 1058 Reg *d, *s;\
1059 d = (Reg *)((char *)env + PARAM1);\ 1059 d = (Reg *)((char *)env + PARAM1);\
1060 s = (Reg *)((char *)env + PARAM2);\ 1060 s = (Reg *)((char *)env + PARAM2);\
1061 - d->XMM_Q(0) = F(d->XMM_D(0), s->XMM_D(0));\ 1061 + d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
1062 } 1062 }
1063 1063
1064 -#define FPU_CMPEQ(a, b) (a) == (b) ? -1 : 0  
1065 -#define FPU_CMPLT(a, b) (a) < (b) ? -1 : 0  
1066 -#define FPU_CMPLE(a, b) (a) <= (b) ? -1 : 0  
1067 -#define FPU_CMPUNORD(a, b) (fpu_isnan(a) || fpu_isnan(b)) ? - 1 : 0  
1068 -#define FPU_CMPNEQ(a, b) (a) == (b) ? 0 : -1  
1069 -#define FPU_CMPNLT(a, b) (a) < (b) ? 0 : -1  
1070 -#define FPU_CMPNLE(a, b) (a) <= (b) ? 0 : -1  
1071 -#define FPU_CMPORD(a, b) (!fpu_isnan(a) && !fpu_isnan(b)) ? - 1 : 0 1064 +#define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0
  1065 +#define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0
  1066 +#define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0
  1067 +#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? - 1 : 0
  1068 +#define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1
  1069 +#define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1
  1070 +#define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1
  1071 +#define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1
1072 1072
1073 SSE_OP_CMP(cmpeq, FPU_CMPEQ) 1073 SSE_OP_CMP(cmpeq, FPU_CMPEQ)
1074 SSE_OP_CMP(cmplt, FPU_CMPLT) 1074 SSE_OP_CMP(cmplt, FPU_CMPLT)
@@ -1082,19 +1082,28 @@ SSE_OP_CMP(cmpord, FPU_CMPORD) @@ -1082,19 +1082,28 @@ SSE_OP_CMP(cmpord, FPU_CMPORD)
1082 void OPPROTO op_ucomiss(void) 1082 void OPPROTO op_ucomiss(void)
1083 { 1083 {
1084 int eflags; 1084 int eflags;
1085 - float s0, s1; 1085 + float32 s0, s1;
1086 Reg *d, *s; 1086 Reg *d, *s;
1087 d = (Reg *)((char *)env + PARAM1); 1087 d = (Reg *)((char *)env + PARAM1);
1088 s = (Reg *)((char *)env + PARAM2); 1088 s = (Reg *)((char *)env + PARAM2);
1089 1089
1090 s0 = d->XMM_S(0); 1090 s0 = d->XMM_S(0);
1091 s1 = s->XMM_S(0); 1091 s1 = s->XMM_S(0);
1092 - if (s0 < s1) 1092 + switch(float32_compare_quiet(s0, s1, &env->sse_status)) {
  1093 + case -1:
1093 eflags = CC_C; 1094 eflags = CC_C;
1094 - else if (s0 == s1) 1095 + break;
  1096 + case 0:
1095 eflags = CC_Z; 1097 eflags = CC_Z;
1096 - else 1098 + break;
  1099 + case 1:
1097 eflags = 0; 1100 eflags = 0;
  1101 + break;
  1102 + case 2:
  1103 + default:
  1104 + eflags = CC_Z | CC_P | CC_C;
  1105 + break;
  1106 + }
1098 CC_SRC = eflags; 1107 CC_SRC = eflags;
1099 FORCE_RET(); 1108 FORCE_RET();
1100 } 1109 }
@@ -1102,19 +1111,28 @@ void OPPROTO op_ucomiss(void) @@ -1102,19 +1111,28 @@ void OPPROTO op_ucomiss(void)
1102 void OPPROTO op_comiss(void) 1111 void OPPROTO op_comiss(void)
1103 { 1112 {
1104 int eflags; 1113 int eflags;
1105 - float s0, s1; 1114 + float32 s0, s1;
1106 Reg *d, *s; 1115 Reg *d, *s;
1107 d = (Reg *)((char *)env + PARAM1); 1116 d = (Reg *)((char *)env + PARAM1);
1108 s = (Reg *)((char *)env + PARAM2); 1117 s = (Reg *)((char *)env + PARAM2);
1109 1118
1110 s0 = d->XMM_S(0); 1119 s0 = d->XMM_S(0);
1111 s1 = s->XMM_S(0); 1120 s1 = s->XMM_S(0);
1112 - if (s0 < s1) 1121 + switch(float32_compare(s0, s1, &env->sse_status)) {
  1122 + case -1:
1113 eflags = CC_C; 1123 eflags = CC_C;
1114 - else if (s0 == s1) 1124 + break;
  1125 + case 0:
1115 eflags = CC_Z; 1126 eflags = CC_Z;
1116 - else 1127 + break;
  1128 + case 1:
1117 eflags = 0; 1129 eflags = 0;
  1130 + break;
  1131 + case 2:
  1132 + default:
  1133 + eflags = CC_Z | CC_P | CC_C;
  1134 + break;
  1135 + }
1118 CC_SRC = eflags; 1136 CC_SRC = eflags;
1119 FORCE_RET(); 1137 FORCE_RET();
1120 } 1138 }
@@ -1122,19 +1140,28 @@ void OPPROTO op_comiss(void) @@ -1122,19 +1140,28 @@ void OPPROTO op_comiss(void)
1122 void OPPROTO op_ucomisd(void) 1140 void OPPROTO op_ucomisd(void)
1123 { 1141 {
1124 int eflags; 1142 int eflags;
1125 - double d0, d1; 1143 + float64 d0, d1;
1126 Reg *d, *s; 1144 Reg *d, *s;
1127 d = (Reg *)((char *)env + PARAM1); 1145 d = (Reg *)((char *)env + PARAM1);
1128 s = (Reg *)((char *)env + PARAM2); 1146 s = (Reg *)((char *)env + PARAM2);
1129 1147
1130 d0 = d->XMM_D(0); 1148 d0 = d->XMM_D(0);
1131 d1 = s->XMM_D(0); 1149 d1 = s->XMM_D(0);
1132 - if (d0 < d1) 1150 + switch(float64_compare_quiet(d0, d1, &env->sse_status)) {
  1151 + case -1:
1133 eflags = CC_C; 1152 eflags = CC_C;
1134 - else if (d0 == d1) 1153 + break;
  1154 + case 0:
1135 eflags = CC_Z; 1155 eflags = CC_Z;
1136 - else 1156 + break;
  1157 + case 1:
1137 eflags = 0; 1158 eflags = 0;
  1159 + break;
  1160 + case 2:
  1161 + default:
  1162 + eflags = CC_Z | CC_P | CC_C;
  1163 + break;
  1164 + }
1138 CC_SRC = eflags; 1165 CC_SRC = eflags;
1139 FORCE_RET(); 1166 FORCE_RET();
1140 } 1167 }
@@ -1142,19 +1169,28 @@ void OPPROTO op_ucomisd(void) @@ -1142,19 +1169,28 @@ void OPPROTO op_ucomisd(void)
1142 void OPPROTO op_comisd(void) 1169 void OPPROTO op_comisd(void)
1143 { 1170 {
1144 int eflags; 1171 int eflags;
1145 - double d0, d1; 1172 + float64 d0, d1;
1146 Reg *d, *s; 1173 Reg *d, *s;
1147 d = (Reg *)((char *)env + PARAM1); 1174 d = (Reg *)((char *)env + PARAM1);
1148 s = (Reg *)((char *)env + PARAM2); 1175 s = (Reg *)((char *)env + PARAM2);
1149 1176
1150 d0 = d->XMM_D(0); 1177 d0 = d->XMM_D(0);
1151 d1 = s->XMM_D(0); 1178 d1 = s->XMM_D(0);
1152 - if (d0 < d1) 1179 + switch(float64_compare(d0, d1, &env->sse_status)) {
  1180 + case -1:
1153 eflags = CC_C; 1181 eflags = CC_C;
1154 - else if (d0 == d1) 1182 + break;
  1183 + case 0:
1155 eflags = CC_Z; 1184 eflags = CC_Z;
1156 - else 1185 + break;
  1186 + case 1:
1157 eflags = 0; 1187 eflags = 0;
  1188 + break;
  1189 + case 2:
  1190 + default:
  1191 + eflags = CC_Z | CC_P | CC_C;
  1192 + break;
  1193 + }
1158 CC_SRC = eflags; 1194 CC_SRC = eflags;
1159 FORCE_RET(); 1195 FORCE_RET();
1160 } 1196 }