aboutsummaryrefslogtreecommitdiff
path: root/fpu/softfloat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fpu/softfloat.c')
-rw-r--r--fpu/softfloat.c95
1 files changed, 71 insertions, 24 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 8d75d66..34c962d 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -79,9 +79,6 @@ this code that are retained.
* version 2 or later. See the COPYING file in the top-level directory.
*/
-/* softfloat (and in particular the code in softfloat-specialize.h) is
- * target-dependent and needs the TARGET_* macros.
- */
#include "qemu/osdep.h"
#include <math.h>
#include "qemu/bitops.h"
@@ -132,7 +129,7 @@ this code that are retained.
if (unlikely(soft_t ## _is_denormal(*a))) { \
*a = soft_t ## _set_sign(soft_t ## _zero, \
soft_t ## _is_neg(*a)); \
- float_raise(float_flag_input_denormal, s); \
+ float_raise(float_flag_input_denormal_flushed, s); \
} \
}
@@ -220,11 +217,9 @@ GEN_INPUT_FLUSH3(float64_input_flush3, float64)
* the use of hardfloat, since hardfloat relies on the inexact flag being
* already set.
*/
-#if defined(TARGET_PPC) || defined(__FAST_MATH__)
# if defined(__FAST_MATH__)
# warning disabling hardfloat due to -ffast-math: hardfloat requires an exact \
IEEE implementation
-# endif
# define QEMU_NO_HARDFLOAT 1
# define QEMU_SOFTFLOAT_ATTR QEMU_FLATTEN
#else
@@ -404,12 +399,16 @@ float64_gen2(float64 xa, float64 xb, float_status *s,
/*
* Classify a floating point number. Everything above float_class_qnan
* is a NaN so cls >= float_class_qnan is any NaN.
+ *
+ * Note that we canonicalize denormals, so most code should treat
+ * class_normal and class_denormal identically.
*/
typedef enum __attribute__ ((__packed__)) {
float_class_unclassified,
float_class_zero,
float_class_normal,
+ float_class_denormal, /* input was a non-squashed denormal */
float_class_inf,
float_class_qnan, /* all NaNs from here */
float_class_snan,
@@ -420,12 +419,14 @@ typedef enum __attribute__ ((__packed__)) {
enum {
float_cmask_zero = float_cmask(float_class_zero),
float_cmask_normal = float_cmask(float_class_normal),
+ float_cmask_denormal = float_cmask(float_class_denormal),
float_cmask_inf = float_cmask(float_class_inf),
float_cmask_qnan = float_cmask(float_class_qnan),
float_cmask_snan = float_cmask(float_class_snan),
float_cmask_infzero = float_cmask_zero | float_cmask_inf,
float_cmask_anynan = float_cmask_qnan | float_cmask_snan,
+ float_cmask_anynorm = float_cmask_normal | float_cmask_denormal,
};
/* Flags for parts_minmax. */
@@ -460,6 +461,20 @@ static inline __attribute__((unused)) bool is_qnan(FloatClass c)
}
/*
+ * Return true if the float_cmask has only normals in it
+ * (including input denormals that were canonicalized)
+ */
+static inline bool cmask_is_only_normals(int cmask)
+{
+ return !(cmask & ~float_cmask_anynorm);
+}
+
+static inline bool is_anynorm(FloatClass c)
+{
+ return float_cmask(c) & float_cmask_anynorm;
+}
+
+/*
* Structure holding all of the decomposed parts of a float.
* The exponent is unbiased and the fraction is normalized.
*
@@ -517,7 +532,8 @@ typedef struct {
* round_mask: bits below lsb which must be rounded
* The following optional modifiers are available:
* arm_althp: handle ARM Alternative Half Precision
- * m68k_denormal: explicit integer bit for extended precision may be 1
+ * has_explicit_bit: has an explicit integer bit; this affects whether
+ * the float_status floatx80_behaviour handling applies
*/
typedef struct {
int exp_size;
@@ -527,7 +543,7 @@ typedef struct {
int frac_size;
int frac_shift;
bool arm_althp;
- bool m68k_denormal;
+ bool has_explicit_bit;
uint64_t round_mask;
} FloatFmt;
@@ -580,9 +596,7 @@ static const FloatFmt floatx80_params[3] = {
[floatx80_precision_d] = { FLOATX80_PARAMS(52) },
[floatx80_precision_x] = {
FLOATX80_PARAMS(64),
-#ifdef TARGET_M68K
- .m68k_denormal = true,
-#endif
+ .has_explicit_bit = true,
},
};
@@ -1729,6 +1743,7 @@ static float64 float64r32_round_pack_canonical(FloatParts64 *p,
*/
switch (p->cls) {
case float_class_normal:
+ case float_class_denormal:
if (unlikely(p->exp == 0)) {
/*
* The result is denormal for float32, but can be represented
@@ -1789,7 +1804,7 @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f,
g_assert_not_reached();
}
- if (unlikely(floatx80_invalid_encoding(f))) {
+ if (unlikely(floatx80_invalid_encoding(f, s))) {
float_raise(float_flag_invalid, s);
return false;
}
@@ -1817,6 +1832,7 @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p,
switch (p->cls) {
case float_class_normal:
+ case float_class_denormal:
if (s->floatx80_rounding_precision == floatx80_precision_x) {
parts_uncanon_normal(p, s, fmt);
frac = p->frac_hi;
@@ -1838,7 +1854,8 @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p,
case float_class_inf:
/* x86 and m68k differ in the setting of the integer bit. */
- frac = floatx80_infinity_low;
+ frac = s->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero ?
+ 0 : (1ULL << 63);
exp = fmt->exp_max;
break;
@@ -2696,6 +2713,9 @@ static void parts_float_to_ahp(FloatParts64 *a, float_status *s)
float16_params_ahp.frac_size + 1);
break;
+ case float_class_denormal:
+ float_raise(float_flag_input_denormal_used, s);
+ break;
case float_class_normal:
case float_class_zero:
break;
@@ -2710,6 +2730,9 @@ static void parts64_float_to_float(FloatParts64 *a, float_status *s)
if (is_nan(a->cls)) {
parts_return_nan(a, s);
}
+ if (a->cls == float_class_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
}
static void parts128_float_to_float(FloatParts128 *a, float_status *s)
@@ -2717,6 +2740,9 @@ static void parts128_float_to_float(FloatParts128 *a, float_status *s)
if (is_nan(a->cls)) {
parts_return_nan(a, s);
}
+ if (a->cls == float_class_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
}
#define parts_float_to_float(P, S) \
@@ -2729,12 +2755,21 @@ static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b,
a->sign = b->sign;
a->exp = b->exp;
- if (a->cls == float_class_normal) {
+ switch (a->cls) {
+ case float_class_denormal:
+ float_raise(float_flag_input_denormal_used, s);
+ /* fall through */
+ case float_class_normal:
frac_truncjam(a, b);
- } else if (is_nan(a->cls)) {
+ break;
+ case float_class_snan:
+ case float_class_qnan:
/* Discard the low bits of the NaN. */
a->frac = b->frac_hi;
parts_return_nan(a, s);
+ break;
+ default:
+ break;
}
}
@@ -2749,6 +2784,9 @@ static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b,
if (is_nan(a->cls)) {
parts_return_nan(a, s);
}
+ if (a->cls == float_class_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
}
float32 float16_to_float32(float16 a, bool ieee, float_status *s)
@@ -3218,6 +3256,7 @@ static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode,
return int128_zero();
case float_class_normal:
+ case float_class_denormal:
if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) {
flags = float_flag_inexact;
}
@@ -3645,6 +3684,7 @@ static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode,
return int128_zero();
case float_class_normal:
+ case float_class_denormal:
if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) {
flags = float_flag_inexact;
if (p.cls == float_class_zero) {
@@ -4386,7 +4426,11 @@ float32_hs_compare(float32 xa, float32 xb, float_status *s, bool is_quiet)
goto soft;
}
- float32_input_flush2(&ua.s, &ub.s, s);
+ if (unlikely(float32_is_denormal(ua.s) || float32_is_denormal(ub.s))) {
+ /* We may need to set the input_denormal_used flag */
+ goto soft;
+ }
+
if (isgreaterequal(ua.h, ub.h)) {
if (isgreater(ua.h, ub.h)) {
return float_relation_greater;
@@ -4436,7 +4480,11 @@ float64_hs_compare(float64 xa, float64 xb, float_status *s, bool is_quiet)
goto soft;
}
- float64_input_flush2(&ua.s, &ub.s, s);
+ if (unlikely(float64_is_denormal(ua.s) || float64_is_denormal(ub.s))) {
+ /* We may need to set the input_denormal_used flag */
+ goto soft;
+ }
+
if (isgreaterequal(ua.h, ub.h)) {
if (isgreater(ua.h, ub.h)) {
return float_relation_greater;
@@ -4848,7 +4896,7 @@ float128 float128_silence_nan(float128 a, float_status *status)
static bool parts_squash_denormal(FloatParts64 p, float_status *status)
{
if (p.exp == 0 && p.frac != 0) {
- float_raise(float_flag_input_denormal, status);
+ float_raise(float_flag_input_denormal_flushed, status);
return true;
}
@@ -5017,7 +5065,7 @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign,
}
if ( zExp <= 0 ) {
if (status->flush_to_zero) {
- float_raise(float_flag_output_denormal, status);
+ float_raise(float_flag_output_denormal_flushed, status);
return packFloatx80(zSign, 0, 0);
}
isTiny = status->tininess_before_rounding
@@ -5091,9 +5139,7 @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign,
) {
return packFloatx80( zSign, 0x7FFE, ~ roundMask );
}
- return packFloatx80(zSign,
- floatx80_infinity_high,
- floatx80_infinity_low);
+ return floatx80_default_inf(zSign, status);
}
if ( zExp <= 0 ) {
isTiny = status->tininess_before_rounding
@@ -5231,6 +5277,8 @@ float32 float32_exp2(float32 a, float_status *status)
float32_unpack_canonical(&xp, a, status);
if (unlikely(xp.cls != float_class_normal)) {
switch (xp.cls) {
+ case float_class_denormal:
+ break;
case float_class_snan:
case float_class_qnan:
parts_return_nan(&xp, status);
@@ -5240,9 +5288,8 @@ float32 float32_exp2(float32 a, float_status *status)
case float_class_zero:
return float32_one;
default:
- break;
+ g_assert_not_reached();
}
- g_assert_not_reached();
}
float_raise(float_flag_inexact, status);