summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp')
-rw-r--r--3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp992
1 files changed, 992 insertions, 0 deletions
diff --git a/3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp b/3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp
new file mode 100644
index 00000000000..61b6f67e794
--- /dev/null
+++ b/3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp
@@ -0,0 +1,992 @@
+//
+//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
+//Copyright (C) 2012-2013 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "localintermediate.h"
+#include <cmath>
+#include <cfloat>
+#include <cstdlib>
+
+namespace {
+
+using namespace glslang;
+
+typedef union {
+ double d;
+ int i[2];
+} DoubleIntUnion;
+
+// Some helper functions
+
+bool isNan(double x)
+{
+ DoubleIntUnion u;
+ // tough to find a platform independent library function, do it directly
+ u.d = x;
+ int bitPatternL = u.i[0];
+ int bitPatternH = u.i[1];
+ return (bitPatternH & 0x7ff80000) == 0x7ff80000 &&
+ ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0);
+}
+
+bool isInf(double x)
+{
+ DoubleIntUnion u;
+ // tough to find a platform independent library function, do it directly
+ u.d = x;
+ int bitPatternL = u.i[0];
+ int bitPatternH = u.i[1];
+ return (bitPatternH & 0x7ff00000) == 0x7ff00000 &&
+ (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0;
+}
+
+const double pi = 3.1415926535897932384626433832795;
+
+} // end anonymous namespace
+
+
+namespace glslang {
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the node to keep using, which may or may not be the node passed in.
+//
+// Note: As of version 1.2, all constant operations must be folded. It is
+// not opportunistic, but rather a semantic requirement.
+//
+
+//
+// Do folding between a pair of nodes.
+// 'this' is the left-hand operand and 'rightConstantNode' is the right-hand operand.
+//
+// Returns a new node representing the result.
+//
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* rightConstantNode) const
+{
+ // For most cases, the return type matches the argument type, so set that
+ // up and just code to exceptions below.
+ TType returnType;
+ returnType.shallowCopy(getType());
+
+ //
+ // A pair of nodes is to be folded together
+ //
+
+ const TIntermConstantUnion *rightNode = rightConstantNode->getAsConstantUnion();
+ TConstUnionArray leftUnionArray = getConstArray();
+ TConstUnionArray rightUnionArray = rightNode->getConstArray();
+
+ // Figure out the size of the result
+ int newComps;
+ int constComps;
+ switch(op) {
+ case EOpMatrixTimesMatrix:
+ newComps = rightNode->getMatrixCols() * getMatrixRows();
+ break;
+ case EOpMatrixTimesVector:
+ newComps = getMatrixRows();
+ break;
+ case EOpVectorTimesMatrix:
+ newComps = rightNode->getMatrixCols();
+ break;
+ default:
+ newComps = getType().computeNumComponents();
+ constComps = rightConstantNode->getType().computeNumComponents();
+ if (constComps == 1 && newComps > 1) {
+ // for a case like vec4 f = vec4(2,3,4,5) + 1.2;
+ TConstUnionArray smearedArray(newComps, rightNode->getConstArray()[0]);
+ rightUnionArray = smearedArray;
+ } else if (constComps > 1 && newComps == 1) {
+ // for a case like vec4 f = 1.2 + vec4(2,3,4,5);
+ newComps = constComps;
+ rightUnionArray = rightNode->getConstArray();
+ TConstUnionArray smearedArray(newComps, getConstArray()[0]);
+ leftUnionArray = smearedArray;
+ returnType.shallowCopy(rightNode->getType());
+ }
+ break;
+ }
+
+ TConstUnionArray newConstArray(newComps);
+ TType constBool(EbtBool, EvqConst);
+
+ switch(op) {
+ case EOpAdd:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] + rightUnionArray[i];
+ break;
+ case EOpSub:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] - rightUnionArray[i];
+ break;
+
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] * rightUnionArray[i];
+ break;
+ case EOpMatrixTimesMatrix:
+ for (int row = 0; row < getMatrixRows(); row++) {
+ for (int column = 0; column < rightNode->getMatrixCols(); column++) {
+ double sum = 0.0f;
+ for (int i = 0; i < rightNode->getMatrixRows(); i++)
+ sum += leftUnionArray[i * getMatrixRows() + row].getDConst() * rightUnionArray[column * rightNode->getMatrixRows() + i].getDConst();
+ newConstArray[column * getMatrixRows() + row].setDConst(sum);
+ }
+ }
+ returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, rightNode->getMatrixCols(), getMatrixRows()));
+ break;
+ case EOpDiv:
+ for (int i = 0; i < newComps; i++) {
+ switch (getType().getBasicType()) {
+ case EbtDouble:
+ case EbtFloat:
+#ifdef AMD_EXTENSIONS
+ case EbtFloat16:
+#endif
+ newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst());
+ break;
+
+ case EbtInt:
+ if (rightUnionArray[i] == 0)
+ newConstArray[i].setIConst(0x7FFFFFFF);
+ else if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == (int)0x80000000)
+ newConstArray[i].setIConst(0x80000000);
+ else
+ newConstArray[i].setIConst(leftUnionArray[i].getIConst() / rightUnionArray[i].getIConst());
+ break;
+
+ case EbtUint:
+ if (rightUnionArray[i] == 0) {
+ newConstArray[i].setUConst(0xFFFFFFFF);
+ } else
+ newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst());
+ break;
+
+ case EbtInt64:
+ if (rightUnionArray[i] == 0)
+ newConstArray[i].setI64Const(0x7FFFFFFFFFFFFFFFll);
+ else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == (long long)0x8000000000000000)
+ newConstArray[i].setI64Const(0x8000000000000000);
+ else
+ newConstArray[i].setI64Const(leftUnionArray[i].getI64Const() / rightUnionArray[i].getI64Const());
+ break;
+
+ case EbtUint64:
+ if (rightUnionArray[i] == 0) {
+ newConstArray[i].setU64Const(0xFFFFFFFFFFFFFFFFull);
+ } else
+ newConstArray[i].setU64Const(leftUnionArray[i].getU64Const() / rightUnionArray[i].getU64Const());
+ break;
+ default:
+ return 0;
+ }
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ for (int i = 0; i < getMatrixRows(); i++) {
+ double sum = 0.0f;
+ for (int j = 0; j < rightNode->getVectorSize(); j++) {
+ sum += leftUnionArray[j*getMatrixRows() + i].getDConst() * rightUnionArray[j].getDConst();
+ }
+ newConstArray[i].setDConst(sum);
+ }
+
+ returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows()));
+ break;
+
+ case EOpVectorTimesMatrix:
+ for (int i = 0; i < rightNode->getMatrixCols(); i++) {
+ double sum = 0.0f;
+ for (int j = 0; j < getVectorSize(); j++)
+ sum += leftUnionArray[j].getDConst() * rightUnionArray[i*rightNode->getMatrixRows() + j].getDConst();
+ newConstArray[i].setDConst(sum);
+ }
+
+ returnType.shallowCopy(TType(getBasicType(), EvqConst, rightNode->getMatrixCols()));
+ break;
+
+ case EOpMod:
+ for (int i = 0; i < newComps; i++) {
+ if (rightUnionArray[i] == 0)
+ newConstArray[i] = leftUnionArray[i];
+ else
+ newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
+ }
+ break;
+
+ case EOpRightShift:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] >> rightUnionArray[i];
+ break;
+
+ case EOpLeftShift:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] << rightUnionArray[i];
+ break;
+
+ case EOpAnd:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] & rightUnionArray[i];
+ break;
+ case EOpInclusiveOr:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] | rightUnionArray[i];
+ break;
+ case EOpExclusiveOr:
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] ^ rightUnionArray[i];
+ break;
+
+ case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] && rightUnionArray[i];
+ break;
+
+ case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+ for (int i = 0; i < newComps; i++)
+ newConstArray[i] = leftUnionArray[i] || rightUnionArray[i];
+ break;
+
+ case EOpLogicalXor:
+ for (int i = 0; i < newComps; i++) {
+ switch (getType().getBasicType()) {
+ case EbtBool: newConstArray[i].setBConst((leftUnionArray[i] == rightUnionArray[i]) ? false : true); break;
+ default: assert(false && "Default missing");
+ }
+ }
+ break;
+
+ case EOpLessThan:
+ newConstArray[0].setBConst(leftUnionArray[0] < rightUnionArray[0]);
+ returnType.shallowCopy(constBool);
+ break;
+ case EOpGreaterThan:
+ newConstArray[0].setBConst(leftUnionArray[0] > rightUnionArray[0]);
+ returnType.shallowCopy(constBool);
+ break;
+ case EOpLessThanEqual:
+ newConstArray[0].setBConst(! (leftUnionArray[0] > rightUnionArray[0]));
+ returnType.shallowCopy(constBool);
+ break;
+ case EOpGreaterThanEqual:
+ newConstArray[0].setBConst(! (leftUnionArray[0] < rightUnionArray[0]));
+ returnType.shallowCopy(constBool);
+ break;
+ case EOpEqual:
+ newConstArray[0].setBConst(rightNode->getConstArray() == leftUnionArray);
+ returnType.shallowCopy(constBool);
+ break;
+ case EOpNotEqual:
+ newConstArray[0].setBConst(rightNode->getConstArray() != leftUnionArray);
+ returnType.shallowCopy(constBool);
+ break;
+
+ default:
+ return 0;
+ }
+
+ TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
+ newNode->setLoc(getLoc());
+
+ return newNode;
+}
+
+//
+// Do single unary node folding
+//
+// Returns a new node representing the result.
+//
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) const
+{
+ // First, size the result, which is mostly the same as the argument's size,
+ // but not always, and classify what is componentwise.
+ // Also, eliminate cases that can't be compile-time constant.
+ int resultSize;
+ bool componentWise = true;
+
+ int objectSize = getType().computeNumComponents();
+ switch (op) {
+ case EOpDeterminant:
+ case EOpAny:
+ case EOpAll:
+ case EOpLength:
+ componentWise = false;
+ resultSize = 1;
+ break;
+
+ case EOpEmitStreamVertex:
+ case EOpEndStreamPrimitive:
+ // These don't actually fold
+ return 0;
+
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+ componentWise = false;
+ resultSize = 1;
+ break;
+
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpUnpackHalf2x16:
+ componentWise = false;
+ resultSize = 2;
+ break;
+
+ case EOpNormalize:
+ componentWise = false;
+ resultSize = objectSize;
+ break;
+
+ default:
+ resultSize = objectSize;
+ break;
+ }
+
+ // Set up for processing
+ TConstUnionArray newConstArray(resultSize);
+ const TConstUnionArray& unionArray = getConstArray();
+
+ // Process non-component-wise operations
+ switch (op) {
+ case EOpLength:
+ case EOpNormalize:
+ {
+ double sum = 0;
+ for (int i = 0; i < objectSize; i++)
+ sum += unionArray[i].getDConst() * unionArray[i].getDConst();
+ double length = sqrt(sum);
+ if (op == EOpLength)
+ newConstArray[0].setDConst(length);
+ else {
+ for (int i = 0; i < objectSize; i++)
+ newConstArray[i].setDConst(unionArray[i].getDConst() / length);
+ }
+ break;
+ }
+
+ case EOpAny:
+ {
+ bool result = false;
+ for (int i = 0; i < objectSize; i++) {
+ if (unionArray[i].getBConst())
+ result = true;
+ }
+ newConstArray[0].setBConst(result);
+ break;
+ }
+ case EOpAll:
+ {
+ bool result = true;
+ for (int i = 0; i < objectSize; i++) {
+ if (! unionArray[i].getBConst())
+ result = false;
+ }
+ newConstArray[0].setBConst(result);
+ break;
+ }
+
+ // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
+
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpUnpackHalf2x16:
+
+ case EOpDeterminant:
+ case EOpMatrixInverse:
+ case EOpTranspose:
+ return 0;
+
+ default:
+ assert(componentWise);
+ break;
+ }
+
+ // Turn off the componentwise loop
+ if (! componentWise)
+ objectSize = 0;
+
+ // Process component-wise operations
+ for (int i = 0; i < objectSize; i++) {
+ switch (op) {
+ case EOpNegative:
+ switch (getType().getBasicType()) {
+ case EbtDouble:
+#ifdef AMD_EXTENSIONS
+ case EbtFloat16:
+#endif
+ case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
+ case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+ case EbtUint: newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break;
+ case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
+ case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getU64Const()))); break;
+ default:
+ return 0;
+ }
+ break;
+ case EOpLogicalNot:
+ case EOpVectorLogicalNot:
+ switch (getType().getBasicType()) {
+ case EbtBool: newConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+ default:
+ return 0;
+ }
+ break;
+ case EOpBitwiseNot:
+ newConstArray[i] = ~unionArray[i];
+ break;
+ case EOpRadians:
+ newConstArray[i].setDConst(unionArray[i].getDConst() * pi / 180.0);
+ break;
+ case EOpDegrees:
+ newConstArray[i].setDConst(unionArray[i].getDConst() * 180.0 / pi);
+ break;
+ case EOpSin:
+ newConstArray[i].setDConst(sin(unionArray[i].getDConst()));
+ break;
+ case EOpCos:
+ newConstArray[i].setDConst(cos(unionArray[i].getDConst()));
+ break;
+ case EOpTan:
+ newConstArray[i].setDConst(tan(unionArray[i].getDConst()));
+ break;
+ case EOpAsin:
+ newConstArray[i].setDConst(asin(unionArray[i].getDConst()));
+ break;
+ case EOpAcos:
+ newConstArray[i].setDConst(acos(unionArray[i].getDConst()));
+ break;
+ case EOpAtan:
+ newConstArray[i].setDConst(atan(unionArray[i].getDConst()));
+ break;
+
+ case EOpDPdx:
+ case EOpDPdy:
+ case EOpFwidth:
+ case EOpDPdxFine:
+ case EOpDPdyFine:
+ case EOpFwidthFine:
+ case EOpDPdxCoarse:
+ case EOpDPdyCoarse:
+ case EOpFwidthCoarse:
+ // The derivatives are all mandated to create a constant 0.
+ newConstArray[i].setDConst(0.0);
+ break;
+
+ case EOpExp:
+ newConstArray[i].setDConst(exp(unionArray[i].getDConst()));
+ break;
+ case EOpLog:
+ newConstArray[i].setDConst(log(unionArray[i].getDConst()));
+ break;
+ case EOpExp2:
+ {
+ const double inv_log2_e = 0.69314718055994530941723212145818;
+ newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e));
+ break;
+ }
+ case EOpLog2:
+ {
+ const double log2_e = 1.4426950408889634073599246810019;
+ newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst()));
+ break;
+ }
+ case EOpSqrt:
+ newConstArray[i].setDConst(sqrt(unionArray[i].getDConst()));
+ break;
+ case EOpInverseSqrt:
+ newConstArray[i].setDConst(1.0 / sqrt(unionArray[i].getDConst()));
+ break;
+
+ case EOpAbs:
+ if (unionArray[i].getType() == EbtDouble)
+ newConstArray[i].setDConst(fabs(unionArray[i].getDConst()));
+ else if (unionArray[i].getType() == EbtInt)
+ newConstArray[i].setIConst(abs(unionArray[i].getIConst()));
+ else
+ newConstArray[i] = unionArray[i];
+ break;
+ case EOpSign:
+ #define SIGN(X) (X == 0 ? 0 : (X < 0 ? -1 : 1))
+ if (unionArray[i].getType() == EbtDouble)
+ newConstArray[i].setDConst(SIGN(unionArray[i].getDConst()));
+ else
+ newConstArray[i].setIConst(SIGN(unionArray[i].getIConst()));
+ break;
+ case EOpFloor:
+ newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
+ break;
+ case EOpTrunc:
+ if (unionArray[i].getDConst() > 0)
+ newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
+ else
+ newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
+ break;
+ case EOpRound:
+ newConstArray[i].setDConst(floor(0.5 + unionArray[i].getDConst()));
+ break;
+ case EOpRoundEven:
+ {
+ double flr = floor(unionArray[i].getDConst());
+ bool even = flr / 2.0 == floor(flr / 2.0);
+ double rounded = even ? ceil(unionArray[i].getDConst() - 0.5) : floor(unionArray[i].getDConst() + 0.5);
+ newConstArray[i].setDConst(rounded);
+ break;
+ }
+ case EOpCeil:
+ newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
+ break;
+ case EOpFract:
+ {
+ double x = unionArray[i].getDConst();
+ newConstArray[i].setDConst(x - floor(x));
+ break;
+ }
+
+ case EOpIsNan:
+ {
+ newConstArray[i].setBConst(isNan(unionArray[i].getDConst()));
+ break;
+ }
+ case EOpIsInf:
+ {
+ newConstArray[i].setBConst(isInf(unionArray[i].getDConst()));
+ break;
+ }
+
+ // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
+
+ case EOpSinh:
+ case EOpCosh:
+ case EOpTanh:
+ case EOpAsinh:
+ case EOpAcosh:
+ case EOpAtanh:
+
+ case EOpFloatBitsToInt:
+ case EOpFloatBitsToUint:
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ case EOpDoubleBitsToInt64:
+ case EOpDoubleBitsToUint64:
+
+ default:
+ return 0;
+ }
+ }
+
+ TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
+ newNode->getWritableType().getQualifier().storage = EvqConst;
+ newNode->setLoc(getLoc());
+
+ return newNode;
+}
+
+//
+// Do constant folding for an aggregate node that has all its children
+// as constants and an operator that requires constant folding.
+//
+TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
+{
+ if (! areAllChildConst(aggrNode))
+ return aggrNode;
+
+ if (aggrNode->isConstructor())
+ return foldConstructor(aggrNode);
+
+ TIntermSequence& children = aggrNode->getSequence();
+
+ // First, see if this is an operation to constant fold, kick out if not,
+ // see what size the result is if so.
+
+ bool componentwise = false; // will also say componentwise if a scalar argument gets repeated to make per-component results
+ int objectSize;
+ switch (aggrNode->getOp()) {
+ case EOpAtan:
+ case EOpPow:
+ case EOpMin:
+ case EOpMax:
+ case EOpMix:
+ case EOpClamp:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ componentwise = true;
+ objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+ break;
+ case EOpCross:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpFaceForward:
+ objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+ break;
+ case EOpDistance:
+ case EOpDot:
+ objectSize = 1;
+ break;
+ case EOpOuterProduct:
+ objectSize = children[0]->getAsTyped()->getType().getVectorSize() *
+ children[1]->getAsTyped()->getType().getVectorSize();
+ break;
+ case EOpStep:
+ componentwise = true;
+ objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
+ children[1]->getAsTyped()->getType().getVectorSize());
+ break;
+ case EOpSmoothStep:
+ componentwise = true;
+ objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
+ children[2]->getAsTyped()->getType().getVectorSize());
+ break;
+ default:
+ return aggrNode;
+ }
+ TConstUnionArray newConstArray(objectSize);
+
+ TVector<TConstUnionArray> childConstUnions;
+ for (unsigned int arg = 0; arg < children.size(); ++arg)
+ childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray());
+
+ // Second, do the actual folding
+
+ bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat ||
+#ifdef AMD_EXTENSIONS
+ children[0]->getAsTyped()->getBasicType() == EbtFloat16 ||
+#endif
+ children[0]->getAsTyped()->getBasicType() == EbtDouble;
+ bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt ||
+ children[0]->getAsTyped()->getBasicType() == EbtInt64;
+ bool isInt64 = children[0]->getAsTyped()->getBasicType() == EbtInt64 ||
+ children[0]->getAsTyped()->getBasicType() == EbtUint64;
+ if (componentwise) {
+ for (int comp = 0; comp < objectSize; comp++) {
+
+ // some arguments are scalars instead of matching vectors; simulate a smear
+ int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1);
+ int arg1comp = 0;
+ if (children.size() > 1)
+ arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1);
+ int arg2comp = 0;
+ if (children.size() > 2)
+ arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1);
+
+ switch (aggrNode->getOp()) {
+ case EOpAtan:
+ newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+ break;
+ case EOpPow:
+ newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+ break;
+ case EOpMin:
+ if (isFloatingPoint)
+ newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+ else if (isSigned) {
+ if (isInt64)
+ newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
+ else
+ newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
+ } else {
+ if (isInt64)
+ newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
+ else
+ newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
+ }
+ break;
+ case EOpMax:
+ if (isFloatingPoint)
+ newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+ else if (isSigned) {
+ if (isInt64)
+ newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
+ else
+ newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
+ } else {
+ if (isInt64)
+ newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
+ else
+ newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
+ }
+ break;
+ case EOpClamp:
+ if (isFloatingPoint)
+ newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()),
+ childConstUnions[2][arg2comp].getDConst()));
+ else if (isSigned) {
+ if (isInt64)
+ newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()),
+ childConstUnions[2][arg2comp].getI64Const()));
+ else
+ newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()),
+ childConstUnions[2][arg2comp].getIConst()));
+ } else {
+ if (isInt64)
+ newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()),
+ childConstUnions[2][arg2comp].getU64Const()));
+ else
+ newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()),
+ childConstUnions[2][arg2comp].getUConst()));
+ }
+ break;
+ case EOpLessThan:
+ newConstArray[comp].setBConst(childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]);
+ break;
+ case EOpGreaterThan:
+ newConstArray[comp].setBConst(childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]);
+ break;
+ case EOpLessThanEqual:
+ newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]));
+ break;
+ case EOpGreaterThanEqual:
+ newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]));
+ break;
+ case EOpVectorEqual:
+ newConstArray[comp].setBConst(childConstUnions[0][arg0comp] == childConstUnions[1][arg1comp]);
+ break;
+ case EOpVectorNotEqual:
+ newConstArray[comp].setBConst(childConstUnions[0][arg0comp] != childConstUnions[1][arg1comp]);
+ break;
+ case EOpMix:
+ if (children[2]->getAsTyped()->getBasicType() == EbtBool)
+ newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() :
+ childConstUnions[0][arg0comp].getDConst());
+ else
+ newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) +
+ childConstUnions[1][arg1comp].getDConst() * childConstUnions[2][arg2comp].getDConst());
+ break;
+ case EOpStep:
+ newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0);
+ break;
+ case EOpSmoothStep:
+ {
+ double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) /
+ (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst());
+ if (t < 0.0)
+ t = 0.0;
+ if (t > 1.0)
+ t = 1.0;
+ newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t));
+ break;
+ }
+ default:
+ return aggrNode;
+ }
+ }
+ } else {
+ // Non-componentwise...
+
+ int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+ double dot;
+
+ switch (aggrNode->getOp()) {
+ case EOpDistance:
+ {
+ double sum = 0.0;
+ for (int comp = 0; comp < numComps; ++comp) {
+ double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst();
+ sum += diff * diff;
+ }
+ newConstArray[0].setDConst(sqrt(sum));
+ break;
+ }
+ case EOpDot:
+ newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
+ break;
+ case EOpCross:
+ newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1];
+ newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2];
+ newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0];
+ break;
+ case EOpFaceForward:
+ // If dot(Nref, I) < 0 return N, otherwise return -N: Arguments are (N, I, Nref).
+ dot = childConstUnions[1].dot(childConstUnions[2]);
+ for (int comp = 0; comp < numComps; ++comp) {
+ if (dot < 0.0)
+ newConstArray[comp] = childConstUnions[0][comp];
+ else
+ newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst());
+ }
+ break;
+ case EOpReflect:
+ // I - 2 * dot(N, I) * N: Arguments are (I, N).
+ dot = childConstUnions[0].dot(childConstUnions[1]);
+ dot *= 2.0;
+ for (int comp = 0; comp < numComps; ++comp)
+ newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst());
+ break;
+ case EOpRefract:
+ {
+ // Arguments are (I, N, eta).
+ // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+ // if (k < 0.0)
+ // return dvec(0.0)
+ // else
+ // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
+ dot = childConstUnions[0].dot(childConstUnions[1]);
+ double eta = childConstUnions[2][0].getDConst();
+ double k = 1.0 - eta * eta * (1.0 - dot * dot);
+ if (k < 0.0) {
+ for (int comp = 0; comp < numComps; ++comp)
+ newConstArray[comp].setDConst(0.0);
+ } else {
+ for (int comp = 0; comp < numComps; ++comp)
+ newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst());
+ }
+ break;
+ }
+ case EOpOuterProduct:
+ {
+ int numRows = numComps;
+ int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents();
+ for (int row = 0; row < numRows; ++row)
+ for (int col = 0; col < numCols; ++col)
+ newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
+ break;
+ }
+ default:
+ return aggrNode;
+ }
+ }
+
+ TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType());
+ newNode->getWritableType().getQualifier().storage = EvqConst;
+ newNode->setLoc(aggrNode->getLoc());
+
+ return newNode;
+}
+
+bool TIntermediate::areAllChildConst(TIntermAggregate* aggrNode)
+{
+ bool allConstant = true;
+
+ // check if all the child nodes are constants so that they can be inserted into
+ // the parent node
+ if (aggrNode) {
+ TIntermSequence& childSequenceVector = aggrNode->getSequence();
+ for (TIntermSequence::iterator p = childSequenceVector.begin();
+ p != childSequenceVector.end(); p++) {
+ if (!(*p)->getAsTyped()->getAsConstantUnion())
+ return false;
+ }
+ }
+
+ return allConstant;
+}
+
+TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
+{
+ bool error = false;
+
+ TConstUnionArray unionArray(aggrNode->getType().computeNumComponents());
+ if (aggrNode->getSequence().size() == 1)
+ error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
+ else
+ error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
+
+ if (error)
+ return aggrNode;
+
+ return addConstantUnion(unionArray, aggrNode->getType(), aggrNode->getLoc());
+}
+
+//
+// Constant folding of a bracket (array-style) dereference or struct-like dot
+// dereference. Can handle anything except a multi-character swizzle, though
+// all swizzles may go to foldSwizzle().
+//
+TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, const TSourceLoc& loc)
+{
+ TType dereferencedType(node->getType(), index);
+ dereferencedType.getQualifier().storage = EvqConst;
+ TIntermTyped* result = 0;
+ int size = dereferencedType.computeNumComponents();
+
+ // arrays, vectors, matrices, all use simple multiplicative math
+ // while structures need to add up heterogeneous members
+ int start;
+ if (node->isArray() || ! node->isStruct())
+ start = size * index;
+ else {
+ // it is a structure
+ assert(node->isStruct());
+ start = 0;
+ for (int i = 0; i < index; ++i)
+ start += (*node->getType().getStruct())[i].type->computeNumComponents();
+ }
+
+ result = addConstantUnion(TConstUnionArray(node->getAsConstantUnion()->getConstArray(), start, size), node->getType(), loc);
+
+ if (result == 0)
+ result = node;
+ else
+ result->setType(dereferencedType);
+
+ return result;
+}
+
+//
+// Make a constant vector node or constant scalar node, representing a given
+// constant vector and constant swizzle into it.
+//
+TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc& loc)
+{
+ const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray();
+ TConstUnionArray constArray(fields.num);
+
+ for (int i = 0; i < fields.num; i++)
+ constArray[i] = unionArray[fields.offsets[i]];
+
+ TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc);
+
+ if (result == 0)
+ result = node;
+ else
+ result->setType(TType(node->getBasicType(), EvqConst, fields.num));
+
+ return result;
+}
+
+} // end namespace glslang