Support constant folding of trigonometry built-ins
This change adds constant folding support for trigonometry built-in
functions. Constant folding for these functions also fixes constant
expression issues where constant initializer is a built-in trignometry
function whose arguments are all constant expressions.
BUG=angleproject:913
TEST= dEQP tests
dEQP-GLES3.functional.shaders.constant_expressions.builtin_functions.angle_and_trigonometry*
(112 out of 120 tests pass with this change)
Change-Id: I66275b2ae9faecef63d76763d21a9b67d9bb68fa
Reviewed-on: https://chromium-review.googlesource.com/265392
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 708dcb3..c7fea1c 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -10,6 +10,7 @@
#include <float.h>
#include <limits.h>
+#include <math.h>
#include <algorithm>
#include "compiler/translator/HashNames.h"
@@ -19,6 +20,10 @@
namespace
{
+const float kPi = 3.14159265358979323846f;
+const float kDegreesToRadiansMultiplier = kPi / 180.0f;
+const float kRadiansToDegreesMultiplier = 180.0f / kPi;
+
TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
{
return left > right ? left : right;
@@ -1185,6 +1190,100 @@
}
break;
+ case EOpRadians:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
+ break;
+ }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpDegrees:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
+ break;
+ }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpSin:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::sin), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpCos:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::cos), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpTan:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::tan), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAsin:
+ // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && std::abs(unionArray[i].getFConst()) > 1.0f)
+ tempConstArray[i].setFConst(0.0f);
+ else if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::asin), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAcos:
+ // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && std::abs(unionArray[i].getFConst()) > 1.0f)
+ tempConstArray[i].setFConst(0.0f);
+ else if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::acos), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAtan:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::atan), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpSinh:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::sinh), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpCosh:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::cosh), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpTanh:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::tanh), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAsinh:
+ if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::asinh), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAcosh:
+ // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
+ tempConstArray[i].setFConst(0.0f);
+ else if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::acosh), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAtanh:
+ // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && std::abs(unionArray[i].getFConst()) >= 1.0f)
+ tempConstArray[i].setFConst(0.0f);
+ else if (!foldFloatTypeUnary(unionArray[i], static_cast<FloatTypeUnaryFunc>(&std::atanh), infoSink, &tempConstArray[i]))
+ return nullptr;
+ break;
+
default:
return NULL;
}
@@ -1195,6 +1294,23 @@
}
}
+bool TIntermConstantUnion::foldFloatTypeUnary(const ConstantUnion ¶meter, FloatTypeUnaryFunc builtinFunc,
+ TInfoSink &infoSink, ConstantUnion *result) const
+{
+ ASSERT(builtinFunc);
+
+ if (getType().getBasicType() == EbtFloat)
+ {
+ result->setFConst(builtinFunc(parameter.getFConst()));
+ return true;
+ }
+
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return false;
+}
+
// static
TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
{