Roundup of softfloat patches

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJa/gW0AAoJEGTfOOivfiFf58AIAJsxICtvJlT7ianTTMZ0zlib
 q5aJ77Exwrg4/tEOmPffOQXMEKpvNHzK7lnzTQK7S9lyvuKkrCk/ubg2oLPwYMUo
 uoclSJvix6BCuodfDR8iMCpcyjDWlyCricKN+NEsZXCvPRLkEuLjQHOE816OtAzD
 3ndCBe+tW2IqNYIxA3p97sELz6CZ5yuXX2OreK+SpiS+4dM8MYM2nUbUWTNBFr/0
 hMrI72dFCEj0hqGaX0DzR3a4orhZ1bTkyRn/yFa/r2B3pLaKOBmu8fgRug7bhymG
 PuedxOUjf5rrQti2nqxIAzUZGaagj2nnkv/5yqUtcNceIRrys07u0JmA/nvoMVI=
 =YHC0
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/rth/tags/pull-fpu-20180517' into staging

Roundup of softfloat patches

# gpg: Signature made Thu 17 May 2018 23:44:04 BST
# gpg:                using RSA key 64DF38E8AF7E215F
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>"
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A  05C0 64DF 38E8 AF7E 215F

* remotes/rth/tags/pull-fpu-20180517: (28 commits)
  fpu/softfloat: Define floatN_silence_nan in terms of parts_silence_nan
  fpu/softfloat: Clean up parts_default_nan
  fpu/softfloat: Define floatN_default_nan in terms of parts_default_nan
  fpu/softfloat: Pass FloatClass to pickNaNMulAdd
  fpu/softfloat: Pass FloatClass to pickNaN
  fpu/softfloat: Make is_nan et al available to softfloat-specialize.h
  fpu/softfloat: Specialize on snan_bit_is_one
  fpu/softfloat: Remove floatX_maybe_silence_nan
  fpu/softfloat: Use float*_silence_nan in propagateFloat*NaN
  target/s390x: Remove floatX_maybe_silence_nan from conversions
  target/riscv: Remove floatX_maybe_silence_nan from conversions
  target/mips: Remove floatX_maybe_silence_nan from conversions
  target/m68k: Use floatX_silence_nan when we have already checked for SNaN
  target/hppa: Remove floatX_maybe_silence_nan from conversions
  target/arm: Remove floatX_maybe_silence_nan from conversions
  target/arm: Use floatX_silence_nan when we have already checked for SNaN
  fpu/softfloat: re-factor float to float conversions
  fpu/softfloat: Partial support for ARM Alternative half-precision
  target/arm: squash FZ16 behaviour for conversions
  target/arm: convert conversion helpers to fpst/ahp_flag
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-05-18 10:16:24 +01:00
commit 6812994826
20 changed files with 718 additions and 1006 deletions

File diff suppressed because it is too large Load Diff

View File

@ -95,16 +95,6 @@ this code that are retained.
*----------------------------------------------------------------------------*/
#include "fpu/softfloat-macros.h"
/*----------------------------------------------------------------------------
| Functions and definitions to determine: (1) whether tininess for underflow
| is detected before or after rounding by default, (2) what (if anything)
| happens when exceptions are raised, (3) how signaling NaNs are distinguished
| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
| are propagated from function inputs to output. These details are target-
| specific.
*----------------------------------------------------------------------------*/
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Returns the fraction bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
@ -123,15 +113,6 @@ static inline int extractFloat16Exp(float16 a)
return (float16_val(a) >> 10) & 0x1f;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
static inline flag extractFloat16Sign(float16 a)
{
return float16_val(a)>>15;
}
/*----------------------------------------------------------------------------
| Returns the fraction bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
@ -198,10 +179,24 @@ typedef enum __attribute__ ((__packed__)) {
float_class_inf,
float_class_qnan, /* all NaNs from here */
float_class_snan,
float_class_dnan,
float_class_msnan, /* maybe silenced */
} FloatClass;
/* Simple helpers for checking if, or what kind of, NaN we have */
static inline __attribute__((unused)) bool is_nan(FloatClass c)
{
return unlikely(c >= float_class_qnan);
}
static inline __attribute__((unused)) bool is_snan(FloatClass c)
{
return c == float_class_snan;
}
static inline __attribute__((unused)) bool is_qnan(FloatClass c)
{
return c == float_class_qnan;
}
/*
* Structure holding all of the decomposed parts of a float. The
* exponent is unbiased and the fraction is normalized. All
@ -232,8 +227,10 @@ typedef struct {
* frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT
* The following are computed based the size of fraction
* frac_lsb: least significant bit of fraction
* fram_lsbm1: the bit bellow the least significant bit (for rounding)
* frac_lsbm1: the bit below the least significant bit (for rounding)
* round_mask/roundeven_mask: masks used for rounding
* The following optional modifiers are available:
* arm_althp: handle ARM Alternative Half Precision
*/
typedef struct {
int exp_size;
@ -245,6 +242,7 @@ typedef struct {
uint64_t frac_lsbm1;
uint64_t round_mask;
uint64_t roundeven_mask;
bool arm_althp;
} FloatFmt;
/* Expand fields based on the size of exponent and fraction */
@ -263,6 +261,11 @@ static const FloatFmt float16_params = {
FLOAT_PARAMS(5, 10)
};
static const FloatFmt float16_params_ahp = {
FLOAT_PARAMS(5, 10),
.arm_althp = true
};
static const FloatFmt float32_params = {
FLOAT_PARAMS(8, 23)
};
@ -322,24 +325,27 @@ static inline float64 float64_pack_raw(FloatParts p)
return make_float64(pack_raw(float64_params, p));
}
/*----------------------------------------------------------------------------
| Functions and definitions to determine: (1) whether tininess for underflow
| is detected before or after rounding by default, (2) what (if anything)
| happens when exceptions are raised, (3) how signaling NaNs are distinguished
| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
| are propagated from function inputs to output. These details are target-
| specific.
*----------------------------------------------------------------------------*/
#include "softfloat-specialize.h"
/* Canonicalize EXP and FRAC, setting CLS. */
static FloatParts canonicalize(FloatParts part, const FloatFmt *parm,
float_status *status)
{
if (part.exp == parm->exp_max) {
if (part.exp == parm->exp_max && !parm->arm_althp) {
if (part.frac == 0) {
part.cls = float_class_inf;
} else {
#ifdef NO_SIGNALING_NANS
part.cls = float_class_qnan;
#else
int64_t msb = part.frac << (parm->frac_shift + 2);
if ((msb < 0) == status->snan_bit_is_one) {
part.cls = float_class_snan;
} else {
part.cls = float_class_qnan;
}
#endif
part.frac <<= parm->frac_shift;
part.cls = (parts_is_snan_frac(part.frac, status)
? float_class_snan : float_class_qnan);
}
} else if (part.exp == 0) {
if (likely(part.frac == 0)) {
@ -422,7 +428,15 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
}
frac >>= frac_shift;
if (unlikely(exp >= exp_max)) {
if (parm->arm_althp) {
/* ARM Alt HP eschews Inf and NaN for a wider exponent. */
if (unlikely(exp > exp_max)) {
/* Overflow. Return the maximum normal. */
flags = float_flag_invalid;
exp = exp_max;
frac = -1;
}
} else if (unlikely(exp >= exp_max)) {
flags |= float_flag_overflow | float_flag_inexact;
if (overflow_norm) {
exp = exp_max - 1;
@ -473,13 +487,16 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
case float_class_inf:
do_inf:
assert(!parm->arm_althp);
exp = exp_max;
frac = 0;
break;
case float_class_qnan:
case float_class_snan:
assert(!parm->arm_althp);
exp = exp_max;
frac >>= parm->frac_shift;
break;
default:
@ -492,22 +509,27 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
return p;
}
/* Explicit FloatFmt version */
static FloatParts float16a_unpack_canonical(float16 f, float_status *s,
const FloatFmt *params)
{
return canonicalize(float16_unpack_raw(f), params, s);
}
static FloatParts float16_unpack_canonical(float16 f, float_status *s)
{
return canonicalize(float16_unpack_raw(f), &float16_params, s);
return float16a_unpack_canonical(f, s, &float16_params);
}
static float16 float16a_round_pack_canonical(FloatParts p, float_status *s,
const FloatFmt *params)
{
return float16_pack_raw(round_canonical(p, s, params));
}
static float16 float16_round_pack_canonical(FloatParts p, float_status *s)
{
switch (p.cls) {
case float_class_dnan:
return float16_default_nan(s);
case float_class_msnan:
return float16_maybe_silence_nan(float16_pack_raw(p), s);
default:
p = round_canonical(p, s, &float16_params);
return float16_pack_raw(p);
}
return float16a_round_pack_canonical(p, s, &float16_params);
}
static FloatParts float32_unpack_canonical(float32 f, float_status *s)
@ -517,15 +539,7 @@ static FloatParts float32_unpack_canonical(float32 f, float_status *s)
static float32 float32_round_pack_canonical(FloatParts p, float_status *s)
{
switch (p.cls) {
case float_class_dnan:
return float32_default_nan(s);
case float_class_msnan:
return float32_maybe_silence_nan(float32_pack_raw(p), s);
default:
p = round_canonical(p, s, &float32_params);
return float32_pack_raw(p);
}
return float32_pack_raw(round_canonical(p, s, &float32_params));
}
static FloatParts float64_unpack_canonical(float64 f, float_status *s)
@ -535,29 +549,7 @@ static FloatParts float64_unpack_canonical(float64 f, float_status *s)
static float64 float64_round_pack_canonical(FloatParts p, float_status *s)
{
switch (p.cls) {
case float_class_dnan:
return float64_default_nan(s);
case float_class_msnan:
return float64_maybe_silence_nan(float64_pack_raw(p), s);
default:
p = round_canonical(p, s, &float64_params);
return float64_pack_raw(p);
}
}
/* Simple helpers for checking if what NaN we have */
static bool is_nan(FloatClass c)
{
return unlikely(c >= float_class_qnan);
}
static bool is_snan(FloatClass c)
{
return c == float_class_snan;
}
static bool is_qnan(FloatClass c)
{
return c == float_class_qnan;
return float64_pack_raw(round_canonical(p, s, &float64_params));
}
static FloatParts return_nan(FloatParts a, float_status *s)
@ -565,11 +557,11 @@ static FloatParts return_nan(FloatParts a, float_status *s)
switch (a.cls) {
case float_class_snan:
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_msnan;
a = parts_silence_nan(a, s);
/* fall through */
case float_class_qnan:
if (s->default_nan_mode) {
a.cls = float_class_dnan;
return parts_default_nan(s);
}
break;
@ -586,15 +578,16 @@ static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s)
}
if (s->default_nan_mode) {
a.cls = float_class_dnan;
return parts_default_nan(s);
} else {
if (pickNaN(is_qnan(a.cls), is_snan(a.cls),
is_qnan(b.cls), is_snan(b.cls),
if (pickNaN(a.cls, b.cls,
a.frac > b.frac ||
(a.frac == b.frac && a.sign < b.sign))) {
a = b;
}
a.cls = float_class_msnan;
if (is_snan(a.cls)) {
return parts_silence_nan(a, s);
}
}
return a;
}
@ -608,17 +601,13 @@ static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c,
s->float_exception_flags |= float_flag_invalid;
}
which = pickNaNMulAdd(is_qnan(a.cls), is_snan(a.cls),
is_qnan(b.cls), is_snan(b.cls),
is_qnan(c.cls), is_snan(c.cls),
inf_zero, s);
which = pickNaNMulAdd(a.cls, b.cls, c.cls, inf_zero, s);
if (s->default_nan_mode) {
/* Note that this check is after pickNaNMulAdd so that function
* has an opportunity to set the Invalid flag.
*/
a.cls = float_class_dnan;
return a;
which = 3;
}
switch (which) {
@ -631,13 +620,14 @@ static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c,
a = c;
break;
case 3:
a.cls = float_class_dnan;
return a;
return parts_default_nan(s);
default:
g_assert_not_reached();
}
a.cls = float_class_msnan;
if (is_snan(a.cls)) {
return parts_silence_nan(a, s);
}
return a;
}
@ -685,7 +675,7 @@ static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract,
if (a.cls == float_class_inf) {
if (b.cls == float_class_inf) {
float_raise(float_flag_invalid, s);
a.cls = float_class_dnan;
return parts_default_nan(s);
}
return a;
}
@ -831,9 +821,7 @@ static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s)
if ((a.cls == float_class_inf && b.cls == float_class_zero) ||
(a.cls == float_class_zero && b.cls == float_class_inf)) {
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_dnan;
a.sign = sign;
return a;
return parts_default_nan(s);
}
/* Multiply by 0 or Inf */
if (a.cls == float_class_inf || a.cls == float_class_zero) {
@ -911,8 +899,7 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c,
if (inf_zero) {
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_dnan;
return a;
return parts_default_nan(s);
}
if (flags & float_muladd_negate_c) {
@ -936,13 +923,13 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c,
if (c.cls == float_class_inf) {
if (p_class == float_class_inf && p_sign != c.sign) {
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_dnan;
return parts_default_nan(s);
} else {
a.cls = float_class_inf;
a.sign = c.sign ^ sign_flip;
}
return a;
}
}
if (p_class == float_class_inf) {
a.cls = float_class_inf;
@ -1151,8 +1138,7 @@ static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s)
&&
(a.cls == float_class_inf || a.cls == float_class_zero)) {
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_dnan;
return a;
return parts_default_nan(s);
}
/* Inf / x or 0 / x */
if (a.cls == float_class_inf || a.cls == float_class_zero) {
@ -1202,6 +1188,104 @@ float64 float64_div(float64 a, float64 b, float_status *status)
return float64_round_pack_canonical(pr, status);
}
/*
* Float to Float conversions
*
* Returns the result of converting one float format to another. The
* conversion is performed according to the IEC/IEEE Standard for
* Binary Floating-Point Arithmetic.
*
* The float_to_float helper only needs to take care of raising
* invalid exceptions and handling the conversion on NaNs.
*/
static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf,
float_status *s)
{
if (dstf->arm_althp) {
switch (a.cls) {
case float_class_qnan:
case float_class_snan:
/* There is no NaN in the destination format. Raise Invalid
* and return a zero with the sign of the input NaN.
*/
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_zero;
a.frac = 0;
a.exp = 0;
break;
case float_class_inf:
/* There is no Inf in the destination format. Raise Invalid
* and return the maximum normal with the correct sign.
*/
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_normal;
a.exp = dstf->exp_max;
a.frac = ((1ull << dstf->frac_size) - 1) << dstf->frac_shift;
break;
default:
break;
}
} else if (is_nan(a.cls)) {
if (is_snan(a.cls)) {
s->float_exception_flags |= float_flag_invalid;
a = parts_silence_nan(a, s);
}
if (s->default_nan_mode) {
return parts_default_nan(s);
}
}
return a;
}
float32 float16_to_float32(float16 a, bool ieee, float_status *s)
{
const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
FloatParts p = float16a_unpack_canonical(a, s, fmt16);
FloatParts pr = float_to_float(p, &float32_params, s);
return float32_round_pack_canonical(pr, s);
}
float64 float16_to_float64(float16 a, bool ieee, float_status *s)
{
const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
FloatParts p = float16a_unpack_canonical(a, s, fmt16);
FloatParts pr = float_to_float(p, &float64_params, s);
return float64_round_pack_canonical(pr, s);
}
float16 float32_to_float16(float32 a, bool ieee, float_status *s)
{
const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
FloatParts p = float32_unpack_canonical(a, s);
FloatParts pr = float_to_float(p, fmt16, s);
return float16a_round_pack_canonical(pr, s, fmt16);
}
float64 float32_to_float64(float32 a, float_status *s)
{
FloatParts p = float32_unpack_canonical(a, s);
FloatParts pr = float_to_float(p, &float64_params, s);
return float64_round_pack_canonical(pr, s);
}
float16 float64_to_float16(float64 a, bool ieee, float_status *s)
{
const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
FloatParts p = float64_unpack_canonical(a, s);
FloatParts pr = float_to_float(p, fmt16, s);
return float16a_round_pack_canonical(pr, s, fmt16);
}
float32 float64_to_float32(float64 a, float_status *s)
{
FloatParts p = float64_unpack_canonical(a, s);
FloatParts pr = float_to_float(p, &float32_params, s);
return float32_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
@ -1350,8 +1434,6 @@ static int64_t round_to_int_and_pack(FloatParts in, int rmode,
switch (p.cls) {
case float_class_snan:
case float_class_qnan:
case float_class_dnan:
case float_class_msnan:
s->float_exception_flags = orig_flags | float_flag_invalid;
return max;
case float_class_inf:
@ -1442,8 +1524,6 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
switch (p.cls) {
case float_class_snan:
case float_class_qnan:
case float_class_dnan:
case float_class_msnan:
s->float_exception_flags = orig_flags | float_flag_invalid;
return max;
case float_class_inf:
@ -1943,8 +2023,7 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p)
}
if (a.sign) {
s->float_exception_flags |= float_flag_invalid;
a.cls = float_class_dnan;
return a;
return parts_default_nan(s);
}
if (a.cls == float_class_inf) {
return a; /* sqrt(+inf) = +inf */
@ -2013,6 +2092,78 @@ float64 __attribute__((flatten)) float64_sqrt(float64 a, float_status *status)
return float64_round_pack_canonical(pr, status);
}
/*----------------------------------------------------------------------------
| The pattern for a default generated NaN.
*----------------------------------------------------------------------------*/
float16 float16_default_nan(float_status *status)
{
FloatParts p = parts_default_nan(status);
p.frac >>= float16_params.frac_shift;
return float16_pack_raw(p);
}
float32 float32_default_nan(float_status *status)
{
FloatParts p = parts_default_nan(status);
p.frac >>= float32_params.frac_shift;
return float32_pack_raw(p);
}
float64 float64_default_nan(float_status *status)
{
FloatParts p = parts_default_nan(status);
p.frac >>= float64_params.frac_shift;
return float64_pack_raw(p);
}
float128 float128_default_nan(float_status *status)
{
FloatParts p = parts_default_nan(status);
float128 r;
/* Extrapolate from the choices made by parts_default_nan to fill
* in the quad-floating format. If the low bit is set, assume we
* want to set all non-snan bits.
*/
r.low = -(p.frac & 1);
r.high = p.frac >> (DECOMPOSED_BINARY_POINT - 48);
r.high |= LIT64(0x7FFF000000000000);
r.high |= (uint64_t)p.sign << 63;
return r;
}
/*----------------------------------------------------------------------------
| Returns a quiet NaN from a signalling NaN for the floating point value `a'.
*----------------------------------------------------------------------------*/
float16 float16_silence_nan(float16 a, float_status *status)
{
FloatParts p = float16_unpack_raw(a);
p.frac <<= float16_params.frac_shift;
p = parts_silence_nan(p, status);
p.frac >>= float16_params.frac_shift;
return float16_pack_raw(p);
}
float32 float32_silence_nan(float32 a, float_status *status)
{
FloatParts p = float32_unpack_raw(a);
p.frac <<= float32_params.frac_shift;
p = parts_silence_nan(p, status);
p.frac >>= float32_params.frac_shift;
return float32_pack_raw(p);
}
float64 float64_silence_nan(float64 a, float_status *status)
{
FloatParts p = float64_unpack_raw(a);
p.frac <<= float64_params.frac_shift;
p = parts_silence_nan(p, status);
p.frac >>= float64_params.frac_shift;
return float64_pack_raw(p);
}
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
@ -3147,42 +3298,7 @@ float128 uint64_to_float128(uint64_t a, float_status *status)
if (a == 0) {
return float128_zero;
}
return normalizeRoundAndPackFloat128(0, 0x406E, a, 0, status);
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point value
| `a' to the double-precision floating-point format. The conversion is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
*----------------------------------------------------------------------------*/
float64 float32_to_float64(float32 a, float_status *status)
{
flag aSign;
int aExp;
uint32_t aSig;
a = float32_squash_input_denormal(a, status);
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if (aSig) {
return commonNaNToFloat64(float32ToCommonNaN(a, status), status);
}
return packFloat64( aSign, 0x7FF, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
--aExp;
}
return packFloat64( aSign, aExp + 0x380, ( (uint64_t) aSig )<<29 );
return normalizeRoundAndPackFloat128(0, 0x406E, 0, a, status);
}
/*----------------------------------------------------------------------------
@ -3703,173 +3819,6 @@ int float32_unordered_quiet(float32 a, float32 b, float_status *status)
return 0;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point value
| `a' to the single-precision floating-point format. The conversion is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
*----------------------------------------------------------------------------*/
float32 float64_to_float32(float64 a, float_status *status)
{
flag aSign;
int aExp;
uint64_t aSig;
uint32_t zSig;
a = float64_squash_input_denormal(a, status);
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if (aSig) {
return commonNaNToFloat32(float64ToCommonNaN(a, status), status);
}
return packFloat32( aSign, 0xFF, 0 );
}
shift64RightJamming( aSig, 22, &aSig );
zSig = aSig;
if ( aExp || zSig ) {
zSig |= 0x40000000;
aExp -= 0x381;
}
return roundAndPackFloat32(aSign, aExp, zSig, status);
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
| half-precision floating-point value, returning the result. After being
| shifted into the proper positions, the three fields are simply added
| together to form the result. This means that any integer portion of `zSig'
| will be added into the exponent. Since a properly normalized significand
| will have an integer portion equal to 1, the `zExp' input should be 1 less
| than the desired result exponent whenever `zSig' is a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
static float16 packFloat16(flag zSign, int zExp, uint16_t zSig)
{
return make_float16(
(((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper half-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the half-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal half-
| precision floating-point number.
| The `ieee' flag indicates whether to use IEEE standard half precision, or
| ARM-style "alternative representation", which omits the NaN and Inf
| encodings in order to raise the maximum representable exponent by one.
| The input significand `zSig' has its binary point between bits 22
| and 23, which is 13 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| Note the slightly odd position of the binary point in zSig compared with the
| other roundAndPackFloat functions. This should probably be fixed if we
| need to implement more float16 routines than just conversion.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
static float16 roundAndPackFloat16(flag zSign, int zExp,
uint32_t zSig, flag ieee,
float_status *status)
{
int maxexp = ieee ? 29 : 30;
uint32_t mask;
uint32_t increment;
bool rounding_bumps_exp;
bool is_tiny = false;
/* Calculate the mask of bits of the mantissa which are not
* representable in half-precision and will be lost.
*/
if (zExp < 1) {
/* Will be denormal in halfprec */
mask = 0x00ffffff;
if (zExp >= -11) {
mask >>= 11 + zExp;
}
} else {
/* Normal number in halfprec */
mask = 0x00001fff;
}
switch (status->float_rounding_mode) {
case float_round_nearest_even:
increment = (mask + 1) >> 1;
if ((zSig & mask) == increment) {
increment = zSig & (increment << 1);
}
break;
case float_round_ties_away:
increment = (mask + 1) >> 1;
break;
case float_round_up:
increment = zSign ? 0 : mask;
break;
case float_round_down:
increment = zSign ? mask : 0;
break;
default: /* round_to_zero */
increment = 0;
break;
}
rounding_bumps_exp = (zSig + increment >= 0x01000000);
if (zExp > maxexp || (zExp == maxexp && rounding_bumps_exp)) {
if (ieee) {
float_raise(float_flag_overflow | float_flag_inexact, status);
return packFloat16(zSign, 0x1f, 0);
} else {
float_raise(float_flag_invalid, status);
return packFloat16(zSign, 0x1f, 0x3ff);
}
}
if (zExp < 0) {
/* Note that flush-to-zero does not affect half-precision results */
is_tiny =
(status->float_detect_tininess == float_tininess_before_rounding)
|| (zExp < -1)
|| (!rounding_bumps_exp);
}
if (zSig & mask) {
float_raise(float_flag_inexact, status);
if (is_tiny) {
float_raise(float_flag_underflow, status);
}
}
zSig += increment;
if (rounding_bumps_exp) {
zSig >>= 1;
zExp++;
}
if (zExp < -10) {
return packFloat16(zSign, 0, 0);
}
if (zExp < 0) {
zSig >>= -zExp;
zExp = 0;
}
return packFloat16(zSign, zExp, zSig >> 13);
}
/*----------------------------------------------------------------------------
| If `a' is denormal and we are in flush-to-zero mode then set the
| input-denormal exception and return zero. Otherwise just return the value.
@ -3885,163 +3834,6 @@ float16 float16_squash_input_denormal(float16 a, float_status *status)
return a;
}
static void normalizeFloat16Subnormal(uint32_t aSig, int *zExpPtr,
uint32_t *zSigPtr)
{
int8_t shiftCount = countLeadingZeros32(aSig) - 21;
*zSigPtr = aSig << shiftCount;
*zExpPtr = 1 - shiftCount;
}
/* Half precision floats come in two formats: standard IEEE and "ARM" format.
The latter gains extra exponent range by omitting the NaN/Inf encodings. */
float32 float16_to_float32(float16 a, flag ieee, float_status *status)
{
flag aSign;
int aExp;
uint32_t aSig;
aSign = extractFloat16Sign(a);
aExp = extractFloat16Exp(a);
aSig = extractFloat16Frac(a);
if (aExp == 0x1f && ieee) {
if (aSig) {
return commonNaNToFloat32(float16ToCommonNaN(a, status), status);
}
return packFloat32(aSign, 0xff, 0);
}
if (aExp == 0) {
if (aSig == 0) {
return packFloat32(aSign, 0, 0);
}
normalizeFloat16Subnormal(aSig, &aExp, &aSig);
aExp--;
}
return packFloat32( aSign, aExp + 0x70, aSig << 13);
}
float16 float32_to_float16(float32 a, flag ieee, float_status *status)
{
flag aSign;
int aExp;
uint32_t aSig;
a = float32_squash_input_denormal(a, status);
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if (aSig) {
/* Input is a NaN */
if (!ieee) {
float_raise(float_flag_invalid, status);
return packFloat16(aSign, 0, 0);
}
return commonNaNToFloat16(
float32ToCommonNaN(a, status), status);
}
/* Infinity */
if (!ieee) {
float_raise(float_flag_invalid, status);
return packFloat16(aSign, 0x1f, 0x3ff);
}
return packFloat16(aSign, 0x1f, 0);
}
if (aExp == 0 && aSig == 0) {
return packFloat16(aSign, 0, 0);
}
/* Decimal point between bits 22 and 23. Note that we add the 1 bit
* even if the input is denormal; however this is harmless because
* the largest possible single-precision denormal is still smaller
* than the smallest representable half-precision denormal, and so we
* will end up ignoring aSig and returning via the "always return zero"
* codepath.
*/
aSig |= 0x00800000;
aExp -= 0x71;
return roundAndPackFloat16(aSign, aExp, aSig, ieee, status);
}
float64 float16_to_float64(float16 a, flag ieee, float_status *status)
{
flag aSign;
int aExp;
uint32_t aSig;
aSign = extractFloat16Sign(a);
aExp = extractFloat16Exp(a);
aSig = extractFloat16Frac(a);
if (aExp == 0x1f && ieee) {
if (aSig) {
return commonNaNToFloat64(
float16ToCommonNaN(a, status), status);
}
return packFloat64(aSign, 0x7ff, 0);
}
if (aExp == 0) {
if (aSig == 0) {
return packFloat64(aSign, 0, 0);
}
normalizeFloat16Subnormal(aSig, &aExp, &aSig);
aExp--;
}
return packFloat64(aSign, aExp + 0x3f0, ((uint64_t)aSig) << 42);
}
float16 float64_to_float16(float64 a, flag ieee, float_status *status)
{
flag aSign;
int aExp;
uint64_t aSig;
uint32_t zSig;
a = float64_squash_input_denormal(a, status);
aSig = extractFloat64Frac(a);
aExp = extractFloat64Exp(a);
aSign = extractFloat64Sign(a);
if (aExp == 0x7FF) {
if (aSig) {
/* Input is a NaN */
if (!ieee) {
float_raise(float_flag_invalid, status);
return packFloat16(aSign, 0, 0);
}
return commonNaNToFloat16(
float64ToCommonNaN(a, status), status);
}
/* Infinity */
if (!ieee) {
float_raise(float_flag_invalid, status);
return packFloat16(aSign, 0x1f, 0x3ff);
}
return packFloat16(aSign, 0x1f, 0);
}
shift64RightJamming(aSig, 29, &aSig);
zSig = aSig;
if (aExp == 0 && zSig == 0) {
return packFloat16(aSign, 0, 0);
}
/* Decimal point between bits 22 and 23. Note that we add the 1 bit
* even if the input is denormal; however this is harmless because
* the largest possible single-precision denormal is still smaller
* than the smallest representable half-precision denormal, and so we
* will end up ignoring aSig and returning via the "always return zero"
* codepath.
*/
zSig |= 0x00800000;
aExp -= 0x3F1;
return roundAndPackFloat16(aSign, aExp, zSig, ieee, status);
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point value
| `a' to the extended double-precision floating-point format. The conversion

View File

@ -173,6 +173,7 @@ typedef struct float_status {
/* should denormalised inputs go to zero and set the input_denormal flag? */
flag flush_inputs_to_zero;
flag default_nan_mode;
/* not always used -- see snan_bit_is_one() in softfloat-specialize.h */
flag snan_bit_is_one;
} float_status;

View File

@ -211,10 +211,10 @@ float128 uint64_to_float128(uint64_t, float_status *status);
/*----------------------------------------------------------------------------
| Software half-precision conversion routines.
*----------------------------------------------------------------------------*/
float16 float32_to_float16(float32, flag, float_status *status);
float32 float16_to_float32(float16, flag, float_status *status);
float16 float64_to_float16(float64 a, flag ieee, float_status *status);
float64 float16_to_float64(float16 a, flag ieee, float_status *status);
float16 float32_to_float16(float32, bool ieee, float_status *status);
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);
int16_t float16_to_int16(float16, float_status *status);
uint16_t float16_to_uint16(float16 a, float_status *status);
int16_t float16_to_int16_round_to_zero(float16, float_status *status);
@ -257,7 +257,7 @@ int float16_compare_quiet(float16, float16, float_status *status);
int float16_is_quiet_nan(float16, float_status *status);
int float16_is_signaling_nan(float16, float_status *status);
float16 float16_maybe_silence_nan(float16, float_status *status);
float16 float16_silence_nan(float16, float_status *status);
static inline int float16_is_any_nan(float16 a)
{
@ -368,7 +368,7 @@ float32 float32_minnummag(float32, float32, float_status *status);
float32 float32_maxnummag(float32, float32, float_status *status);
int float32_is_quiet_nan(float32, float_status *status);
int float32_is_signaling_nan(float32, float_status *status);
float32 float32_maybe_silence_nan(float32, float_status *status);
float32 float32_silence_nan(float32, float_status *status);
float32 float32_scalbn(float32, int, float_status *status);
static inline float32 float32_abs(float32 a)
@ -497,7 +497,7 @@ float64 float64_minnummag(float64, float64, float_status *status);
float64 float64_maxnummag(float64, float64, float_status *status);
int float64_is_quiet_nan(float64 a, float_status *status);
int float64_is_signaling_nan(float64, float_status *status);
float64 float64_maybe_silence_nan(float64, float_status *status);
float64 float64_silence_nan(float64, float_status *status);
float64 float64_scalbn(float64, int, float_status *status);
static inline float64 float64_abs(float64 a)
@ -600,7 +600,7 @@ int floatx80_compare(floatx80, floatx80, float_status *status);
int floatx80_compare_quiet(floatx80, floatx80, float_status *status);
int floatx80_is_quiet_nan(floatx80, float_status *status);
int floatx80_is_signaling_nan(floatx80, float_status *status);
floatx80 floatx80_maybe_silence_nan(floatx80, float_status *status);
floatx80 floatx80_silence_nan(floatx80, float_status *status);
floatx80 floatx80_scalbn(floatx80, int, float_status *status);
static inline floatx80 floatx80_abs(floatx80 a)
@ -811,7 +811,7 @@ int float128_compare(float128, float128, float_status *status);
int float128_compare_quiet(float128, float128, float_status *status);
int float128_is_quiet_nan(float128, float_status *status);
int float128_is_signaling_nan(float128, float_status *status);
float128 float128_maybe_silence_nan(float128, float_status *status);
float128 float128_silence_nan(float128, float_status *status);
float128 float128_scalbn(float128, int, float_status *status);
static inline float128 float128_abs(float128 a)

View File

@ -376,7 +376,7 @@ float16 HELPER(frecpx_f16)(float16 a, void *fpstp)
float16 nan = a;
if (float16_is_signaling_nan(a, fpst)) {
float_raise(float_flag_invalid, fpst);
nan = float16_maybe_silence_nan(a, fpst);
nan = float16_silence_nan(a, fpst);
}
if (fpst->default_nan_mode) {
nan = float16_default_nan(fpst);
@ -405,7 +405,7 @@ float32 HELPER(frecpx_f32)(float32 a, void *fpstp)
float32 nan = a;
if (float32_is_signaling_nan(a, fpst)) {
float_raise(float_flag_invalid, fpst);
nan = float32_maybe_silence_nan(a, fpst);
nan = float32_silence_nan(a, fpst);
}
if (fpst->default_nan_mode) {
nan = float32_default_nan(fpst);
@ -434,7 +434,7 @@ float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
float64 nan = a;
if (float64_is_signaling_nan(a, fpst)) {
float_raise(float_flag_invalid, fpst);
nan = float64_maybe_silence_nan(a, fpst);
nan = float64_silence_nan(a, fpst);
}
if (fpst->default_nan_mode) {
nan = float64_default_nan(fpst);
@ -466,7 +466,6 @@ float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
set_float_rounding_mode(float_round_to_zero, &tstat);
set_float_exception_flags(0, &tstat);
r = float64_to_float32(a, &tstat);
r = float32_maybe_silence_nan(r, &tstat);
exflags = get_float_exception_flags(&tstat);
if (exflags & float_flag_inexact) {
r = make_float32(float32_val(r) | 1);

View File

@ -11348,20 +11348,12 @@ FLOAT_CONVS(ui, d, 64, u)
/* floating point conversion */
float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env)
{
float64 r = float32_to_float64(x, &env->vfp.fp_status);
/* ARM requires that S<->D conversion of any kind of NaN generates
* a quiet NaN by forcing the most significant frac bit to 1.
*/
return float64_maybe_silence_nan(r, &env->vfp.fp_status);
return float32_to_float64(x, &env->vfp.fp_status);
}
float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
{
float32 r = float64_to_float32(x, &env->vfp.fp_status);
/* ARM requires that S<->D conversion of any kind of NaN generates
* a quiet NaN by forcing the most significant frac bit to 1.
*/
return float32_maybe_silence_nan(r, &env->vfp.fp_status);
return float64_to_float32(x, &env->vfp.fp_status);
}
/* VFP3 fixed point conversion. */
@ -11540,64 +11532,56 @@ uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env)
}
/* Half precision conversions. */
static float32 do_fcvt_f16_to_f32(uint32_t a, CPUARMState *env, float_status *s)
float32 HELPER(vfp_fcvt_f16_to_f32)(float16 a, void *fpstp, uint32_t ahp_mode)
{
int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
float32 r = float16_to_float32(make_float16(a), ieee, s);
if (ieee) {
return float32_maybe_silence_nan(r, s);
}
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing input denormals.
*/
float_status *fpst = fpstp;
flag save = get_flush_inputs_to_zero(fpst);
set_flush_inputs_to_zero(false, fpst);
float32 r = float16_to_float32(a, !ahp_mode, fpst);
set_flush_inputs_to_zero(save, fpst);
return r;
}
static uint32_t do_fcvt_f32_to_f16(float32 a, CPUARMState *env, float_status *s)
float16 HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
{
int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
float16 r = float32_to_float16(a, ieee, s);
if (ieee) {
r = float16_maybe_silence_nan(r, s);
}
return float16_val(r);
}
float32 HELPER(neon_fcvt_f16_to_f32)(uint32_t a, CPUARMState *env)
{
return do_fcvt_f16_to_f32(a, env, &env->vfp.standard_fp_status);
}
uint32_t HELPER(neon_fcvt_f32_to_f16)(float32 a, CPUARMState *env)
{
return do_fcvt_f32_to_f16(a, env, &env->vfp.standard_fp_status);
}
float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUARMState *env)
{
return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status);
}
uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUARMState *env)
{
return do_fcvt_f32_to_f16(a, env, &env->vfp.fp_status);
}
float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, CPUARMState *env)
{
int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
float64 r = float16_to_float64(make_float16(a), ieee, &env->vfp.fp_status);
if (ieee) {
return float64_maybe_silence_nan(r, &env->vfp.fp_status);
}
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing output denormals.
*/
float_status *fpst = fpstp;
flag save = get_flush_to_zero(fpst);
set_flush_to_zero(false, fpst);
float16 r = float32_to_float16(a, !ahp_mode, fpst);
set_flush_to_zero(save, fpst);
return r;
}
uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, CPUARMState *env)
float64 HELPER(vfp_fcvt_f16_to_f64)(float16 a, void *fpstp, uint32_t ahp_mode)
{
int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
float16 r = float64_to_float16(a, ieee, &env->vfp.fp_status);
if (ieee) {
r = float16_maybe_silence_nan(r, &env->vfp.fp_status);
}
return float16_val(r);
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing input denormals.
*/
float_status *fpst = fpstp;
flag save = get_flush_inputs_to_zero(fpst);
set_flush_inputs_to_zero(false, fpst);
float64 r = float16_to_float64(a, !ahp_mode, fpst);
set_flush_inputs_to_zero(save, fpst);
return r;
}
float16 HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode)
{
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing output denormals.
*/
float_status *fpst = fpstp;
flag save = get_flush_to_zero(fpst);
set_flush_to_zero(false, fpst);
float16 r = float64_to_float16(a, !ahp_mode, fpst);
set_flush_to_zero(save, fpst);
return r;
}
#define float32_two make_float32(0x40000000)
@ -11739,7 +11723,7 @@ float16 HELPER(recpe_f16)(float16 input, void *fpstp)
float16 nan = f16;
if (float16_is_signaling_nan(f16, fpst)) {
float_raise(float_flag_invalid, fpst);
nan = float16_maybe_silence_nan(f16, fpst);
nan = float16_silence_nan(f16, fpst);
}
if (fpst->default_nan_mode) {
nan = float16_default_nan(fpst);
@ -11787,7 +11771,7 @@ float32 HELPER(recpe_f32)(float32 input, void *fpstp)
float32 nan = f32;
if (float32_is_signaling_nan(f32, fpst)) {
float_raise(float_flag_invalid, fpst);
nan = float32_maybe_silence_nan(f32, fpst);
nan = float32_silence_nan(f32, fpst);
}
if (fpst->default_nan_mode) {
nan = float32_default_nan(fpst);
@ -11835,7 +11819,7 @@ float64 HELPER(recpe_f64)(float64 input, void *fpstp)
float64 nan = f64;
if (float64_is_signaling_nan(f64, fpst)) {
float_raise(float_flag_invalid, fpst);
nan = float64_maybe_silence_nan(f64, fpst);
nan = float64_silence_nan(f64, fpst);
}
if (fpst->default_nan_mode) {
nan = float64_default_nan(fpst);
@ -11934,7 +11918,7 @@ float16 HELPER(rsqrte_f16)(float16 input, void *fpstp)
float16 nan = f16;
if (float16_is_signaling_nan(f16, s)) {
float_raise(float_flag_invalid, s);
nan = float16_maybe_silence_nan(f16, s);
nan = float16_silence_nan(f16, s);
}
if (s->default_nan_mode) {
nan = float16_default_nan(s);
@ -11978,7 +11962,7 @@ float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
float32 nan = f32;
if (float32_is_signaling_nan(f32, s)) {
float_raise(float_flag_invalid, s);
nan = float32_maybe_silence_nan(f32, s);
nan = float32_silence_nan(f32, s);
}
if (s->default_nan_mode) {
nan = float32_default_nan(s);
@ -12021,7 +12005,7 @@ float64 HELPER(rsqrte_f64)(float64 input, void *fpstp)
float64 nan = f64;
if (float64_is_signaling_nan(f64, s)) {
float_raise(float_flag_invalid, s);
nan = float64_maybe_silence_nan(f64, s);
nan = float64_silence_nan(f64, s);
}
if (s->default_nan_mode) {
nan = float64_default_nan(s);

View File

@ -187,12 +187,10 @@ DEF_HELPER_3(vfp_uqtoh, f16, i64, i32, ptr)
DEF_HELPER_FLAGS_2(set_rmode, TCG_CALL_NO_RWG, i32, i32, ptr)
DEF_HELPER_FLAGS_2(set_neon_rmode, TCG_CALL_NO_RWG, i32, i32, env)
DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env)
DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
DEF_HELPER_FLAGS_2(vfp_fcvt_f16_to_f64, TCG_CALL_NO_RWG, f64, i32, env)
DEF_HELPER_FLAGS_2(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, i32, f64, env)
DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f32, TCG_CALL_NO_RWG, f32, f16, ptr, i32)
DEF_HELPER_FLAGS_3(vfp_fcvt_f32_to_f16, TCG_CALL_NO_RWG, f16, f32, ptr, i32)
DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f64, TCG_CALL_NO_RWG, f64, f16, ptr, i32)
DEF_HELPER_FLAGS_3(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, f16, f64, ptr, i32)
DEF_HELPER_4(vfp_muladdd, f64, f64, f64, f64, ptr)
DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr)

View File

@ -5147,10 +5147,15 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
} else {
/* Single to half */
TCGv_i32 tcg_rd = tcg_temp_new_i32();
gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, cpu_env);
TCGv_i32 ahp = get_ahp_flag();
TCGv_ptr fpst = get_fpstatus_ptr(false);
gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, fpst, ahp);
/* write_fp_sreg is OK here because top half of tcg_rd is zero */
write_fp_sreg(s, rd, tcg_rd);
tcg_temp_free_i32(tcg_rd);
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
}
tcg_temp_free_i32(tcg_rn);
break;
@ -5163,9 +5168,13 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
/* Double to single */
gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env);
} else {
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp = get_ahp_flag();
/* Double to half */
gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, cpu_env);
gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp);
/* write_fp_sreg is OK here because top half of tcg_rd is zero */
tcg_temp_free_ptr(fpst);
tcg_temp_free_i32(ahp);
}
write_fp_sreg(s, rd, tcg_rd);
tcg_temp_free_i32(tcg_rd);
@ -5175,17 +5184,21 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
case 0x3:
{
TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
TCGv_ptr tcg_fpst = get_fpstatus_ptr(false);
TCGv_i32 tcg_ahp = get_ahp_flag();
tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
if (dtype == 0) {
/* Half to single */
TCGv_i32 tcg_rd = tcg_temp_new_i32();
gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, cpu_env);
gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
write_fp_sreg(s, rd, tcg_rd);
tcg_temp_free_ptr(tcg_fpst);
tcg_temp_free_i32(tcg_ahp);
tcg_temp_free_i32(tcg_rd);
} else {
/* Half to double */
TCGv_i64 tcg_rd = tcg_temp_new_i64();
gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, cpu_env);
gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
write_fp_dreg(s, rd, tcg_rd);
tcg_temp_free_i64(tcg_rd);
}
@ -9053,12 +9066,17 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
} else {
TCGv_i32 tcg_lo = tcg_temp_new_i32();
TCGv_i32 tcg_hi = tcg_temp_new_i32();
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp = get_ahp_flag();
tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, cpu_env);
gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, cpu_env);
gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
tcg_temp_free_i32(tcg_lo);
tcg_temp_free_i32(tcg_hi);
tcg_temp_free_ptr(fpst);
tcg_temp_free_i32(ahp);
}
break;
case 0x56: /* FCVTXN, FCVTXN2 */
@ -11532,18 +11550,23 @@ static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q,
/* 16 -> 32 bit fp conversion */
int srcelt = is_q ? 4 : 0;
TCGv_i32 tcg_res[4];
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp = get_ahp_flag();
for (pass = 0; pass < 4; pass++) {
tcg_res[pass] = tcg_temp_new_i32();
read_vec_element_i32(s, tcg_res[pass], rn, srcelt + pass, MO_16);
gen_helper_vfp_fcvt_f16_to_f32(tcg_res[pass], tcg_res[pass],
cpu_env);
fpst, ahp);
}
for (pass = 0; pass < 4; pass++) {
write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
tcg_temp_free_i32(tcg_res[pass]);
}
tcg_temp_free_ptr(fpst);
tcg_temp_free_i32(ahp);
}
}

View File

@ -3824,38 +3824,56 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
gen_vfp_sqrt(dp);
break;
case 4: /* vcvtb.f32.f16, vcvtb.f64.f16 */
{
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp_mode = get_ahp_flag();
tmp = gen_vfp_mrs();
tcg_gen_ext16u_i32(tmp, tmp);
if (dp) {
gen_helper_vfp_fcvt_f16_to_f64(cpu_F0d, tmp,
cpu_env);
fpst, ahp_mode);
} else {
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp,
cpu_env);
fpst, ahp_mode);
}
tcg_temp_free_i32(ahp_mode);
tcg_temp_free_ptr(fpst);
tcg_temp_free_i32(tmp);
break;
}
case 5: /* vcvtt.f32.f16, vcvtt.f64.f16 */
{
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp = get_ahp_flag();
tmp = gen_vfp_mrs();
tcg_gen_shri_i32(tmp, tmp, 16);
if (dp) {
gen_helper_vfp_fcvt_f16_to_f64(cpu_F0d, tmp,
cpu_env);
fpst, ahp);
} else {
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp,
cpu_env);
fpst, ahp);
}
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
break;
}
case 6: /* vcvtb.f16.f32, vcvtb.f16.f64 */
{
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp = get_ahp_flag();
tmp = tcg_temp_new_i32();
if (dp) {
gen_helper_vfp_fcvt_f64_to_f16(tmp, cpu_F0d,
cpu_env);
fpst, ahp);
} else {
gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s,
cpu_env);
fpst, ahp);
}
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
gen_mov_F0_vreg(0, rd);
tmp2 = gen_vfp_mrs();
tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
@ -3863,15 +3881,21 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmp2);
gen_vfp_msr(tmp);
break;
}
case 7: /* vcvtt.f16.f32, vcvtt.f16.f64 */
{
TCGv_ptr fpst = get_fpstatus_ptr(false);
TCGv_i32 ahp = get_ahp_flag();
tmp = tcg_temp_new_i32();
if (dp) {
gen_helper_vfp_fcvt_f64_to_f16(tmp, cpu_F0d,
cpu_env);
fpst, ahp);
} else {
gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s,
cpu_env);
fpst, ahp);
}
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
tcg_gen_shli_i32(tmp, tmp, 16);
gen_mov_F0_vreg(0, rd);
tmp2 = gen_vfp_mrs();
@ -3880,6 +3904,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmp2);
gen_vfp_msr(tmp);
break;
}
case 8: /* cmp */
gen_vfp_cmp(dp);
break;
@ -7222,53 +7247,70 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
break;
case NEON_2RM_VCVT_F16_F32:
{
TCGv_ptr fpst;
TCGv_i32 ahp;
if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
q || (rm & 1)) {
return 1;
}
tmp = tcg_temp_new_i32();
tmp2 = tcg_temp_new_i32();
fpst = get_fpstatus_ptr(true);
ahp = get_ahp_flag();
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, fpst, ahp);
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, fpst, ahp);
tcg_gen_shli_i32(tmp2, tmp2, 16);
tcg_gen_or_i32(tmp2, tmp2, tmp);
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, fpst, ahp);
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
neon_store_reg(rd, 0, tmp2);
tmp2 = tcg_temp_new_i32();
gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, fpst, ahp);
tcg_gen_shli_i32(tmp2, tmp2, 16);
tcg_gen_or_i32(tmp2, tmp2, tmp);
neon_store_reg(rd, 1, tmp2);
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
break;
}
case NEON_2RM_VCVT_F32_F16:
{
TCGv_ptr fpst;
TCGv_i32 ahp;
if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
q || (rd & 1)) {
return 1;
}
fpst = get_fpstatus_ptr(true);
ahp = get_ahp_flag();
tmp3 = tcg_temp_new_i32();
tmp = neon_load_reg(rm, 0);
tmp2 = neon_load_reg(rm, 1);
tcg_gen_ext16u_i32(tmp3, tmp);
gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
tcg_gen_shri_i32(tmp3, tmp, 16);
gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
tcg_temp_free_i32(tmp);
tcg_gen_ext16u_i32(tmp3, tmp2);
gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
tcg_gen_shri_i32(tmp3, tmp2, 16);
gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp3);
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
break;
}
case NEON_2RM_AESE: case NEON_2RM_AESMC:
if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)
|| ((rm | rd) & 1)) {

View File

@ -177,4 +177,16 @@ void arm_free_cc(DisasCompare *cmp);
void arm_jump_cc(DisasCompare *cmp, TCGLabel *label);
void arm_gen_test_cc(int cc, TCGLabel *label);
/* Return state of Alternate Half-precision flag, caller frees result */
static inline TCGv_i32 get_ahp_flag(void)
{
TCGv_i32 ret = tcg_temp_new_i32();
tcg_gen_ld_i32(ret, cpu_env,
offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPSCR]));
tcg_gen_extract_i32(ret, ret, 26, 1);
return ret;
}
#endif /* TARGET_ARM_TRANSLATE_H */

View File

@ -141,7 +141,6 @@ static void hppa_cpu_initfn(Object *obj)
cs->env_ptr = env;
cs->exception_index = -1;
cpu_hppa_loaded_fr0(env);
set_snan_bit_is_one(true, &env->fp_status);
cpu_hppa_put_psw(env, PSW_W);
}

View File

@ -341,7 +341,6 @@ float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b)
float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
{
float64 ret = float32_to_float64(arg, &env->fp_status);
ret = float64_maybe_silence_nan(ret, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
@ -349,7 +348,6 @@ float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg)
{
float32 ret = float64_to_float32(arg, &env->fp_status);
ret = float32_maybe_silence_nan(ret, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}

View File

@ -31,13 +31,14 @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
{
if (floatx80_is_signaling_nan(a, status)) {
float_raise(float_flag_invalid, status);
a = floatx80_silence_nan(a, status);
}
if (status->default_nan_mode) {
return floatx80_default_nan(status);
}
return floatx80_maybe_silence_nan(a, status);
return a;
}
/*----------------------------------------------------------------------------

View File

@ -1615,7 +1615,6 @@ static inline float16 float16_from_float32(int32_t a, flag ieee,
float16 f_val;
f_val = float32_to_float16((float32)a, ieee, status);
f_val = float16_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1 << 15)) : f_val;
}
@ -1625,7 +1624,6 @@ static inline float32 float32_from_float64(int64_t a, float_status *status)
float32 f_val;
f_val = float64_to_float32((float64)a, status);
f_val = float32_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1 << 31)) : f_val;
}
@ -1636,7 +1634,6 @@ static inline float32 float32_from_float16(int16_t a, flag ieee,
float32 f_val;
f_val = float16_to_float32((float16)a, ieee, status);
f_val = float32_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1 << 31)) : f_val;
}
@ -1646,7 +1643,6 @@ static inline float64 float64_from_float32(int32_t a, float_status *status)
float64 f_val;
f_val = float32_to_float64((float64)a, status);
f_val = float64_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1ULL << 63)) : f_val;
}

View File

@ -2700,7 +2700,6 @@ uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
uint64_t fdt2;
fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
fdt2 = float64_maybe_silence_nan(fdt2, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdt2;
}
@ -2790,7 +2789,6 @@ uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
uint32_t fst2;
fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
fst2 = float32_maybe_silence_nan(fst2, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fst2;
}

View File

@ -3382,7 +3382,6 @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode)
xt.f128 = xb.f128;
} else if (float128_is_neg(xb.f128) && !float128_is_zero(xb.f128)) {
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
set_snan_bit_is_one(0, &env->fp_status);
xt.f128 = float128_default_nan(&env->fp_status);
}
}

View File

@ -279,14 +279,12 @@ uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
{
rs1 = float64_to_float32(rs1, &env->fp_status);
return float32_maybe_silence_nan(rs1, &env->fp_status);
return float64_to_float32(rs1, &env->fp_status);
}
uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
{
rs1 = float32_to_float64(rs1, &env->fp_status);
return float64_maybe_silence_nan(rs1, &env->fp_status);
return float32_to_float64(rs1, &env->fp_status);
}
uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)

View File

@ -269,7 +269,7 @@ uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
{
float64 ret = float32_to_float64(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
return float64_maybe_silence_nan(ret, &env->fpu_status);
return ret;
}
/* convert 128-bit float to 64-bit float */
@ -277,7 +277,7 @@ uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, GETPC());
return float64_maybe_silence_nan(ret, &env->fpu_status);
return ret;
}
/* convert 64-bit float to 128-bit float */
@ -285,7 +285,7 @@ uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float64_to_float128(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
return RET128(float128_maybe_silence_nan(ret, &env->fpu_status));
return RET128(ret);
}
/* convert 32-bit float to 128-bit float */
@ -293,7 +293,7 @@ uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float32_to_float128(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
return RET128(float128_maybe_silence_nan(ret, &env->fpu_status));
return RET128(ret);
}
/* convert 64-bit float to 32-bit float */
@ -301,7 +301,7 @@ uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
{
float32 ret = float64_to_float32(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
return float32_maybe_silence_nan(ret, &env->fpu_status);
return ret;
}
/* convert 128-bit float to 32-bit float */
@ -309,7 +309,7 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, GETPC());
return float32_maybe_silence_nan(ret, &env->fpu_status);
return ret;
}
/* 32-bit FP compare */

View File

@ -71,7 +71,6 @@ static void superh_cpu_reset(CPUState *s)
set_flush_to_zero(1, &env->fp_status);
#endif
set_default_nan_mode(1, &env->fp_status);
set_snan_bit_is_one(1, &env->fp_status);
}
static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)

View File

@ -70,7 +70,6 @@ static void unicore_ii_cpu_initfn(Object *obj)
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
set_snan_bit_is_one(1, &env->ucf64.fp_status);
}
static void uc32_any_cpu_initfn(Object *obj)
@ -83,7 +82,6 @@ static void uc32_any_cpu_initfn(Object *obj)
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
set_snan_bit_is_one(1, &env->ucf64.fp_status);
}
static void uc32_cpu_realizefn(DeviceState *dev, Error **errp)