* float16 comparison wrappers

* float16 conversions to/from 8-bit integers
 * bfloat16 support
 -----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAl9LDyIdHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV81cgf/TI/O39OQ2pt+zpLN
 bU6PHBOXg1MgnGJmb7N8erSFtzv9O38umidgZvq0M2WHlYyW1bWlhKqUqJOCjLy6
 ykWII3S245XrcMZmbg3D79+GAnZJstKNiyVfeexxQDg1R58ne+OixZe2Xyyiw4VF
 Z3OrqAwsfigzZtMSILzsEG3ArhmPkR0NyUxrOmdtMfb8Pbk3k4c89LSZByRKkODb
 ajBMv+70aEu1MRO21KDN1rGzybp6Kkp7DHIbkpDtpzrLrpPW0Oob9WEnb+ozI+fU
 af3EBpblEBzO8NjSKGk7ttvQ3aH/17DPom+fJPnB1dz4fVM0uTL7m3lMUMX9JgLm
 1Fy9Vg==
 =MHCo
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/rth/tags/pull-sf-20200829' into staging

* float16 comparison wrappers
* float16 conversions to/from 8-bit integers
* bfloat16 support

# gpg: Signature made Sun 30 Aug 2020 03:29:54 BST
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A  05C0 64DF 38E8 AF7E 215F

* remotes/rth/tags/pull-sf-20200829:
  softfloat: Define comparison operations for bfloat16
  softfloat: Define misc operations for bfloat16
  softfloat: Define convert operations for bfloat16
  softfloat: Define operations for bfloat16
  softfloat: Add float16_is_normal
  softfloat: Add fp16 and uint8/int8 conversion functions
  softfloat: Implement the full set of comparisons for float16

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-08-30 14:01:25 +01:00
commit 4bc08c6141
5 changed files with 703 additions and 25 deletions

View File

@ -265,6 +265,25 @@ bool float16_is_quiet_nan(float16 a_, float_status *status)
}
}
/*----------------------------------------------------------------------------
| Returns 1 if the bfloat16 value `a' is a quiet
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
bool bfloat16_is_quiet_nan(bfloat16 a_, float_status *status)
{
if (no_signaling_nans(status)) {
return bfloat16_is_any_nan(a_);
} else {
uint16_t a = a_;
if (snan_bit_is_one(status)) {
return (((a >> 6) & 0x1FF) == 0x1FE) && (a & 0x3F);
} else {
return ((a >> 6) & 0x1FF) == 0x1FF;
}
}
}
/*----------------------------------------------------------------------------
| Returns 1 if the half-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
@ -284,6 +303,25 @@ bool float16_is_signaling_nan(float16 a_, float_status *status)
}
}
/*----------------------------------------------------------------------------
| Returns 1 if the bfloat16 value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
bool bfloat16_is_signaling_nan(bfloat16 a_, float_status *status)
{
if (no_signaling_nans(status)) {
return 0;
} else {
uint16_t a = a_;
if (snan_bit_is_one(status)) {
return ((a >> 6) & 0x1FF) == 0x1FF;
} else {
return (((a >> 6) & 0x1FF) == 0x1FE) && (a & 0x3F);
}
}
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.

View File

@ -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);
@ -1158,6 +1182,28 @@ float64_sub(float64 a, float64 b, float_status *s)
return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub);
}
/*
* 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
@ -1260,6 +1306,20 @@ float64_mul(float64 a, float64 b, float_status *s)
f64_is_zon2, f64_addsubmul_post);
}
/*
* 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
@ -1642,6 +1702,23 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
return soft_f64_muladd(ua.s, ub.s, uc.s, flags, 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
@ -1808,6 +1885,20 @@ float64_div(float64 a, float64 b, float_status *s)
f64_div_pre, f64_div_post);
}
/*
* 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
*
@ -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
@ -2052,6 +2171,18 @@ float64 float64_round_to_int(float64 a, float_status *s)
return float64_round_pack_canonical(pr, 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
@ -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);
@ -2262,6 +2405,62 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *s)
return float64_to_int64_scalbn(a, float_round_to_zero, 0, 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
@ -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);
@ -2475,6 +2686,62 @@ uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s)
return float64_to_uint64_scalbn(a, float_round_to_zero, 0, 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
*
@ -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

View File

@ -112,6 +112,11 @@ typedef struct {
#define make_float128(high_, low_) ((float128) { .high = high_, .low = low_ })
#define make_float128_init(high_, low_) { .high = high_, .low = low_ }
/*
* Software neural-network floating-point types.
*/
typedef uint16_t bfloat16;
/*
* Software IEC/IEEE floating-point underflow tininess-detection mode.
*/

View File

@ -109,6 +109,7 @@ void float_raise(uint8_t flags, float_status *status);
float16 float16_squash_input_denormal(float16 a, float_status *status);
float32 float32_squash_input_denormal(float32 a, float_status *status);
float64 float64_squash_input_denormal(float64 a, float_status *status);
bfloat16 bfloat16_squash_input_denormal(bfloat16 a, float_status *status);
/*----------------------------------------------------------------------------
| Options to indicate which negations to perform in float*_muladd()
@ -136,9 +137,11 @@ float16 uint16_to_float16_scalbn(uint16_t a, int, float_status *status);
float16 uint32_to_float16_scalbn(uint32_t a, int, float_status *status);
float16 uint64_to_float16_scalbn(uint64_t a, int, float_status *status);
float16 int8_to_float16(int8_t a, float_status *status);
float16 int16_to_float16(int16_t a, float_status *status);
float16 int32_to_float16(int32_t a, float_status *status);
float16 int64_to_float16(int64_t a, float_status *status);
float16 uint8_to_float16(uint8_t a, float_status *status);
float16 uint16_to_float16(uint16_t a, float_status *status);
float16 uint32_to_float16(uint32_t a, float_status *status);
float16 uint64_to_float16(uint64_t a, float_status *status);
@ -187,10 +190,13 @@ float32 float16_to_float32(float16, bool ieee, float_status *status);
float16 float64_to_float16(float64 a, bool ieee, float_status *status);
float64 float16_to_float64(float16 a, bool ieee, float_status *status);
int8_t float16_to_int8_scalbn(float16, FloatRoundMode, int,
float_status *status);
int16_t float16_to_int16_scalbn(float16, FloatRoundMode, int, float_status *);
int32_t float16_to_int32_scalbn(float16, FloatRoundMode, int, float_status *);
int64_t float16_to_int64_scalbn(float16, FloatRoundMode, int, float_status *);
int8_t float16_to_int8(float16, float_status *status);
int16_t float16_to_int16(float16, float_status *status);
int32_t float16_to_int32(float16, float_status *status);
int64_t float16_to_int64(float16, float_status *status);
@ -199,6 +205,8 @@ int16_t float16_to_int16_round_to_zero(float16, float_status *status);
int32_t float16_to_int32_round_to_zero(float16, float_status *status);
int64_t float16_to_int64_round_to_zero(float16, float_status *status);
uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode,
int, float_status *status);
uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode,
int, float_status *status);
uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode,
@ -206,6 +214,7 @@ uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode,
uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode,
int, float_status *status);
uint8_t float16_to_uint8(float16 a, float_status *status);
uint16_t float16_to_uint16(float16 a, float_status *status);
uint32_t float16_to_uint32(float16 a, float_status *status);
uint64_t float16_to_uint64(float16 a, float_status *status);
@ -264,6 +273,11 @@ static inline bool float16_is_zero_or_denormal(float16 a)
return (float16_val(a) & 0x7c00) == 0;
}
static inline bool float16_is_normal(float16 a)
{
return (((float16_val(a) >> 10) + 1) & 0x1f) >= 2;
}
static inline float16 float16_abs(float16 a)
{
/* Note that abs does *not* handle NaN specially, nor does
@ -285,6 +299,47 @@ static inline float16 float16_set_sign(float16 a, int sign)
return make_float16((float16_val(a) & 0x7fff) | (sign << 15));
}
static inline bool float16_eq(float16 a, float16 b, float_status *s)
{
return float16_compare(a, b, s) == float_relation_equal;
}
static inline bool float16_le(float16 a, float16 b, float_status *s)
{
return float16_compare(a, b, s) <= float_relation_equal;
}
static inline bool float16_lt(float16 a, float16 b, float_status *s)
{
return float16_compare(a, b, s) < float_relation_equal;
}
static inline bool float16_unordered(float16 a, float16 b, float_status *s)
{
return float16_compare(a, b, s) == float_relation_unordered;
}
static inline bool float16_eq_quiet(float16 a, float16 b, float_status *s)
{
return float16_compare_quiet(a, b, s) == float_relation_equal;
}
static inline bool float16_le_quiet(float16 a, float16 b, float_status *s)
{
return float16_compare_quiet(a, b, s) <= float_relation_equal;
}
static inline bool float16_lt_quiet(float16 a, float16 b, float_status *s)
{
return float16_compare_quiet(a, b, s) < float_relation_equal;
}
static inline bool float16_unordered_quiet(float16 a, float16 b,
float_status *s)
{
return float16_compare_quiet(a, b, s) == float_relation_unordered;
}
#define float16_zero make_float16(0)
#define float16_half make_float16(0x3800)
#define float16_one make_float16(0x3c00)
@ -293,6 +348,186 @@ static inline float16 float16_set_sign(float16 a, int sign)
#define float16_three make_float16(0x4200)
#define float16_infinity make_float16(0x7c00)
/*----------------------------------------------------------------------------
| Software bfloat16 conversion routines.
*----------------------------------------------------------------------------*/
bfloat16 bfloat16_round_to_int(bfloat16, float_status *status);
bfloat16 float32_to_bfloat16(float32, float_status *status);
float32 bfloat16_to_float32(bfloat16, float_status *status);
bfloat16 float64_to_bfloat16(float64 a, float_status *status);
float64 bfloat16_to_float64(bfloat16 a, float_status *status);
int16_t bfloat16_to_int16_scalbn(bfloat16, FloatRoundMode,
int, float_status *status);
int32_t bfloat16_to_int32_scalbn(bfloat16, FloatRoundMode,
int, float_status *status);
int64_t bfloat16_to_int64_scalbn(bfloat16, FloatRoundMode,
int, float_status *status);
int16_t bfloat16_to_int16(bfloat16, float_status *status);
int32_t bfloat16_to_int32(bfloat16, float_status *status);
int64_t bfloat16_to_int64(bfloat16, float_status *status);
int16_t bfloat16_to_int16_round_to_zero(bfloat16, float_status *status);
int32_t bfloat16_to_int32_round_to_zero(bfloat16, float_status *status);
int64_t bfloat16_to_int64_round_to_zero(bfloat16, float_status *status);
uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode,
int, float_status *status);
uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode,
int, float_status *status);
uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode,
int, float_status *status);
uint16_t bfloat16_to_uint16(bfloat16 a, float_status *status);
uint32_t bfloat16_to_uint32(bfloat16 a, float_status *status);
uint64_t bfloat16_to_uint64(bfloat16 a, float_status *status);
uint16_t bfloat16_to_uint16_round_to_zero(bfloat16 a, float_status *status);
uint32_t bfloat16_to_uint32_round_to_zero(bfloat16 a, float_status *status);
uint64_t bfloat16_to_uint64_round_to_zero(bfloat16 a, float_status *status);
bfloat16 int16_to_bfloat16_scalbn(int16_t a, int, float_status *status);
bfloat16 int32_to_bfloat16_scalbn(int32_t a, int, float_status *status);
bfloat16 int64_to_bfloat16_scalbn(int64_t a, int, float_status *status);
bfloat16 uint16_to_bfloat16_scalbn(uint16_t a, int, float_status *status);
bfloat16 uint32_to_bfloat16_scalbn(uint32_t a, int, float_status *status);
bfloat16 uint64_to_bfloat16_scalbn(uint64_t a, int, float_status *status);
bfloat16 int16_to_bfloat16(int16_t a, float_status *status);
bfloat16 int32_to_bfloat16(int32_t a, float_status *status);
bfloat16 int64_to_bfloat16(int64_t a, float_status *status);
bfloat16 uint16_to_bfloat16(uint16_t a, float_status *status);
bfloat16 uint32_to_bfloat16(uint32_t a, float_status *status);
bfloat16 uint64_to_bfloat16(uint64_t a, float_status *status);
/*----------------------------------------------------------------------------
| Software bfloat16 operations.
*----------------------------------------------------------------------------*/
bfloat16 bfloat16_add(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_sub(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_mul(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_div(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_muladd(bfloat16, bfloat16, bfloat16, int,
float_status *status);
float16 bfloat16_scalbn(bfloat16, int, float_status *status);
bfloat16 bfloat16_min(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_max(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_minnum(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maxnum(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_minnummag(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maxnummag(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_sqrt(bfloat16, float_status *status);
FloatRelation bfloat16_compare(bfloat16, bfloat16, float_status *status);
FloatRelation bfloat16_compare_quiet(bfloat16, bfloat16, float_status *status);
bool bfloat16_is_quiet_nan(bfloat16, float_status *status);
bool bfloat16_is_signaling_nan(bfloat16, float_status *status);
bfloat16 bfloat16_silence_nan(bfloat16, float_status *status);
bfloat16 bfloat16_default_nan(float_status *status);
static inline bool bfloat16_is_any_nan(bfloat16 a)
{
return ((a & ~0x8000) > 0x7F80);
}
static inline bool bfloat16_is_neg(bfloat16 a)
{
return a >> 15;
}
static inline bool bfloat16_is_infinity(bfloat16 a)
{
return (a & 0x7fff) == 0x7F80;
}
static inline bool bfloat16_is_zero(bfloat16 a)
{
return (a & 0x7fff) == 0;
}
static inline bool bfloat16_is_zero_or_denormal(bfloat16 a)
{
return (a & 0x7F80) == 0;
}
static inline bool bfloat16_is_normal(bfloat16 a)
{
return (((a >> 7) + 1) & 0xff) >= 2;
}
static inline bfloat16 bfloat16_abs(bfloat16 a)
{
/* Note that abs does *not* handle NaN specially, nor does
* it flush denormal inputs to zero.
*/
return a & 0x7fff;
}
static inline bfloat16 bfloat16_chs(bfloat16 a)
{
/* Note that chs does *not* handle NaN specially, nor does
* it flush denormal inputs to zero.
*/
return a ^ 0x8000;
}
static inline bfloat16 bfloat16_set_sign(bfloat16 a, int sign)
{
return (a & 0x7fff) | (sign << 15);
}
static inline bool bfloat16_eq(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare(a, b, s) == float_relation_equal;
}
static inline bool bfloat16_le(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare(a, b, s) <= float_relation_equal;
}
static inline bool bfloat16_lt(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare(a, b, s) < float_relation_equal;
}
static inline bool bfloat16_unordered(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare(a, b, s) == float_relation_unordered;
}
static inline bool bfloat16_eq_quiet(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare_quiet(a, b, s) == float_relation_equal;
}
static inline bool bfloat16_le_quiet(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare_quiet(a, b, s) <= float_relation_equal;
}
static inline bool bfloat16_lt_quiet(bfloat16 a, bfloat16 b, float_status *s)
{
return bfloat16_compare_quiet(a, b, s) < float_relation_equal;
}
static inline bool bfloat16_unordered_quiet(bfloat16 a, bfloat16 b,
float_status *s)
{
return bfloat16_compare_quiet(a, b, s) == float_relation_unordered;
}
#define bfloat16_zero 0
#define bfloat16_half 0x3f00
#define bfloat16_one 0x3f80
#define bfloat16_one_point_five 0x3fc0
#define bfloat16_two 0x4000
#define bfloat16_three 0x4040
#define bfloat16_infinity 0x7f80
/*----------------------------------------------------------------------------
| The pattern for a default generated half-precision NaN.
*----------------------------------------------------------------------------*/

View File

@ -3955,12 +3955,6 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
} \
}
static bool float16_eq_quiet(uint16_t a, uint16_t b, float_status *s)
{
FloatRelation compare = float16_compare_quiet(a, b, s);
return compare == float_relation_equal;
}
GEN_VEXT_CMP_VV_ENV(vmfeq_vv_h, uint16_t, H2, float16_eq_quiet)
GEN_VEXT_CMP_VV_ENV(vmfeq_vv_w, uint32_t, H4, float32_eq_quiet)
GEN_VEXT_CMP_VV_ENV(vmfeq_vv_d, uint64_t, H8, float64_eq_quiet)
@ -4017,12 +4011,6 @@ GEN_VEXT_CMP_VF(vmfne_vf_h, uint16_t, H2, vmfne16)
GEN_VEXT_CMP_VF(vmfne_vf_w, uint32_t, H4, vmfne32)
GEN_VEXT_CMP_VF(vmfne_vf_d, uint64_t, H8, vmfne64)
static bool float16_lt(uint16_t a, uint16_t b, float_status *s)
{
FloatRelation compare = float16_compare(a, b, s);
return compare == float_relation_less;
}
GEN_VEXT_CMP_VV_ENV(vmflt_vv_h, uint16_t, H2, float16_lt)
GEN_VEXT_CMP_VV_ENV(vmflt_vv_w, uint32_t, H4, float32_lt)
GEN_VEXT_CMP_VV_ENV(vmflt_vv_d, uint64_t, H8, float64_lt)
@ -4030,13 +4018,6 @@ GEN_VEXT_CMP_VF(vmflt_vf_h, uint16_t, H2, float16_lt)
GEN_VEXT_CMP_VF(vmflt_vf_w, uint32_t, H4, float32_lt)
GEN_VEXT_CMP_VF(vmflt_vf_d, uint64_t, H8, float64_lt)
static bool float16_le(uint16_t a, uint16_t b, float_status *s)
{
FloatRelation compare = float16_compare(a, b, s);
return compare == float_relation_less ||
compare == float_relation_equal;
}
GEN_VEXT_CMP_VV_ENV(vmfle_vv_h, uint16_t, H2, float16_le)
GEN_VEXT_CMP_VV_ENV(vmfle_vv_w, uint32_t, H4, float32_le)
GEN_VEXT_CMP_VV_ENV(vmfle_vv_d, uint64_t, H8, float64_le)
@ -4091,12 +4072,6 @@ GEN_VEXT_CMP_VF(vmfge_vf_h, uint16_t, H2, vmfge16)
GEN_VEXT_CMP_VF(vmfge_vf_w, uint32_t, H4, vmfge32)
GEN_VEXT_CMP_VF(vmfge_vf_d, uint64_t, H8, vmfge64)
static bool float16_unordered_quiet(uint16_t a, uint16_t b, float_status *s)
{
FloatRelation compare = float16_compare_quiet(a, b, s);
return compare == float_relation_unordered;
}
GEN_VEXT_CMP_VV_ENV(vmford_vv_h, uint16_t, H2, !float16_unordered_quiet)
GEN_VEXT_CMP_VV_ENV(vmford_vv_w, uint32_t, H4, !float32_unordered_quiet)
GEN_VEXT_CMP_VV_ENV(vmford_vv_d, uint64_t, H8, !float64_unordered_quiet)