[Mesa-dev] [PATCH] glsl: Fix type error when lowering integer divisions
Jose Fonseca
jfonseca at vmware.com
Mon Aug 15 08:50:58 PDT 2011
----- Original Message -----
> On 13 August 2011 09:58, Kenneth Graunke <kenneth at whitecape.org>
> wrote:
> > On 08/12/2011 10:38 AM, Paul Berry wrote:
> >>
> >> This patch fixes a bug when lowering an integer division:
> >>
> >> x/y
> >>
> >> to a multiplication by a reciprocal:
> >>
> >> int(float(x)*reciprocal(float(y)))
> >>
> >> If x was a a plain int and y was an ivecN, the lowering pass
> >> incorrectly assigned the type of the product to be float, when in
> >> fact
> >> it should be vecN. This caused mesa to abort with an IR
> >> validation
> >> error.
> >>
> >> Fixes piglit tests {fs,vs}-op-div-int-ivec{2,3,4}.
> >
> > Good catch, Paul! Thanks again for writing all these test cases.
> >
> > Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
> >
> > Come to think of it, we may want to avoid this altogether on i965.
> > The
> > mathbox has an INT DIV message that computes integer quotient and
> > remainder...so we can support it natively.
> >
> > I guess the question is "which is faster?". My intuition says that
> > using
> > INT DIV will be faster on Gen6+, possibly on Gen5, and slower on
> > Gen4/G45.
> > AFAICT on Gen5+ you can compute quotient & remainder separately (3
> > or 4
> > rounds) while on Gen4 you always have to compute both (3 + 4 = 7
> > rounds?).
> > Meanwhile RCP is 2 rounds. Not only is that more rounds, it means
> > hogging
> > the shared mathbox for longer.
>
> Accuracy is also a question. Our current technique of multiplying by
> the reciprocal doesn't work for some denominators because of rounding
> errors in computing the reciprocal. For example, try to write a
> piglit tests that computes 77/77. On Gen5 hardware, at least, this
> produces zero. The reason is because rounding errors in computing
> the
> floating point reciprocal mean that 77*reciprocal(77) is actually
> slightly less than 1.0, so it gets rounded down to zero when it's
> converted back to an int. Note: I believe the smallest integer for
> which rounding errors cause n*reciprocal(n) to be less than 1.0 is
> n=25, which probably explains why we haven't noticed this bug before.
In places you don't have native int division support, you could use one Newton-Raphson iteration step for almost accurate results, assuggested accuracy of SSE2's RCPPS instructions. See for reference the following llvmpipe comment:
/**
* Do one Newton-Raphson step to improve reciprocate precision:
*
* x_{i+1} = x_i * (2 - a * x_i)
*
* XXX: Unfortunately this won't give IEEE-754 conformant results for 0 or
* +/-Inf, giving NaN instead. Certain applications rely on this behavior,
* such as Google Earth, which does RCP(RSQRT(0.0) when drawing the Earth's
* halo. It would be necessary to clamp the argument to prevent this.
*
* See also:
* - http://en.wikipedia.org/wiki/Division_(digital)#Newton.E2.80.93Raphson_division
* - http://softwarecommunity.intel.com/articles/eng/1818.htm
*/
The softwarecommunity.intel.com link is down, but the "Intel® 64 and IA-32 Architectures Optimization Reference Manual" also documents this.
As mentioned, the N-R iteration gives wrong results for the reciprocate of +/-inf, but that's guaranteed to never happen when the arguments are integers encoded as floats.
Jose
More information about the mesa-dev
mailing list