aboutsummaryrefslogtreecommitdiff
path: root/target/i386/tcg/fpu_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/i386/tcg/fpu_helper.c')
-rw-r--r--target/i386/tcg/fpu_helper.c215
1 files changed, 138 insertions, 77 deletions
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index e1b850f..b3b2382 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -21,8 +21,8 @@
#include <math.h>
#include "cpu.h"
#include "tcg-cpu.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
+#include "exec/cputlb.h"
+#include "accel/tcg/cpu-ldst.h"
#include "exec/helper-proto.h"
#include "fpu/softfloat.h"
#include "fpu/softfloat-macros.h"
@@ -135,16 +135,79 @@ static void fpu_set_exception(CPUX86State *env, int mask)
}
}
-static inline uint8_t save_exception_flags(CPUX86State *env)
+void cpu_init_fp_statuses(CPUX86State *env)
{
- uint8_t old_flags = get_float_exception_flags(&env->fp_status);
+ /*
+ * Initialise the non-runtime-varying fields of the various
+ * float_status words to x86 behaviour. This must be called at
+ * CPU reset because the float_status words are in the
+ * "zeroed on reset" portion of the CPU state struct.
+ * Fields in float_status that vary under guest control are set
+ * via the codepath for setting that register, eg cpu_set_fpuc().
+ */
+ /*
+ * Use x87 NaN propagation rules:
+ * SNaN + QNaN => return the QNaN
+ * two SNaNs => return the one with the larger significand, silenced
+ * two QNaNs => return the one with the larger significand
+ * SNaN and a non-NaN => return the SNaN, silenced
+ * QNaN and a non-NaN => return the QNaN
+ *
+ * If we get down to comparing significands and they are the same,
+ * return the NaN with the positive sign bit (if any).
+ */
+ set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
+ /*
+ * TODO: These are incorrect: the x86 Software Developer's Manual vol 1
+ * section 4.8.3.5 "Operating on SNaNs and QNaNs" says that the
+ * "larger significand" behaviour is only used for x87 FPU operations.
+ * For SSE the required behaviour is to always return the first NaN,
+ * which is float_2nan_prop_ab.
+ *
+ * mmx_status is used only for the AMD 3DNow! instructions, which
+ * are documented in the "3DNow! Technology Manual" as not supporting
+ * NaNs or infinities as inputs. The result of passing two NaNs is
+ * documented as "undefined", so we can do what we choose.
+ * (Strictly there is some behaviour we don't implement correctly
+ * for these "unsupported" NaN and Inf values, like "NaN * 0 == 0".)
+ */
+ set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
+ set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
+ /*
+ * Only SSE has multiply-add instructions. In the SDM Section 14.5.2
+ * "Fused-Multiply-ADD (FMA) Numeric Behavior" the NaN handling is
+ * specified -- for 0 * inf + NaN the input NaN is selected, and if
+ * there are multiple input NaNs they are selected in the order a, b, c.
+ * We also do not raise Invalid for the 0 * inf + (Q)NaN case.
+ */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never |
+ float_infzeronan_suppress_invalid,
+ &env->sse_status);
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status);
+ /* Default NaN: sign bit set, most significant frac bit set */
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
+ set_float_default_nan_pattern(0b11000000, &env->mmx_status);
+ set_float_default_nan_pattern(0b11000000, &env->sse_status);
+ /*
+ * x86 does flush-to-zero detection after rounding (the SDM
+ * section 10.2.3.3 on the FTZ bit of MXCSR says that we flush
+ * when we detect underflow, which x86 does after rounding).
+ */
+ set_float_ftz_detection(float_ftz_after_rounding, &env->fp_status);
+ set_float_ftz_detection(float_ftz_after_rounding, &env->mmx_status);
+ set_float_ftz_detection(float_ftz_after_rounding, &env->sse_status);
+}
+
+static inline int save_exception_flags(CPUX86State *env)
+{
+ int old_flags = get_float_exception_flags(&env->fp_status);
set_float_exception_flags(0, &env->fp_status);
return old_flags;
}
-static void merge_exception_flags(CPUX86State *env, uint8_t old_flags)
+static void merge_exception_flags(CPUX86State *env, int old_flags)
{
- uint8_t new_flags = get_float_exception_flags(&env->fp_status);
+ int new_flags = get_float_exception_flags(&env->fp_status);
float_raise(old_flags, &env->fp_status);
fpu_set_exception(env,
((new_flags & float_flag_invalid ? FPUS_IE : 0) |
@@ -152,12 +215,12 @@ static void merge_exception_flags(CPUX86State *env, uint8_t old_flags)
(new_flags & float_flag_overflow ? FPUS_OE : 0) |
(new_flags & float_flag_underflow ? FPUS_UE : 0) |
(new_flags & float_flag_inexact ? FPUS_PE : 0) |
- (new_flags & float_flag_input_denormal ? FPUS_DE : 0)));
+ (new_flags & float_flag_input_denormal_used ? FPUS_DE : 0)));
}
static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
floatx80 ret = floatx80_div(a, b, &env->fp_status);
merge_exception_flags(env, old_flags);
return ret;
@@ -177,7 +240,7 @@ static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr)
void helper_flds_FT0(CPUX86State *env, uint32_t val)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
union {
float32 f;
uint32_t i;
@@ -190,7 +253,7 @@ void helper_flds_FT0(CPUX86State *env, uint32_t val)
void helper_fldl_FT0(CPUX86State *env, uint64_t val)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
union {
float64 f;
uint64_t i;
@@ -208,7 +271,7 @@ void helper_fildl_FT0(CPUX86State *env, int32_t val)
void helper_flds_ST0(CPUX86State *env, uint32_t val)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int new_fpstt;
union {
float32 f;
@@ -225,7 +288,7 @@ void helper_flds_ST0(CPUX86State *env, uint32_t val)
void helper_fldl_ST0(CPUX86State *env, uint64_t val)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int new_fpstt;
union {
float64 f;
@@ -275,7 +338,7 @@ void helper_fildll_ST0(CPUX86State *env, int64_t val)
uint32_t helper_fsts_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
union {
float32 f;
uint32_t i;
@@ -288,7 +351,7 @@ uint32_t helper_fsts_ST0(CPUX86State *env)
uint64_t helper_fstl_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
union {
float64 f;
uint64_t i;
@@ -301,7 +364,7 @@ uint64_t helper_fstl_ST0(CPUX86State *env)
int32_t helper_fist_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int32_t val;
val = floatx80_to_int32(ST0, &env->fp_status);
@@ -315,7 +378,7 @@ int32_t helper_fist_ST0(CPUX86State *env)
int32_t helper_fistl_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int32_t val;
val = floatx80_to_int32(ST0, &env->fp_status);
@@ -328,7 +391,7 @@ int32_t helper_fistl_ST0(CPUX86State *env)
int64_t helper_fistll_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int64_t val;
val = floatx80_to_int64(ST0, &env->fp_status);
@@ -341,7 +404,7 @@ int64_t helper_fistll_ST0(CPUX86State *env)
int32_t helper_fistt_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int32_t val;
val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
@@ -355,7 +418,7 @@ int32_t helper_fistt_ST0(CPUX86State *env)
int32_t helper_fisttl_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int32_t val;
val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
@@ -368,7 +431,7 @@ int32_t helper_fisttl_ST0(CPUX86State *env)
int64_t helper_fisttll_ST0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int64_t val;
val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
@@ -464,7 +527,7 @@ static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
void helper_fcom_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
FloatRelation ret;
ret = floatx80_compare(ST0, FT0, &env->fp_status);
@@ -474,7 +537,7 @@ void helper_fcom_ST0_FT0(CPUX86State *env)
void helper_fucom_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
FloatRelation ret;
ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
@@ -486,7 +549,7 @@ static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
void helper_fcomi_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int eflags;
FloatRelation ret;
@@ -499,7 +562,7 @@ void helper_fcomi_ST0_FT0(CPUX86State *env)
void helper_fucomi_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int eflags;
FloatRelation ret;
@@ -512,28 +575,28 @@ void helper_fucomi_ST0_FT0(CPUX86State *env)
void helper_fadd_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST0 = floatx80_add(ST0, FT0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fmul_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fsub_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fsubr_ST0_FT0(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
@@ -552,28 +615,28 @@ void helper_fdivr_ST0_FT0(CPUX86State *env)
void helper_fadd_STN_ST0(CPUX86State *env, int st_index)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fmul_STN_ST0(CPUX86State *env, int st_index)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fsub_STN_ST0(CPUX86State *env, int st_index)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fsubr_STN_ST0(CPUX86State *env, int st_index)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
merge_exception_flags(env, old_flags);
}
@@ -798,7 +861,7 @@ void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
int v;
target_ulong mem_ref, mem_end;
int64_t val;
@@ -1073,12 +1136,12 @@ static const struct f2xm1_data f2xm1_table[65] = {
void helper_f2xm1(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
uint64_t sig = extractFloatx80Frac(ST0);
int32_t exp = extractFloatx80Exp(ST0);
bool sign = extractFloatx80Sign(ST0);
- if (floatx80_invalid_encoding(ST0)) {
+ if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@@ -1306,7 +1369,7 @@ static const struct fpatan_data fpatan_table[9] = {
void helper_fpatan(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
uint64_t arg0_sig = extractFloatx80Frac(ST0);
int32_t arg0_exp = extractFloatx80Exp(ST0);
bool arg0_sign = extractFloatx80Sign(ST0);
@@ -1320,8 +1383,8 @@ void helper_fpatan(CPUX86State *env)
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
- } else if (floatx80_invalid_encoding(ST0) ||
- floatx80_invalid_encoding(ST1)) {
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@@ -1330,7 +1393,8 @@ void helper_fpatan(CPUX86State *env)
/* Pass this NaN through. */
} else if (floatx80_is_zero(ST1) && !arg0_sign) {
/* Pass this zero through. */
- } else if (((floatx80_is_infinity(ST0) && !floatx80_is_infinity(ST1)) ||
+ } else if (((floatx80_is_infinity(ST0, &env->fp_status) &&
+ !floatx80_is_infinity(ST1, &env->fp_status)) ||
arg0_exp - arg1_exp >= 80) &&
!arg0_sign) {
/*
@@ -1379,8 +1443,8 @@ void helper_fpatan(CPUX86State *env)
rexp = pi_exp;
rsig0 = pi_sig_high;
rsig1 = pi_sig_low;
- } else if (floatx80_is_infinity(ST1)) {
- if (floatx80_is_infinity(ST0)) {
+ } else if (floatx80_is_infinity(ST1, &env->fp_status)) {
+ if (floatx80_is_infinity(ST0, &env->fp_status)) {
if (arg0_sign) {
rexp = pi_34_exp;
rsig0 = pi_34_sig_high;
@@ -1399,7 +1463,8 @@ void helper_fpatan(CPUX86State *env)
rexp = pi_2_exp;
rsig0 = pi_2_sig_high;
rsig1 = pi_2_sig_low;
- } else if (floatx80_is_infinity(ST0) || arg0_exp - arg1_exp >= 80) {
+ } else if (floatx80_is_infinity(ST0, &env->fp_status) ||
+ arg0_exp - arg1_exp >= 80) {
/* ST0 is negative. */
rexp = pi_exp;
rsig0 = pi_sig_high;
@@ -1743,7 +1808,7 @@ void helper_fpatan(CPUX86State *env)
void helper_fxtract(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
CPU_LDoubleU temp;
temp.d = ST0;
@@ -1754,7 +1819,7 @@ void helper_fxtract(CPUX86State *env)
&env->fp_status);
fpush(env);
ST0 = temp.d;
- } else if (floatx80_invalid_encoding(ST0)) {
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
fpush(env);
@@ -1766,10 +1831,10 @@ void helper_fxtract(CPUX86State *env)
}
fpush(env);
ST0 = ST1;
- } else if (floatx80_is_infinity(ST0)) {
+ } else if (floatx80_is_infinity(ST0, &env->fp_status)) {
fpush(env);
ST0 = ST1;
- ST1 = floatx80_infinity;
+ ST1 = floatx80_default_inf(0, &env->fp_status);
} else {
int expdif;
@@ -1777,7 +1842,7 @@ void helper_fxtract(CPUX86State *env)
int shift = clz64(temp.l.lower);
temp.l.lower <<= shift;
expdif = 1 - EXPBIAS - shift;
- float_raise(float_flag_input_denormal, &env->fp_status);
+ float_raise(float_flag_input_denormal_flushed, &env->fp_status);
} else {
expdif = EXPD(temp) - EXPBIAS;
}
@@ -1792,7 +1857,7 @@ void helper_fxtract(CPUX86State *env)
static void helper_fprem_common(CPUX86State *env, bool mod)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
uint64_t quotient;
CPU_LDoubleU temp0, temp1;
int exp0, exp1, expdiff;
@@ -1805,7 +1870,8 @@ static void helper_fprem_common(CPUX86State *env, bool mod)
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
if (floatx80_is_zero(ST0) || floatx80_is_zero(ST1) ||
exp0 == 0x7fff || exp1 == 0x7fff ||
- floatx80_invalid_encoding(ST0) || floatx80_invalid_encoding(ST1)) {
+ floatx80_invalid_encoding(ST0, &env->fp_status) ||
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
ST0 = floatx80_modrem(ST0, ST1, mod, &quotient, &env->fp_status);
} else {
if (exp0 == 0) {
@@ -1987,7 +2053,7 @@ static void helper_fyl2x_common(CPUX86State *env, floatx80 arg, int32_t *exp,
void helper_fyl2xp1(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
uint64_t arg0_sig = extractFloatx80Frac(ST0);
int32_t arg0_exp = extractFloatx80Exp(ST0);
bool arg0_sign = extractFloatx80Sign(ST0);
@@ -2001,8 +2067,8 @@ void helper_fyl2xp1(CPUX86State *env)
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
- } else if (floatx80_invalid_encoding(ST0) ||
- floatx80_invalid_encoding(ST1)) {
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@@ -2085,7 +2151,7 @@ void helper_fyl2xp1(CPUX86State *env)
void helper_fyl2x(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
uint64_t arg0_sig = extractFloatx80Frac(ST0);
int32_t arg0_exp = extractFloatx80Exp(ST0);
bool arg0_sign = extractFloatx80Sign(ST0);
@@ -2099,8 +2165,8 @@ void helper_fyl2x(CPUX86State *env)
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
- } else if (floatx80_invalid_encoding(ST0) ||
- floatx80_invalid_encoding(ST1)) {
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@@ -2110,7 +2176,7 @@ void helper_fyl2x(CPUX86State *env)
} else if (arg0_sign && !floatx80_is_zero(ST0)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
- } else if (floatx80_is_infinity(ST1)) {
+ } else if (floatx80_is_infinity(ST1, &env->fp_status)) {
FloatRelation cmp = floatx80_compare(ST0, floatx80_one,
&env->fp_status);
switch (cmp) {
@@ -2125,7 +2191,7 @@ void helper_fyl2x(CPUX86State *env)
ST1 = floatx80_default_nan(&env->fp_status);
break;
}
- } else if (floatx80_is_infinity(ST0)) {
+ } else if (floatx80_is_infinity(ST0, &env->fp_status)) {
if (floatx80_is_zero(ST1)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
@@ -2232,7 +2298,7 @@ void helper_fyl2x(CPUX86State *env)
void helper_fsqrt(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
if (floatx80_is_neg(ST0)) {
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
env->fpus |= 0x400;
@@ -2258,15 +2324,16 @@ void helper_fsincos(CPUX86State *env)
void helper_frndint(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
+ int old_flags = save_exception_flags(env);
ST0 = floatx80_round_to_int(ST0, &env->fp_status);
merge_exception_flags(env, old_flags);
}
void helper_fscale(CPUX86State *env)
{
- uint8_t old_flags = save_exception_flags(env);
- if (floatx80_invalid_encoding(ST1) || floatx80_invalid_encoding(ST0)) {
+ int old_flags = save_exception_flags(env);
+ if (floatx80_invalid_encoding(ST1, &env->fp_status) ||
+ floatx80_invalid_encoding(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST1)) {
@@ -2278,11 +2345,11 @@ void helper_fscale(CPUX86State *env)
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_silence_nan(ST0, &env->fp_status);
}
- } else if (floatx80_is_infinity(ST1) &&
- !floatx80_invalid_encoding(ST0) &&
+ } else if (floatx80_is_infinity(ST1, &env->fp_status) &&
+ !floatx80_invalid_encoding(ST0, &env->fp_status) &&
!floatx80_is_any_nan(ST0)) {
if (floatx80_is_neg(ST1)) {
- if (floatx80_is_infinity(ST0)) {
+ if (floatx80_is_infinity(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else {
@@ -2295,15 +2362,14 @@ void helper_fscale(CPUX86State *env)
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else {
- ST0 = (floatx80_is_neg(ST0) ?
- floatx80_chs(floatx80_infinity) :
- floatx80_infinity);
+ ST0 = floatx80_default_inf(floatx80_is_neg(ST0),
+ &env->fp_status);
}
}
} else {
int n;
FloatX80RoundPrec save = env->fp_status.floatx80_rounding_precision;
- uint8_t save_flags = get_float_exception_flags(&env->fp_status);
+ int save_flags = get_float_exception_flags(&env->fp_status);
set_float_exception_flags(0, &env->fp_status);
n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
set_float_exception_flags(save_flags, &env->fp_status);
@@ -3188,6 +3254,7 @@ void update_mxcsr_status(CPUX86State *env)
/* Set exception flags. */
set_float_exception_flags((mxcsr & FPUS_IE ? float_flag_invalid : 0) |
+ (mxcsr & FPUS_DE ? float_flag_input_denormal_used : 0) |
(mxcsr & FPUS_ZE ? float_flag_divbyzero : 0) |
(mxcsr & FPUS_OE ? float_flag_overflow : 0) |
(mxcsr & FPUS_UE ? float_flag_underflow : 0) |
@@ -3203,20 +3270,14 @@ void update_mxcsr_status(CPUX86State *env)
void update_mxcsr_from_sse_status(CPUX86State *env)
{
- uint8_t flags = get_float_exception_flags(&env->sse_status);
- /*
- * The MXCSR denormal flag has opposite semantics to
- * float_flag_input_denormal (the softfloat code sets that flag
- * only when flushing input denormals to zero, but SSE sets it
- * only when not flushing them to zero), so is not converted
- * here.
- */
+ int flags = get_float_exception_flags(&env->sse_status);
env->mxcsr |= ((flags & float_flag_invalid ? FPUS_IE : 0) |
+ (flags & float_flag_input_denormal_used ? FPUS_DE : 0) |
(flags & float_flag_divbyzero ? FPUS_ZE : 0) |
(flags & float_flag_overflow ? FPUS_OE : 0) |
(flags & float_flag_underflow ? FPUS_UE : 0) |
(flags & float_flag_inexact ? FPUS_PE : 0) |
- (flags & float_flag_output_denormal ? FPUS_UE | FPUS_PE :
+ (flags & float_flag_output_denormal_flushed ? FPUS_UE | FPUS_PE :
0));
}