[Mesa-dev] [PATCH 11/28] util: added float to float16 conversions with RTZ and RTNE

Samuel Iglesias Gonsálvez siglesias at igalia.com
Wed Dec 5 15:55:26 UTC 2018


Signed-off-by: Samuel Iglesias Gonsálvez <siglesias at 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



More information about the mesa-dev mailing list