#endif
}
+/* If a shader is in the soft-fp64 path, it almost certainly has register
+ * pressure problems. Choose a method to exchange two values that does not
+ * require a temporary.
+ */
+#define EXCHANGE(a, b) \
+ do { \
+ a ^= b; \
+ b ^= a; \
+ a ^= b; \
+ } while (false)
+
/* Returns the result of adding the double-precision floating-point values
* `a' and `b'. The operation is performed according to the IEEE Standard for
* Floating-Point Arithmetic.
uint bFracHi = __extractFloat64FracHi(b);
int aExp = __extractFloat64Exp(a);
int bExp = __extractFloat64Exp(b);
- uint zFrac0 = 0u;
- uint zFrac1 = 0u;
int expDiff = aExp - bExp;
if (aSign == bSign) {
- uint zFrac2 = 0u;
+ uint zFrac0;
+ uint zFrac1;
+ uint zFrac2;
int zExp;
- bool orig_exp_diff_is_zero = (expDiff == 0);
- if (orig_exp_diff_is_zero) {
+ if (expDiff == 0) {
if (aExp == 0x7FF) {
bool propagate = ((aFracHi | bFracHi) | (aFracLo| bFracLo)) != 0u;
return mix(a, __propagateFloat64NaN(a, b), propagate);
zExp = aExp;
__shift64ExtraRightJamming(
zFrac0, zFrac1, zFrac2, 1, zFrac0, zFrac1, zFrac2);
- } else if (0 < expDiff) {
- if (aExp == 0x7FF) {
- bool propagate = (aFracHi | aFracLo) != 0u;
- return mix(a, __propagateFloat64NaN(a, b), propagate);
- }
+ } else {
+ if (0 < expDiff) {
+ if (aExp == 0x7FF) {
+ bool propagate = (aFracHi | aFracLo) != 0u;
+ return mix(a, __propagateFloat64NaN(a, b), propagate);
+ }
- expDiff = mix(expDiff, expDiff - 1, bExp == 0);
- bFracHi = mix(bFracHi | 0x00100000u, bFracHi, bExp == 0);
- __shift64ExtraRightJamming(
- bFracHi, bFracLo, 0u, expDiff, bFracHi, bFracLo, zFrac2);
- zExp = aExp;
- } else if (expDiff < 0) {
- if (bExp == 0x7FF) {
- bool propagate = (bFracHi | bFracLo) != 0u;
- return mix(__packFloat64(aSign, 0x7ff, 0u, 0u), __propagateFloat64NaN(a, b), propagate);
+ expDiff = mix(expDiff, expDiff - 1, bExp == 0);
+ bFracHi = mix(bFracHi | 0x00100000u, bFracHi, bExp == 0);
+ __shift64ExtraRightJamming(
+ bFracHi, bFracLo, 0u, expDiff, bFracHi, bFracLo, zFrac2);
+ zExp = aExp;
+ } else {
+ EXCHANGE(aFracHi, bFracHi);
+ EXCHANGE(aFracLo, bFracLo);
+ EXCHANGE(aExp, bExp);
+
+ if (aExp == 0x7FF) {
+ bool propagate = (aFracHi | aFracLo) != 0u;
+ return mix(__packFloat64(aSign, 0x7ff, 0u, 0u), __propagateFloat64NaN(a, b), propagate);
+ }
+ expDiff = mix(expDiff, expDiff + 1, bExp == 0);
+ bFracHi = mix(bFracHi | 0x00100000u, bFracHi, bExp == 0);
+ __shift64ExtraRightJamming(
+ bFracHi, bFracLo, 0u, - expDiff, bFracHi, bFracLo, zFrac2);
+ zExp = aExp;
}
- expDiff = mix(expDiff, expDiff + 1, aExp == 0);
- aFracHi = mix(aFracHi | 0x00100000u, aFracHi, aExp == 0);
- __shift64ExtraRightJamming(
- aFracHi, aFracLo, 0u, - expDiff, aFracHi, aFracLo, zFrac2);
- zExp = bExp;
- }
- if (!orig_exp_diff_is_zero) {
+
aFracHi |= 0x00100000u;
__add64(aFracHi, aFracLo, bFracHi, bFracLo, zFrac0, zFrac1);
--zExp;
__shortShift64Left(aFracHi, aFracLo, 10, aFracHi, aFracLo);
__shortShift64Left(bFracHi, bFracLo, 10, bFracHi, bFracLo);
if (0 < expDiff) {
+ uint zFrac0;
+ uint zFrac1;
+
if (aExp == 0x7FF) {
bool propagate = (aFracHi | aFracLo) != 0u;
return mix(a, __propagateFloat64NaN(a, b), propagate);
return __normalizeRoundAndPackFloat64(aSign, zExp - 10, zFrac0, zFrac1);
}
if (expDiff < 0) {
+ uint zFrac0;
+ uint zFrac1;
+
if (bExp == 0x7FF) {
bool propagate = (bFracHi | bFracLo) != 0u;
return mix(__packFloat64(aSign ^ 0x80000000u, 0x7ff, 0u, 0u), __propagateFloat64NaN(a, b), propagate);
}
bExp = mix(bExp, 1, aExp == 0);
aExp = mix(aExp, 1, aExp == 0);
- bool zexp_normal = false;
- bool blta = true;
+
+ uint zFrac0;
+ uint zFrac1;
+ uint sign_of_difference = 0;
if (bFracHi < aFracHi) {
__sub64(aFracHi, aFracLo, bFracHi, bFracLo, zFrac0, zFrac1);
- zexp_normal = true;
}
else if (aFracHi < bFracHi) {
__sub64(bFracHi, bFracLo, aFracHi, aFracLo, zFrac0, zFrac1);
- blta = false;
- zexp_normal = true;
+ sign_of_difference = 0x80000000;
}
- else if (bFracLo < aFracLo) {
+ else if (bFracLo <= aFracLo) {
+ /* It is possible that zFrac0 and zFrac1 may be zero after this. */
__sub64(aFracHi, aFracLo, bFracHi, bFracLo, zFrac0, zFrac1);
- zexp_normal = true;
}
- else if (aFracLo < bFracLo) {
+ else {
__sub64(bFracHi, bFracLo, aFracHi, aFracLo, zFrac0, zFrac1);
- blta = false;
- zexp_normal = true;
+ sign_of_difference = 0x80000000;
}
- zExp = mix(bExp, aExp, blta);
- aSign = mix(aSign ^ 0x80000000u, aSign, blta);
+ zExp = mix(bExp, aExp, sign_of_difference == 0u);
+ aSign ^= sign_of_difference;
uint64_t retval_0 = __packFloat64(uint(FLOAT_ROUNDING_MODE == FLOAT_ROUND_DOWN) << 31, 0, 0u, 0u);
uint64_t retval_1 = __normalizeRoundAndPackFloat64(aSign, zExp - 11, zFrac0, zFrac1);
- return mix(retval_0, retval_1, zexp_normal);
+ return mix(retval_0, retval_1, zFrac0 != 0u || zFrac1 != 0u);
}
}
uint64_t
__ffloor64(uint64_t a)
{
- bool is_positive = __fge64(a, 0ul);
+ /* The big assumtion is that when 'a' is NaN, __ftrunc(a) returns a. Based
+ * on that assumption, NaN values that don't have the sign bit will safely
+ * return NaN (identity). This is guarded by RELAXED_NAN_PROPAGATION
+ * because otherwise the NaN should have the "signal" bit set. The
+ * __fadd64 will ensure that occurs.
+ */
+ bool is_positive =
+#if defined RELAXED_NAN_PROPAGATION
+ int(unpackUint2x32(a).y) >= 0
+#else
+ __fge64(a, 0ul)
+#endif
+ ;
uint64_t tr = __ftrunc64(a);
if (is_positive || __feq64(tr, a)) {
uint64_t
__fmin64(uint64_t a, uint64_t b)
{
- if (__is_nan(a)) return b;
- if (__is_nan(b)) return a;
+ /* This weird layout matters. Doing the "obvious" thing results in extra
+ * flow control being inserted to implement the short-circuit evaluation
+ * rules. Flow control is bad!
+ */
+ bool b_nan = __is_nan(b);
+ bool a_lt_b = __flt64_nonnan(a, b);
+ bool a_nan = __is_nan(a);
- if (__flt64_nonnan(a, b)) return a;
- return b;
+ return (b_nan || a_lt_b) && !a_nan ? a : b;
}
uint64_t
__fmax64(uint64_t a, uint64_t b)
{
- if (__is_nan(a)) return b;
- if (__is_nan(b)) return a;
+ /* This weird layout matters. Doing the "obvious" thing results in extra
+ * flow control being inserted to implement the short-circuit evaluation
+ * rules. Flow control is bad!
+ */
+ bool b_nan = __is_nan(b);
+ bool a_lt_b = __flt64_nonnan(a, b);
+ bool a_nan = __is_nan(a);
- if (__flt64_nonnan(a, b)) return b;
- return a;
+ return (b_nan || a_lt_b) && !a_nan ? b : a;
}
uint64_t