Handle constant folding arithmetic involving infinity
Constant folding arithmetic operations that involve infinity are now
handled correctly in the cases where the result is infinity or zero.
The implementation mostly relies on C++ to implement IEEE float
arithmetic correctly so that unnecessary overhead is avoided.
Constant folding arithmetic operations that result in overflow now
issue a warning but result in infinity. This is not mandated by the
spec but is a reasonable choice since it is the behavior of the
default IEEE rounding mode.
Constant folding arithmetic operations that result in NaN in IEEE will
generate a warning but the NaN is kept. This is also not mandated by
the spec, but is among the allowed behaviors.
There's no special handling for ESSL 1.00. ESSL 1.00 doesn't really
have the concept of NaN, but since it is not feasible to control
generating NaNs at shader run time either way, it should not be a big
issue if constant folding may generate them as well.
TEST=angle_unittests
BUG=chromium:661857
Change-Id: I06116c6fdd02f224939d4a651e4e62f2fd4c98a8
Reviewed-on: https://chromium-review.googlesource.com/414911
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ConstantUnion.cpp b/src/compiler/translator/ConstantUnion.cpp
index 66f444b..dfebbc0 100644
--- a/src/compiler/translator/ConstantUnion.cpp
+++ b/src/compiler/translator/ConstantUnion.cpp
@@ -7,7 +7,6 @@
#include "compiler/translator/ConstantUnion.h"
-#include "base/numerics/safe_math.h"
#include "common/mathutil.h"
#include "compiler/translator/Diagnostics.h"
@@ -17,52 +16,46 @@
namespace
{
-template <typename T>
-T CheckedSum(base::CheckedNumeric<T> lhs,
- base::CheckedNumeric<T> rhs,
- TDiagnostics *diag,
- const TSourceLoc &line)
+float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
{
- ASSERT(lhs.IsValid() && rhs.IsValid());
- auto result = lhs + rhs;
- if (!result.IsValid())
+ float result = lhs + rhs;
+ if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
{
- diag->error(line, "Addition out of range", "*", "");
- return 0;
+ diag->warning(line, "Constant folded undefined addition generated NaN", "+", "");
}
- return result.ValueOrDefault(0);
+ else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
+ {
+ diag->warning(line, "Constant folded addition overflowed to infinity", "+", "");
+ }
+ return result;
}
-template <typename T>
-T CheckedDiff(base::CheckedNumeric<T> lhs,
- base::CheckedNumeric<T> rhs,
- TDiagnostics *diag,
- const TSourceLoc &line)
+float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
{
- ASSERT(lhs.IsValid() && rhs.IsValid());
- auto result = lhs - rhs;
- if (!result.IsValid())
+ float result = lhs - rhs;
+ if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
{
- diag->error(line, "Difference out of range", "*", "");
- return 0;
+ diag->warning(line, "Constant folded undefined subtraction generated NaN", "-", "");
}
- return result.ValueOrDefault(0);
+ else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
+ {
+ diag->warning(line, "Constant folded subtraction overflowed to infinity", "-", "");
+ }
+ return result;
}
-template <typename T>
-T CheckedMul(base::CheckedNumeric<T> lhs,
- base::CheckedNumeric<T> rhs,
- TDiagnostics *diag,
- const TSourceLoc &line)
+float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
{
- ASSERT(lhs.IsValid() && rhs.IsValid());
- auto result = lhs * rhs;
- if (!result.IsValid())
+ float result = lhs * rhs;
+ if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
{
- diag->error(line, "Multiplication out of range", "*", "");
- return 0;
+ diag->warning(line, "Constant folded undefined multiplication generated NaN", "*", "");
}
- return result.ValueOrDefault(0);
+ else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
+ {
+ diag->warning(line, "Constant folded multiplication overflowed to infinity", "*", "");
+ }
+ return result;
}
} // anonymous namespace
@@ -293,7 +286,7 @@
returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
break;
case EbtFloat:
- returnValue.setFConst(CheckedSum<float>(lhs.fConst, rhs.fConst, diag, line));
+ returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));
break;
default:
UNREACHABLE();
@@ -319,7 +312,7 @@
returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
break;
case EbtFloat:
- returnValue.setFConst(CheckedDiff<float>(lhs.fConst, rhs.fConst, diag, line));
+ returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));
break;
default:
UNREACHABLE();
@@ -347,7 +340,7 @@
returnValue.setUConst(lhs.uConst * rhs.uConst);
break;
case EbtFloat:
- returnValue.setFConst(CheckedMul<float>(lhs.fConst, rhs.fConst, diag, line));
+ returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));
break;
default:
UNREACHABLE();