[Mesa-dev] [PATCH] util: Fix fallback iround handling of integral inputs

Richard Sandiford rsandifo at linux.vnet.ibm.com
Mon Jul 21 08:53:38 PDT 2014


lp_build_iround has a fallback case that tries to emulate a round-to-nearest
float->int conversion by adding 0.5 and using a truncating fptosi.  For odd
numbers in the range [2^23, 2^24], which are already integral, this has
the effect of adding 1 to the integer, since the result of adding 0.5 is
exactly half way between two representable values and the tie goes to even.
This includes the important special case of (float)0xffffff, which is the
maximum depth in a z24s8 format.  I.e. calling iround on (float)0xffffff
gives 0x1000000 rather than 0xffffff when the fallback is used.

This patch only uses the x+0.5 trick if the ulp of the input is fractional.
This still doesn't give ties-to-even semantics, but that doesn't seem to
matter much in practice.

Signed-off-by: Richard Sandiford <rsandifo at linux.vnet.ibm.com>
---
 src/gallium/auxiliary/gallivm/lp_bld_arit.c | 43 ++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.c b/src/gallium/auxiliary/gallivm/lp_bld_arit.c
index 9ef8628..82ddb5a 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_arit.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.c
@@ -2181,25 +2181,36 @@ lp_build_iround(struct lp_build_context *bld,
       res = lp_build_round_arch(bld, a, LP_BUILD_ROUND_NEAREST);
    }
    else {
-      LLVMValueRef half;
+      struct lp_type int_type = lp_int_type(type);
+      LLVMTypeRef vec_type = bld->vec_type;
+      unsigned mantissa = lp_mantissa(type);
+      unsigned expbits = type.width - mantissa - 1;
+      unsigned bias = (1 << (expbits - 1)) - 1;
+      LLVMValueRef mask = lp_build_const_int_vec(bld->gallivm, type,
+                               (unsigned long long)1 << (type.width - 1));
+      /* Smallest value with an integral ulp */
+      LLVMValueRef abslimit = lp_build_const_int_vec(bld->gallivm, type,
+                               (bias + mantissa) << mantissa);
+      LLVMValueRef half, sign, absa, fractulp;
 
       half = lp_build_const_vec(bld->gallivm, type, 0.5);
 
-      if (type.sign) {
-         LLVMTypeRef vec_type = bld->vec_type;
-         LLVMValueRef mask = lp_build_const_int_vec(bld->gallivm, type,
-                                    (unsigned long long)1 << (type.width - 1));
-         LLVMValueRef sign;
-
-         /* get sign bit */
-         sign = LLVMBuildBitCast(builder, a, int_vec_type, "");
-         sign = LLVMBuildAnd(builder, sign, mask, "");
-
-         /* sign * 0.5 */
-         half = LLVMBuildBitCast(builder, half, int_vec_type, "");
-         half = LLVMBuildOr(builder, sign, half, "");
-         half = LLVMBuildBitCast(builder, half, vec_type, "");
-      }
+      assert(type.sign);
+
+      /* get sign bit */
+      sign = LLVMBuildBitCast(builder, a, int_vec_type, "");
+      sign = LLVMBuildAnd(builder, sign, mask, "");
+
+      /* get "ulp is fractional" */
+      absa = lp_build_abs(bld, a);
+      absa = LLVMBuildBitCast(builder, absa, int_vec_type, "");
+      fractulp = lp_build_compare(bld->gallivm, int_type, PIPE_FUNC_LESS, absa, abslimit);
+
+      /* (sign * 0.5) & intulp */
+      half = LLVMBuildBitCast(builder, half, int_vec_type, "");
+      half = LLVMBuildOr(builder, sign, half, "");
+      half = LLVMBuildAnd(builder, half, fractulp, "");
+      half = LLVMBuildBitCast(builder, half, vec_type, "");
 
       res = LLVMBuildFAdd(builder, a, half, "");
    }
-- 
1.8.3.1



More information about the mesa-dev mailing list