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>
This commit is contained in:
Blue Swirl 2011-01-18 21:34:51 +00:00
parent 5642463aee
commit 1b5f56b134
1 changed files with 34 additions and 22 deletions

View File

@ -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);