Signed-off-by: Samuel Iglesias Gonsálvez <sigles...@igalia.com> --- src/util/half_float.c | 74 +++++++++++++++++++++++++++++++++++++++++++ src/util/half_float.h | 7 ++++ 2 files changed, 81 insertions(+)
diff --git a/src/util/half_float.c b/src/util/half_float.c index 63aec5c5c14..5fdcb20045b 100644 --- a/src/util/half_float.c +++ b/src/util/half_float.c @@ -125,6 +125,80 @@ _mesa_float_to_half(float val) return result; } +uint16_t +_mesa_float_to_float16_rtz(float val) +{ + const fi_type fi = {val}; + const int flt_m = fi.i & 0x7fffff; + const int flt_e = (fi.i >> 23) & 0xff; + const int flt_s = (fi.i >> 31) & 0x1; + int s, e, m = 0; + uint16_t result; + + /* sign bit */ + s = flt_s; + + /* handle special cases */ + if ((flt_e == 0) && (flt_m == 0)) { + /* zero */ + /* m = 0; - already set */ + e = 0; + } + else if ((flt_e == 0) && (flt_m != 0)) { + /* denorm -- denorm float maps to 0 half */ + /* m = 0; - already set */ + e = 0; + } + else if ((flt_e == 0xff) && (flt_m == 0)) { + /* infinity */ + /* m = 0; - already set */ + e = 31; + } + else if ((flt_e == 0xff) && (flt_m != 0)) { + /* NaN */ + m = 1; + e = 31; + } + else { + /* regular number */ + const int new_exp = flt_e - 127; + if (new_exp < -14) { + /* The float32 lies in the range (0.0, min_normal16) and is rounded + * to a nearby float16 value. The result will be either zero, subnormal, + * or normal. + */ + e = 0; + m = truncf((1 << 24) * fabsf(fi.f)); + } + else if (new_exp > 15) { + /* map this value to infinity */ + /* m = 0; - already set */ + e = 31; + } + else { + /* The float32 lies in the range + * [min_normal16, max_normal16 + max_step16) + * and is rounded to a nearby float16 value. The result will be + * either normal or infinite. + */ + e = new_exp + 15; + m = truncf(flt_m / (float) (1 << 13)); + } + } + + assert(0 <= m && m <= 1024); + if (m == 1024) { + /* The float32 was rounded upwards into the range of the next exponent, + * so bump the exponent. This correctly handles the case where f32 + * should be rounded up to float16 infinity. + */ + ++e; + m = 0; + } + + result = (s << 15) | (e << 10) | m; + return result; +} /** * Convert a 2-byte half float to a 4-byte float. diff --git a/src/util/half_float.h b/src/util/half_float.h index 01557424735..df90802bf34 100644 --- a/src/util/half_float.h +++ b/src/util/half_float.h @@ -39,6 +39,13 @@ uint16_t _mesa_float_to_half(float val); float _mesa_half_to_float(uint16_t val); uint8_t _mesa_half_to_unorm8(uint16_t v); uint16_t _mesa_uint16_div_64k_to_half(uint16_t v); +uint16_t _mesa_float_to_float16_rtz(float val); + +static inline uint16_t +_mesa_float_to_float16_rtne(float val) +{ + return _mesa_float_to_half(val); +} static inline bool _mesa_half_is_negative(uint16_t h) -- 2.19.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev