glsl: Add "built-in" functions to do fp64_to_int(fp64)
authorElie Tournier <tournier.elie@gmail.com>
Wed, 9 Aug 2017 13:22:47 +0000 (14:22 +0100)
committerMatt Turner <mattst88@gmail.com>
Thu, 10 Jan 2019 00:42:40 +0000 (16:42 -0800)
v2: use mix

Signed-off-by: Elie Tournier <elie.tournier@collabora.com>
src/compiler/glsl/float64.glsl

index 232bf18b4d3e383f7f64b494c43f42164248d1c2..72fbefd2eff9382488c81320ca22b8caf4829816 100644 (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));
+}