mesa: reimplement IROUND(), add F_TO_I()

The different implementations of IROUND() behaved differently and in
the case of fistp, depended on the current x86 FPU rounding mode.
This caused some tests like piglit roundmode-pixelstore and
roundmode-getintegerv to fail on 32-bit x86 but pass on 64-bit x86.

Now IROUND() always rounds to the nearest integer (away from zero).
The new F_TO_I function converts a float to an int by whatever means
is fastest.  We'll use this where we're more concerned with performance
and not too worried to how the conversion is done.

Reviewed-by: José Fonseca <jfonseca@vmware.com>
This commit is contained in:
Brian Paul 2012-05-18 14:39:41 -06:00
parent 31d59c78f0
commit 699c1894ee

View file

@ -285,19 +285,47 @@ static inline int GET_FLOAT_BITS( float x )
#endif
/***
*** IROUND: return (as an integer) float rounded to nearest integer
***/
/**
* Convert float to int by rounding to nearest integer, away from zero.
*/
static inline int IROUND(float f)
{
return (int) ((f >= 0.0F) ? (f + 0.5F) : (f - 0.5F));
}
/**
* Convert float to int64 by rounding to nearest integer.
*/
static inline GLint64 IROUND64(float f)
{
return (GLint64) ((f >= 0.0F) ? (f + 0.5F) : (f - 0.5F));
}
/**
* Convert positive float to int by rounding to nearest integer.
*/
static inline int IROUND_POS(float f)
{
assert(f >= 0.0F);
return (int) (f + 0.5F);
}
/**
* Convert float to int using a fast method. The rounding mode may vary.
* XXX We could use an x86-64/SSE2 version here.
*/
#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
static inline int iround(float f)
static inline int F_TO_I(float f)
{
int r;
__asm__ ("fistpl %0" : "=m" (r) : "t" (f) : "st");
return r;
}
#define IROUND(x) iround(x)
#elif defined(USE_X86_ASM) && defined(_MSC_VER)
static inline int iround(float f)
static inline int F_TO_I(float f)
{
int r;
_asm {
@ -306,9 +334,8 @@ static inline int iround(float f)
}
return r;
}
#define IROUND(x) iround(x)
#elif defined(__WATCOMC__) && defined(__386__)
long iround(float f);
long F_TO_I(float f);
#pragma aux iround = \
"push eax" \
"fistp dword ptr [esp]" \
@ -316,20 +343,8 @@ long iround(float f);
parm [8087] \
value [eax] \
modify exact [eax];
#define IROUND(x) iround(x)
#else
#define IROUND(f) ((int) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
#endif
#define IROUND64(f) ((GLint64) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
/***
*** IROUND_POS: return (as an integer) positive float rounded to nearest int
***/
#ifdef DEBUG
#define IROUND_POS(f) (assert((f) >= 0.0F), IROUND(f))
#else
#define IROUND_POS(f) (IROUND(f))
#define F_TO_I(f) IROUND(f)
#endif