[Mesa-dev] [PATCH] softpipe: Do round-to-even, not round-up.

Olivier Galibert galibert at pobox.com
Fri May 18 02:43:28 PDT 2012


Fixes the piglit roundEven tests.

Signed-off-by: Olivier Galibert <galibert at pobox.com>
---
 src/gallium/auxiliary/tgsi/tgsi_exec.c |   76 ++++++++++++++++++++++++++++++--
 1 file changed, 72 insertions(+), 4 deletions(-)

diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index 5e23f5d..7311f5f 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -316,14 +316,82 @@ micro_rcp(union tgsi_exec_channel *dst,
    dst->f[3] = 1.0f / src->f[3];
 }
 
+static float
+ieee754_fp32_round_half_to_even(float v)
+{
+   unsigned int iv;
+   int exponent;
+   unsigned int one_half_bit_mask, fractional_bits_mask;
+   assert(sizeof(v) == 4);
+   assert(sizeof(iv) == 4);
+   memcpy(&iv, &v, 4);
+
+   exponent = ((iv >> 23) & 0xff) - 0x7f;
+
+   // Integer or nan, return unscathed
+   if (exponent >= 23)
+      return v;
+
+   // abs(v) < 0.5, zero, or denormal, return 0
+   if (exponent < -1)
+      return 0;
+
+   // abs(v) >= 0.5 and < 1
+   if (exponent == -1) {
+      // Not exactly 0.5 round to the to appropriate 1, otherwise to 0
+      if (iv & 0x7fffff) {
+         iv = (iv & 0x80000000) | 0x3f800000;
+         memcpy(&v, &iv, 4);
+         return v;
+      } else
+         return 0;
+   }
+
+   one_half_bit_mask   = 0x800000 >> (exponent+1);
+   fractional_bits_mask = 0xffffff >> (exponent+1);
+
+   // Fractional part under 0.5, cutoff the fractional part
+   if (!(iv & one_half_bit_mask)) {
+      iv = iv & ~fractional_bits_mask;
+      memcpy(&v, &iv, 4);
+      return v;
+   }
+
+   // Fractional part over 0.5, round up
+   if ((iv & fractional_bits_mask) != one_half_bit_mask) {
+      // Round up by setting the fractional bits to 1 and incrementing.
+      // The exponent will be automagically incremented when needed
+      // through carry propagation.
+      iv = (iv | fractional_bits_mask) + 1;
+      memcpy(&v, &iv, 4);
+      return v;
+   }
+
+   // Fractional part exactly 0.5, round towards even.
+
+   // Test the bit just over the decimal point to test for oddness.  It
+   // works for the borderline case 1.5 because the exponent is 127 in
+   // that case, i.e. the tested bit is the expected 1.
+
+   // Odd, round up
+   if (iv & (one_half_bit_mask << 1))
+      iv = (iv | fractional_bits_mask) + 1;
+   // Even, round down
+   else
+      iv = iv & ~fractional_bits_mask;
+
+   memcpy(&v, &iv, 4);
+   return v;
+}
+
 static void
 micro_rnd(union tgsi_exec_channel *dst,
           const union tgsi_exec_channel *src)
 {
-   dst->f[0] = floorf(src->f[0] + 0.5f);
-   dst->f[1] = floorf(src->f[1] + 0.5f);
-   dst->f[2] = floorf(src->f[2] + 0.5f);
-   dst->f[3] = floorf(src->f[3] + 0.5f);
+   dst->f[0] = ieee754_fp32_round_half_to_even(src->f[0]);
+   dst->f[1] = ieee754_fp32_round_half_to_even(src->f[1]);
+   dst->f[2] = ieee754_fp32_round_half_to_even(src->f[2]);
+   dst->f[3] = ieee754_fp32_round_half_to_even(src->f[3]);
 }
 
 static void
-- 
1.7.10.rc3.1.gb306



More information about the mesa-dev mailing list