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 325 #define floatx_abs floatx80_abs
326 326 #define floatx_chs floatx80_chs
327 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 330 #define sin sinl
329 331 #define cos cosl
330 332 #define sqrt sqrtl
... ... @@ -340,6 +342,8 @@ static inline void stfl(target_ulong ptr, float v)
340 342 #define floatx_abs float64_abs
341 343 #define floatx_chs float64_chs
342 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 347 #endif
344 348  
345 349 extern CPU86_LDouble sin(CPU86_LDouble x);
... ... @@ -547,8 +551,6 @@ void restore_native_fp_state(CPUState *env);
547 551 void save_native_fp_state(CPUState *env);
548 552 float approx_rsqrt(float a);
549 553 float approx_rcp(float a);
550   -double helper_sqrt(double a);
551   -int fpu_isnan(double a);
552 554 void update_fp_status(void);
553 555  
554 556 extern const uint8_t parity_table[256];
... ...
target-i386/helper.c
... ... @@ -3223,12 +3223,6 @@ void helper_idivq_EAX_T0(void)
3223 3223  
3224 3224 #endif
3225 3225  
3226   -/* XXX: do it */
3227   -int fpu_isnan(double a)
3228   -{
3229   - return 0;
3230   -}
3231   -
3232 3226 float approx_rsqrt(float a)
3233 3227 {
3234 3228 return 1.0 / sqrt(a);
... ...
target-i386/op.c
... ... @@ -1952,52 +1952,94 @@ void OPPROTO op_fxchg_ST0_STN(void)
1952 1952  
1953 1953 /* FPU operations */
1954 1954  
1955   -/* XXX: handle nans */
1956 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 1974 FORCE_RET();
1964 1975 }
1965 1976  
1966   -/* XXX: handle nans */
1967 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 1996 FORCE_RET();
1975 1997 }
1976 1998  
1977   -/* XXX: handle nans */
1978 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 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 2019 CC_SRC = eflags;
1988 2020 FORCE_RET();
1989 2021 }
1990 2022  
1991   -/* XXX: handle nans */
1992 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 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 2043 CC_SRC = eflags;
2002 2044 FORCE_RET();
2003 2045 }
... ...
target-i386/ops_sse.h
... ... @@ -704,7 +704,7 @@ SSE_OP_S(sqrt, FPU_SQRT)
704 704 /* float to float conversions */
705 705 void OPPROTO op_cvtps2pd(void)
706 706 {
707   - float s0, s1;
  707 + float32 s0, s1;
708 708 Reg *d, *s;
709 709 d = (Reg *)((char *)env + PARAM1);
710 710 s = (Reg *)((char *)env + PARAM2);
... ... @@ -1031,10 +1031,10 @@ void OPPROTO op_ ## name ## ps (void)\
1031 1031 Reg *d, *s;\
1032 1032 d = (Reg *)((char *)env + PARAM1);\
1033 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 1040 void OPPROTO op_ ## name ## ss (void)\
... ... @@ -1042,15 +1042,15 @@ void OPPROTO op_ ## name ## ss (void)\
1042 1042 Reg *d, *s;\
1043 1043 d = (Reg *)((char *)env + PARAM1);\
1044 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 1047 void OPPROTO op_ ## name ## pd (void)\
1048 1048 {\
1049 1049 Reg *d, *s;\
1050 1050 d = (Reg *)((char *)env + PARAM1);\
1051 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 1056 void OPPROTO op_ ## name ## sd (void)\
... ... @@ -1058,17 +1058,17 @@ void OPPROTO op_ ## name ## sd (void)\
1058 1058 Reg *d, *s;\
1059 1059 d = (Reg *)((char *)env + PARAM1);\
1060 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 1073 SSE_OP_CMP(cmpeq, FPU_CMPEQ)
1074 1074 SSE_OP_CMP(cmplt, FPU_CMPLT)
... ... @@ -1082,19 +1082,28 @@ SSE_OP_CMP(cmpord, FPU_CMPORD)
1082 1082 void OPPROTO op_ucomiss(void)
1083 1083 {
1084 1084 int eflags;
1085   - float s0, s1;
  1085 + float32 s0, s1;
1086 1086 Reg *d, *s;
1087 1087 d = (Reg *)((char *)env + PARAM1);
1088 1088 s = (Reg *)((char *)env + PARAM2);
1089 1089  
1090 1090 s0 = d->XMM_S(0);
1091 1091 s1 = s->XMM_S(0);
1092   - if (s0 < s1)
  1092 + switch(float32_compare_quiet(s0, s1, &env->sse_status)) {
  1093 + case -1:
1093 1094 eflags = CC_C;
1094   - else if (s0 == s1)
  1095 + break;
  1096 + case 0:
1095 1097 eflags = CC_Z;
1096   - else
  1098 + break;
  1099 + case 1:
1097 1100 eflags = 0;
  1101 + break;
  1102 + case 2:
  1103 + default:
  1104 + eflags = CC_Z | CC_P | CC_C;
  1105 + break;
  1106 + }
1098 1107 CC_SRC = eflags;
1099 1108 FORCE_RET();
1100 1109 }
... ... @@ -1102,19 +1111,28 @@ void OPPROTO op_ucomiss(void)
1102 1111 void OPPROTO op_comiss(void)
1103 1112 {
1104 1113 int eflags;
1105   - float s0, s1;
  1114 + float32 s0, s1;
1106 1115 Reg *d, *s;
1107 1116 d = (Reg *)((char *)env + PARAM1);
1108 1117 s = (Reg *)((char *)env + PARAM2);
1109 1118  
1110 1119 s0 = d->XMM_S(0);
1111 1120 s1 = s->XMM_S(0);
1112   - if (s0 < s1)
  1121 + switch(float32_compare(s0, s1, &env->sse_status)) {
  1122 + case -1:
1113 1123 eflags = CC_C;
1114   - else if (s0 == s1)
  1124 + break;
  1125 + case 0:
1115 1126 eflags = CC_Z;
1116   - else
  1127 + break;
  1128 + case 1:
1117 1129 eflags = 0;
  1130 + break;
  1131 + case 2:
  1132 + default:
  1133 + eflags = CC_Z | CC_P | CC_C;
  1134 + break;
  1135 + }
1118 1136 CC_SRC = eflags;
1119 1137 FORCE_RET();
1120 1138 }
... ... @@ -1122,19 +1140,28 @@ void OPPROTO op_comiss(void)
1122 1140 void OPPROTO op_ucomisd(void)
1123 1141 {
1124 1142 int eflags;
1125   - double d0, d1;
  1143 + float64 d0, d1;
1126 1144 Reg *d, *s;
1127 1145 d = (Reg *)((char *)env + PARAM1);
1128 1146 s = (Reg *)((char *)env + PARAM2);
1129 1147  
1130 1148 d0 = d->XMM_D(0);
1131 1149 d1 = s->XMM_D(0);
1132   - if (d0 < d1)
  1150 + switch(float64_compare_quiet(d0, d1, &env->sse_status)) {
  1151 + case -1:
1133 1152 eflags = CC_C;
1134   - else if (d0 == d1)
  1153 + break;
  1154 + case 0:
1135 1155 eflags = CC_Z;
1136   - else
  1156 + break;
  1157 + case 1:
1137 1158 eflags = 0;
  1159 + break;
  1160 + case 2:
  1161 + default:
  1162 + eflags = CC_Z | CC_P | CC_C;
  1163 + break;
  1164 + }
1138 1165 CC_SRC = eflags;
1139 1166 FORCE_RET();
1140 1167 }
... ... @@ -1142,19 +1169,28 @@ void OPPROTO op_ucomisd(void)
1142 1169 void OPPROTO op_comisd(void)
1143 1170 {
1144 1171 int eflags;
1145   - double d0, d1;
  1172 + float64 d0, d1;
1146 1173 Reg *d, *s;
1147 1174 d = (Reg *)((char *)env + PARAM1);
1148 1175 s = (Reg *)((char *)env + PARAM2);
1149 1176  
1150 1177 d0 = d->XMM_D(0);
1151 1178 d1 = s->XMM_D(0);
1152   - if (d0 < d1)
  1179 + switch(float64_compare(d0, d1, &env->sse_status)) {
  1180 + case -1:
1153 1181 eflags = CC_C;
1154   - else if (d0 == d1)
  1182 + break;
  1183 + case 0:
1155 1184 eflags = CC_Z;
1156   - else
  1185 + break;
  1186 + case 1:
1157 1187 eflags = 0;
  1188 + break;
  1189 + case 2:
  1190 + default:
  1191 + eflags = CC_Z | CC_P | CC_C;
  1192 + break;
  1193 + }
1158 1194 CC_SRC = eflags;
1159 1195 FORCE_RET();
1160 1196 }
... ...