diff options
-rw-r--r-- | src/compiler/glsl/float64.glsl | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/src/compiler/glsl/float64.glsl b/src/compiler/glsl/float64.glsl index 232bf18b4d3..72fbefd2eff 100644 --- a/src/compiler/glsl/float64.glsl +++ b/src/compiler/glsl/float64.glsl @@ -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)); +} |