mirror of https://github.com/xqemu/xqemu.git
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:
commit
6812994826
File diff suppressed because it is too large
Load Diff
726
fpu/softfloat.c
726
fpu/softfloat.c
|
@ -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,12 +923,12 @@ 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;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
if (p_class == 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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue