aboutsummaryrefslogtreecommitdiff
path: root/target-sparc/op_helper.c
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2011-01-18 21:34:51 +0000
committerBlue Swirl <blauwirbel@gmail.com>2011-01-18 21:34:51 +0000
commit1b5f56b134dc2d338911242424795de70c7475fd (patch)
treeca309a5a33201d368bc1d787f2cb39cc8e831ee7 /target-sparc/op_helper.c
parent5642463aeeb187597e217706d9ed2663cd3734c0 (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.c56
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);