diff options
author | Blue Swirl <blauwirbel@gmail.com> | 2011-01-18 21:34:51 +0000 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2011-01-18 21:34:51 +0000 |
commit | 1b5f56b134dc2d338911242424795de70c7475fd (patch) | |
tree | ca309a5a33201d368bc1d787f2cb39cc8e831ee7 /target-sparc/op_helper.c | |
parent | 5642463aeeb187597e217706d9ed2663cd3734c0 (diff) |
sparc: fix NaN handling
Fix several bugs in NaN handling:
* e in fcmpe* only changes qNaN handling
* FCC is unchanged if an exception is raised
* clear previous FTT before setting it
Reported-by: Mateusz Loskot <mateusz@loskot.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r-- | target-sparc/op_helper.c | 56 |
1 files changed, 34 insertions, 22 deletions
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 58f9f82f52..b70970ac2a 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -857,65 +857,77 @@ void helper_fsqrtq(void) QT0 = float128_sqrt(QT1, &env->fp_status); } -#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ +#define GEN_FCMP(name, size, reg1, reg2, FS, E) \ void glue(helper_, name) (void) \ { \ - target_ulong new_fsr; \ - \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= FSR_FTT_NMASK; \ + if (E && (glue(size, _is_any_nan)(reg1) || \ + glue(size, _is_any_nan)(reg2)) && \ + (env->fsr & FSR_NVM)) { \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + raise_exception(TT_FP_EXCP); \ + } \ switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ case float_relation_unordered: \ - new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \ - if ((env->fsr & FSR_NVM) || TRAP) { \ - env->fsr |= new_fsr; \ + if ((env->fsr & FSR_NVM)) { \ env->fsr |= FSR_NVC; \ env->fsr |= FSR_FTT_IEEE_EXCP; \ raise_exception(TT_FP_EXCP); \ } else { \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ env->fsr |= FSR_NVA; \ } \ break; \ case float_relation_less: \ - new_fsr = FSR_FCC0 << FS; \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - new_fsr = FSR_FCC1 << FS; \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC1 << FS; \ break; \ default: \ - new_fsr = 0; \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ break; \ } \ - env->fsr |= new_fsr; \ } -#define GEN_FCMPS(name, size, FS, TRAP) \ +#define GEN_FCMPS(name, size, FS, E) \ void glue(helper_, name)(float32 src1, float32 src2) \ { \ - target_ulong new_fsr; \ - \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= FSR_FTT_NMASK; \ + if (E && (glue(size, _is_any_nan)(src1) || \ + glue(size, _is_any_nan)(src2)) && \ + (env->fsr & FSR_NVM)) { \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ + raise_exception(TT_FP_EXCP); \ + } \ switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ case float_relation_unordered: \ - new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \ - if ((env->fsr & FSR_NVM) || TRAP) { \ - env->fsr |= new_fsr; \ + if ((env->fsr & FSR_NVM)) { \ env->fsr |= FSR_NVC; \ env->fsr |= FSR_FTT_IEEE_EXCP; \ raise_exception(TT_FP_EXCP); \ } else { \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ env->fsr |= FSR_NVA; \ } \ break; \ case float_relation_less: \ - new_fsr = FSR_FCC0 << FS; \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - new_fsr = FSR_FCC1 << FS; \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr |= FSR_FCC1 << FS; \ break; \ default: \ - new_fsr = 0; \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ break; \ } \ - env->fsr |= new_fsr; \ } GEN_FCMPS(fcmps, float32, 0, 0); |