mirror of https://github.com/xqemu/xqemu.git
fpu/softfloat: Partial support for ARM Alternative half-precision
For float16 ARM supports an alternative half-precision format which sacrifices the ability to represent NaN/Inf in return for a higher dynamic range. The new FloatFmt flag, arm_althp, is then used to modify the behaviour of canonicalize and round_canonical with respect to representation and exception raising. Usage of this new flag waits until we re-factor float-to-float conversions. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
0acb9e7cb3
commit
ca3a3d5a31
|
@ -220,8 +220,10 @@ typedef struct {
|
||||||
* frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT
|
* frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT
|
||||||
* The following are computed based the size of fraction
|
* The following are computed based the size of fraction
|
||||||
* frac_lsb: least significant bit 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
|
* round_mask/roundeven_mask: masks used for rounding
|
||||||
|
* The following optional modifiers are available:
|
||||||
|
* arm_althp: handle ARM Alternative Half Precision
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int exp_size;
|
int exp_size;
|
||||||
|
@ -233,6 +235,7 @@ typedef struct {
|
||||||
uint64_t frac_lsbm1;
|
uint64_t frac_lsbm1;
|
||||||
uint64_t round_mask;
|
uint64_t round_mask;
|
||||||
uint64_t roundeven_mask;
|
uint64_t roundeven_mask;
|
||||||
|
bool arm_althp;
|
||||||
} FloatFmt;
|
} FloatFmt;
|
||||||
|
|
||||||
/* Expand fields based on the size of exponent and fraction */
|
/* Expand fields based on the size of exponent and fraction */
|
||||||
|
@ -324,7 +327,7 @@ static inline float64 float64_pack_raw(FloatParts p)
|
||||||
static FloatParts canonicalize(FloatParts part, const FloatFmt *parm,
|
static FloatParts canonicalize(FloatParts part, const FloatFmt *parm,
|
||||||
float_status *status)
|
float_status *status)
|
||||||
{
|
{
|
||||||
if (part.exp == parm->exp_max) {
|
if (part.exp == parm->exp_max && !parm->arm_althp) {
|
||||||
if (part.frac == 0) {
|
if (part.frac == 0) {
|
||||||
part.cls = float_class_inf;
|
part.cls = float_class_inf;
|
||||||
} else {
|
} else {
|
||||||
|
@ -413,7 +416,15 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
|
||||||
}
|
}
|
||||||
frac >>= frac_shift;
|
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;
|
flags |= float_flag_overflow | float_flag_inexact;
|
||||||
if (overflow_norm) {
|
if (overflow_norm) {
|
||||||
exp = exp_max - 1;
|
exp = exp_max - 1;
|
||||||
|
@ -464,12 +475,14 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
|
||||||
|
|
||||||
case float_class_inf:
|
case float_class_inf:
|
||||||
do_inf:
|
do_inf:
|
||||||
|
assert(!parm->arm_althp);
|
||||||
exp = exp_max;
|
exp = exp_max;
|
||||||
frac = 0;
|
frac = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case float_class_qnan:
|
case float_class_qnan:
|
||||||
case float_class_snan:
|
case float_class_snan:
|
||||||
|
assert(!parm->arm_althp);
|
||||||
exp = exp_max;
|
exp = exp_max;
|
||||||
frac >>= parm->frac_shift;
|
frac >>= parm->frac_shift;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue