glsl: Add "built-in" functions to do fp64_to_int(fp64)

v2: use mix

Signed-off-by: Elie Tournier <elie.tournier@collabora.com>
This commit is contained in:
Elie Tournier 2017-08-09 14:22:47 +01:00 committed by Matt Turner
parent cbf090b809
commit 773190f281
1 changed files with 41 additions and 0 deletions

View File

@ -880,3 +880,44 @@ __uint_to_fp64(uint a)
return __packFloat64(0u, 0x432 - shiftDist, aHigh, aLow);
}
/* Returns the result of converting the double-precision floating-point value
* `a' to the 32-bit two's complement integer format. The conversion is
* performed according to the IEEE Standard for Floating-Point Arithmetic---
* which means in particular that the conversion is rounded according to the
* current rounding mode. If `a' is a NaN, the largest positive integer is
* returned. Otherwise, if the conversion overflows, the largest integer with
* the same sign as `a' is returned.
*/
int
__fp64_to_int(uint64_t a)
{
uint aFracLo = __extractFloat64FracLo(a);
uint aFracHi = __extractFloat64FracHi(a);
int aExp = __extractFloat64Exp(a);
uint aSign = __extractFloat64Sign(a);
uint absZ = 0u;
uint aFracExtra = 0u;
int shiftCount = aExp - 0x413;
if (0 <= shiftCount) {
if (0x41E < aExp) {
if ((aExp == 0x7FF) && bool(aFracHi | aFracLo))
aSign = 0u;
return mix(0x7FFFFFFF, 0x80000000, bool(aSign));
}
__shortShift64Left(aFracHi | 0x00100000u, aFracLo, shiftCount, absZ, aFracExtra);
} else {
if (aExp < 0x3FF)
return 0;
aFracHi |= 0x00100000u;
aFracExtra = ( aFracHi << (shiftCount & 31)) | aFracLo;
absZ = aFracHi >> (- shiftCount);
}
int z = mix(int(absZ), -int(absZ), (aSign != 0u));
int nan = mix(0x7FFFFFFF, 0x80000000, bool(aSign));
return mix(z, nan, bool(aSign ^ uint(z < 0)) && bool(z));
}