summaryrefslogtreecommitdiffstats
path: root/fpu/softfloat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fpu/softfloat.c')
-rw-r--r--fpu/softfloat.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 33abc8207b..67cfa0fd82 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -554,6 +554,10 @@ static const FloatFmt float16_params_ahp = {
.arm_althp = true
};
+static const FloatFmt bfloat16_params = {
+ FLOAT_PARAMS(8, 7)
+};
+
static const FloatFmt float32_params = {
FLOAT_PARAMS(8, 23)
};
@@ -580,6 +584,11 @@ static inline FloatParts float16_unpack_raw(float16 f)
return unpack_raw(float16_params, f);
}
+static inline FloatParts bfloat16_unpack_raw(bfloat16 f)
+{
+ return unpack_raw(bfloat16_params, f);
+}
+
static inline FloatParts float32_unpack_raw(float32 f)
{
return unpack_raw(float32_params, f);
@@ -603,6 +612,11 @@ static inline float16 float16_pack_raw(FloatParts p)
return make_float16(pack_raw(float16_params, p));
}
+static inline bfloat16 bfloat16_pack_raw(FloatParts p)
+{
+ return pack_raw(bfloat16_params, p);
+}
+
static inline float32 float32_pack_raw(FloatParts p)
{
return make_float32(pack_raw(float32_params, p));
@@ -820,6 +834,11 @@ static FloatParts float16_unpack_canonical(float16 f, float_status *s)
return float16a_unpack_canonical(f, s, &float16_params);
}
+static FloatParts bfloat16_unpack_canonical(bfloat16 f, float_status *s)
+{
+ return sf_canonicalize(bfloat16_unpack_raw(f), &bfloat16_params, s);
+}
+
static float16 float16a_round_pack_canonical(FloatParts p, float_status *s,
const FloatFmt *params)
{
@@ -831,6 +850,11 @@ static float16 float16_round_pack_canonical(FloatParts p, float_status *s)
return float16a_round_pack_canonical(p, s, &float16_params);
}
+static bfloat16 bfloat16_round_pack_canonical(FloatParts p, float_status *s)
+{
+ return bfloat16_pack_raw(round_canonical(p, s, &bfloat16_params));
+}
+
static FloatParts float32_unpack_canonical(float32 f, float_status *s)
{
return sf_canonicalize(float32_unpack_raw(f), &float32_params, s);
@@ -1159,6 +1183,28 @@ float64_sub(float64 a, float64 b, float_status *s)
}
/*
+ * Returns the result of adding or subtracting the bfloat16
+ * values `a' and `b'.
+ */
+bfloat16 QEMU_FLATTEN bfloat16_add(bfloat16 a, bfloat16 b, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pb = bfloat16_unpack_canonical(b, status);
+ FloatParts pr = addsub_floats(pa, pb, false, status);
+
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
+bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pb = bfloat16_unpack_canonical(b, status);
+ FloatParts pr = addsub_floats(pa, pb, true, status);
+
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
+/*
* Returns the result of multiplying the floating-point values `a' and
* `b'. The operation is performed according to the IEC/IEEE Standard
* for Binary Floating-Point Arithmetic.
@@ -1261,6 +1307,20 @@ float64_mul(float64 a, float64 b, float_status *s)
}
/*
+ * Returns the result of multiplying the bfloat16
+ * values `a' and `b'.
+ */
+
+bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pb = bfloat16_unpack_canonical(b, status);
+ FloatParts pr = mul_floats(pa, pb, status);
+
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
+/*
* Returns the result of multiplying the floating-point values `a' and
* `b' then adding 'c', with no intermediate rounding step after the
* multiplication. The operation is performed according to the
@@ -1643,6 +1703,23 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
}
/*
+ * Returns the result of multiplying the bfloat16 values `a'
+ * and `b' then adding 'c', with no intermediate rounding step after the
+ * multiplication.
+ */
+
+bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c,
+ int flags, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pb = bfloat16_unpack_canonical(b, status);
+ FloatParts pc = bfloat16_unpack_canonical(c, status);
+ FloatParts pr = muladd_floats(pa, pb, pc, flags, status);
+
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
+/*
* Returns the result of dividing the floating-point value `a' by the
* corresponding value `b'. The operation is performed according to
* the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -1809,6 +1886,20 @@ float64_div(float64 a, float64 b, float_status *s)
}
/*
+ * Returns the result of dividing the bfloat16
+ * value `a' by the corresponding value `b'.
+ */
+
+bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pb = bfloat16_unpack_canonical(b, status);
+ FloatParts pr = div_floats(pa, pb, status);
+
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
+/*
* Float to Float conversions
*
* Returns the result of converting one float format to another. The
@@ -1923,6 +2014,34 @@ float32 float64_to_float32(float64 a, float_status *s)
return float32_round_pack_canonical(pr, s);
}
+float32 bfloat16_to_float32(bfloat16 a, float_status *s)
+{
+ FloatParts p = bfloat16_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, &float32_params, s);
+ return float32_round_pack_canonical(pr, s);
+}
+
+float64 bfloat16_to_float64(bfloat16 a, float_status *s)
+{
+ FloatParts p = bfloat16_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, &float64_params, s);
+ return float64_round_pack_canonical(pr, s);
+}
+
+bfloat16 float32_to_bfloat16(float32 a, float_status *s)
+{
+ FloatParts p = float32_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, &bfloat16_params, s);
+ return bfloat16_round_pack_canonical(pr, s);
+}
+
+bfloat16 float64_to_bfloat16(float64 a, float_status *s)
+{
+ FloatParts p = float64_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, &bfloat16_params, s);
+ return bfloat16_round_pack_canonical(pr, s);
+}
+
/*
* Rounds the floating-point value `a' to an integer, and returns the
* result as a floating-point value. The operation is performed
@@ -2053,6 +2172,18 @@ float64 float64_round_to_int(float64 a, float_status *s)
}
/*
+ * Rounds the bfloat16 value `a' to an integer, and returns the
+ * result as a bfloat16 value.
+ */
+
+bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
+ return bfloat16_round_pack_canonical(pr, s);
+}
+
+/*
* Returns the result of converting the floating-point value `a' to
* the two's complement integer format. The conversion is performed
* according to the IEC/IEEE Standard for Binary Floating-Point
@@ -2109,6 +2240,13 @@ static int64_t round_to_int_and_pack(FloatParts in, FloatRoundMode rmode,
}
}
+int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT8_MIN, INT8_MAX, s);
+}
+
int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
@@ -2172,6 +2310,11 @@ int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale,
rmode, scale, INT64_MIN, INT64_MAX, s);
}
+int8_t float16_to_int8(float16 a, float_status *s)
+{
+ return float16_to_int8_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
int16_t float16_to_int16(float16 a, float_status *s)
{
return float16_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
@@ -2263,6 +2406,62 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *s)
}
/*
+ * Returns the result of converting the floating-point value `a' to
+ * the two's complement integer format.
+ */
+
+int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(bfloat16_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(bfloat16_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(bfloat16_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t bfloat16_to_int16(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t bfloat16_to_int32(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t bfloat16_to_int64(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t bfloat16_to_int16_round_to_zero(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int32_t bfloat16_to_int32_round_to_zero(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_int32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int64_t bfloat16_to_int64_round_to_zero(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_int64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+/*
* Returns the result of converting the floating-point value `a' to
* the unsigned integer format. The conversion is performed according
* to the IEC/IEEE Standard for Binary Floating-Point
@@ -2322,6 +2521,13 @@ static uint64_t round_to_uint_and_pack(FloatParts in, FloatRoundMode rmode,
}
}
+uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT8_MAX, s);
+}
+
uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
@@ -2385,6 +2591,11 @@ uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale,
rmode, scale, UINT64_MAX, s);
}
+uint8_t float16_to_uint8(float16 a, float_status *s)
+{
+ return float16_to_uint8_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
uint16_t float16_to_uint16(float16 a, float_status *s)
{
return float16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
@@ -2476,6 +2687,62 @@ uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s)
}
/*
+ * Returns the result of converting the bfloat16 value `a' to
+ * the unsigned integer format.
+ */
+
+uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode rmode,
+ int scale, float_status *s)
+{
+ return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode rmode,
+ int scale, float_status *s)
+{
+ return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
+}
+
+uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode,
+ int scale, float_status *s)
+{
+ return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t bfloat16_to_uint16(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint32_t bfloat16_to_uint32(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint64_t bfloat16_to_uint64(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint16_t bfloat16_to_uint16_round_to_zero(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint32_t bfloat16_to_uint32_round_to_zero(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t bfloat16_to_uint64_round_to_zero(bfloat16 a, float_status *s)
+{
+ return bfloat16_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+/*
* Integer to float conversions
*
* Returns the result of converting the two's complement integer `a'
@@ -2539,6 +2806,11 @@ float16 int16_to_float16(int16_t a, float_status *status)
return int64_to_float16_scalbn(a, 0, status);
}
+float16 int8_to_float16(int8_t a, float_status *status)
+{
+ return int64_to_float16_scalbn(a, 0, status);
+}
+
float32 int64_to_float32_scalbn(int64_t a, int scale, float_status *status)
{
FloatParts pa = int_to_float(a, scale, status);
@@ -2601,6 +2873,41 @@ float64 int16_to_float64(int16_t a, float_status *status)
return int64_to_float64_scalbn(a, 0, status);
}
+/*
+ * Returns the result of converting the two's complement integer `a'
+ * to the bfloat16 format.
+ */
+
+bfloat16 int64_to_bfloat16_scalbn(int64_t a, int scale, float_status *status)
+{
+ FloatParts pa = int_to_float(a, scale, status);
+ return bfloat16_round_pack_canonical(pa, status);
+}
+
+bfloat16 int32_to_bfloat16_scalbn(int32_t a, int scale, float_status *status)
+{
+ return int64_to_bfloat16_scalbn(a, scale, status);
+}
+
+bfloat16 int16_to_bfloat16_scalbn(int16_t a, int scale, float_status *status)
+{
+ return int64_to_bfloat16_scalbn(a, scale, status);
+}
+
+bfloat16 int64_to_bfloat16(int64_t a, float_status *status)
+{
+ return int64_to_bfloat16_scalbn(a, 0, status);
+}
+
+bfloat16 int32_to_bfloat16(int32_t a, float_status *status)
+{
+ return int64_to_bfloat16_scalbn(a, 0, status);
+}
+
+bfloat16 int16_to_bfloat16(int16_t a, float_status *status)
+{
+ return int64_to_bfloat16_scalbn(a, 0, status);
+}
/*
* Unsigned Integer to float conversions
@@ -2664,6 +2971,11 @@ float16 uint16_to_float16(uint16_t a, float_status *status)
return uint64_to_float16_scalbn(a, 0, status);
}
+float16 uint8_to_float16(uint8_t a, float_status *status)
+{
+ return uint64_to_float16_scalbn(a, 0, status);
+}
+
float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status)
{
FloatParts pa = uint_to_float(a, scale, status);
@@ -2726,6 +3038,42 @@ float64 uint16_to_float64(uint16_t a, float_status *status)
return uint64_to_float64_scalbn(a, 0, status);
}
+/*
+ * Returns the result of converting the unsigned integer `a' to the
+ * bfloat16 format.
+ */
+
+bfloat16 uint64_to_bfloat16_scalbn(uint64_t a, int scale, float_status *status)
+{
+ FloatParts pa = uint_to_float(a, scale, status);
+ return bfloat16_round_pack_canonical(pa, status);
+}
+
+bfloat16 uint32_to_bfloat16_scalbn(uint32_t a, int scale, float_status *status)
+{
+ return uint64_to_bfloat16_scalbn(a, scale, status);
+}
+
+bfloat16 uint16_to_bfloat16_scalbn(uint16_t a, int scale, float_status *status)
+{
+ return uint64_to_bfloat16_scalbn(a, scale, status);
+}
+
+bfloat16 uint64_to_bfloat16(uint64_t a, float_status *status)
+{
+ return uint64_to_bfloat16_scalbn(a, 0, status);
+}
+
+bfloat16 uint32_to_bfloat16(uint32_t a, float_status *status)
+{
+ return uint64_to_bfloat16_scalbn(a, 0, status);
+}
+
+bfloat16 uint16_to_bfloat16(uint16_t a, float_status *status)
+{
+ return uint64_to_bfloat16_scalbn(a, 0, status);
+}
+
/* Float Min/Max */
/* min() and max() functions. These can't be implemented as
* 'compare and pick one input' because that would mishandle
@@ -2847,6 +3195,25 @@ MINMAX(64, maxnummag, false, true, true)
#undef MINMAX
+#define BF16_MINMAX(name, ismin, isiee, ismag) \
+bfloat16 bfloat16_ ## name(bfloat16 a, bfloat16 b, float_status *s) \
+{ \
+ FloatParts pa = bfloat16_unpack_canonical(a, s); \
+ FloatParts pb = bfloat16_unpack_canonical(b, s); \
+ FloatParts pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \
+ \
+ return bfloat16_round_pack_canonical(pr, s); \
+}
+
+BF16_MINMAX(min, true, false, false)
+BF16_MINMAX(minnum, true, true, false)
+BF16_MINMAX(minnummag, true, true, true)
+BF16_MINMAX(max, false, false, false)
+BF16_MINMAX(maxnum, false, true, false)
+BF16_MINMAX(maxnummag, false, true, true)
+
+#undef BF16_MINMAX
+
/* Floating point compare */
static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet,
float_status *s)
@@ -3008,6 +3375,24 @@ FloatRelation float64_compare_quiet(float64 a, float64 b, float_status *s)
return f64_compare(a, b, true, s);
}
+static FloatRelation QEMU_FLATTEN
+soft_bf16_compare(bfloat16 a, bfloat16 b, bool is_quiet, float_status *s)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, s);
+ FloatParts pb = bfloat16_unpack_canonical(b, s);
+ return compare_floats(pa, pb, is_quiet, s);
+}
+
+FloatRelation bfloat16_compare(bfloat16 a, bfloat16 b, float_status *s)
+{
+ return soft_bf16_compare(a, b, false, s);
+}
+
+FloatRelation bfloat16_compare_quiet(bfloat16 a, bfloat16 b, float_status *s)
+{
+ return soft_bf16_compare(a, b, true, s);
+}
+
/* Multiply A by 2 raised to the power N. */
static FloatParts scalbn_decomposed(FloatParts a, int n, float_status *s)
{
@@ -3047,6 +3432,13 @@ float64 float64_scalbn(float64 a, int n, float_status *status)
return float64_round_pack_canonical(pr, status);
}
+bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pr = scalbn_decomposed(pa, n, status);
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
/*
* Square Root
*
@@ -3197,6 +3589,13 @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s)
return soft_f64_sqrt(ua.s, s);
}
+bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status)
+{
+ FloatParts pa = bfloat16_unpack_canonical(a, status);
+ FloatParts pr = sqrt_float(pa, status, &bfloat16_params);
+ return bfloat16_round_pack_canonical(pr, status);
+}
+
/*----------------------------------------------------------------------------
| The pattern for a default generated NaN.
*----------------------------------------------------------------------------*/
@@ -3239,6 +3638,13 @@ float128 float128_default_nan(float_status *status)
return r;
}
+bfloat16 bfloat16_default_nan(float_status *status)
+{
+ FloatParts p = parts_default_nan(status);
+ p.frac >>= bfloat16_params.frac_shift;
+ return bfloat16_pack_raw(p);
+}
+
/*----------------------------------------------------------------------------
| Returns a quiet NaN from a signalling NaN for the floating point value `a'.
*----------------------------------------------------------------------------*/
@@ -3270,6 +3676,14 @@ float64 float64_silence_nan(float64 a, float_status *status)
return float64_pack_raw(p);
}
+bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status)
+{
+ FloatParts p = bfloat16_unpack_raw(a);
+ p.frac <<= bfloat16_params.frac_shift;
+ p = parts_silence_nan(p, status);
+ p.frac >>= bfloat16_params.frac_shift;
+ return bfloat16_pack_raw(p);
+}
/*----------------------------------------------------------------------------
| If `a' is denormal and we are in flush-to-zero mode then set the
@@ -3319,6 +3733,17 @@ float64 float64_squash_input_denormal(float64 a, float_status *status)
return a;
}
+bfloat16 bfloat16_squash_input_denormal(bfloat16 a, float_status *status)
+{
+ if (status->flush_inputs_to_zero) {
+ FloatParts p = bfloat16_unpack_raw(a);
+ if (parts_squash_denormal(p, status)) {
+ return bfloat16_set_sign(bfloat16_zero, p.sign);
+ }
+ }
+ return a;
+}
+
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
| and 7, and returns the properly rounded 32-bit integer corresponding to the