diff options
Diffstat (limited to '3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp')
-rw-r--r-- | 3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Constant.cpp | 992 |
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 |