On Fri, 15 Feb 2019 at 19:23, Richard Henderson
<[email protected]> wrote:
>
> Note that float16_to_float32 rightly squashes SNaN to QNaN.
> But of course pickNaNMulAdd, for ARM, selects SNaNs first.
> So we have to preserve SNaN long enough for the correct NaN
> to be selected. Thus float16_to_float32_by_bits.
>
> Signed-off-by: Richard Henderson <[email protected]>
> ---
> +/*
> + * Convert float16 to float32, raising no exceptions and
> + * preserving exceptional values, including SNaN.
> + * This is effectively an unpack+repack operation.
> + */
> +static float32 float16_to_float32_by_bits(uint32_t f16)
> +{
> + const int f16_bias = 15;
> + const int f32_bias = 127;
> + uint32_t sign = extract32(f16, 15, 1);
> + uint32_t exp = extract32(f16, 10, 5);
> + uint32_t frac = extract32(f16, 0, 10);
> +
> + if (exp == 0x1f) {
> + /* Inf or NaN */
> + exp = 0xff;
> + } else if (exp == 0) {
> + /* Zero or denormal. */
> + if (frac != 0) {
> + /*
> + * Denormal; these are all normal float32.
> + * Shift the fraction so that the msb is at bit 11,
> + * then remove bit 11 as the implicit bit of the
> + * normalized float32. Note that we still go through
> + * the shift for normal numbers below, to put the
> + * float32 fraction at the right place.
> + */
> + int shift = clz32(frac) - 21;
> + frac = (frac << shift) & 0x3ff;
> + exp = f32_bias - f16_bias - shift + 1;
> + }
> + } else {
> + /* Normal number; adjust the bias. */
> + exp += f32_bias - f16_bias;
> + }
> + sign <<= 31;
> + exp <<= 23;
> + frac <<= 23 - 10;
> +
> + return sign | exp | frac;
> +}
Shouldn't we be observing FPCR.FZ16 here and flushing
denormal float16 inputs to zero if it's set ?
(In the pseudocode this happens in FPUnpackBase, called
from FPUnpack.)
NB: this might be awkward because for A64 we need to use the
fpstatus with FZ16 in it (vfp.fp_status_f16) for the float16
inputs, but the one with the normal FZ bit (vfp.fp_status)
for the float32 input.
thanks
-- PMM