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 <rsand...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev