Commit f119a263 by Olli Etuaho Committed by Commit Bot

Clean up unary and aggregate math folding

Prefer asserts instead of adding internal errors to the compiler log when types of arguments are not as expected or the folding function runs into an operation it can't handle. Neither of these cases should be possible, the checks for correct argument types are solid at this point. In the future, when new built-in functions are added, constant folding support for them should be added as well. foldUnaryWithDifferentReturnType and foldUnaryWithSameReturnType are renamed to foldUnaryNonComponentWise and foldUnaryComponentWise respectively. These names better reflect what these functions are doing. The info sink member is removed from TIntermediate, since TDiagnostics is now passed into the functions that may generate warnings instead. BUG=angleproject:1490 TEST=angle_unittests Change-Id: I6a08abbe29cf23f3a318032fdc46dd3dbaf4410e Reviewed-on: https://chromium-review.googlesource.com/377959 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 9df01f8a
...@@ -219,8 +219,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -219,8 +219,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
++firstSource; ++firstSource;
} }
TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
compileOptions, true, infoSink, getResources()); compileOptions, true, infoSink, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh); parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
...@@ -254,7 +253,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -254,7 +253,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize(); mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
root = parseContext.getTreeRoot(); root = parseContext.getTreeRoot();
root = intermediate.postProcess(root); root = TIntermediate::PostProcess(root);
// Highp might have been auto-enabled based on shader version // Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
......
...@@ -44,13 +44,14 @@ TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size) ...@@ -44,13 +44,14 @@ TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
return constUnion; return constUnion;
} }
void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType, void UndefinedConstantFoldingError(const TSourceLoc &loc,
TInfoSink &infoSink, TConstantUnion *result) TOperator op,
TBasicType basicType,
TDiagnostics *diagnostics,
TConstantUnion *result)
{ {
std::stringstream constantFoldingErrorStream; diagnostics->warning(loc, "operation result is undefined for the values passed in",
constantFoldingErrorStream << "'" << GetOperatorString(op) GetOperatorString(op), "");
<< "' operation result is undefined for the values passed in";
infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
switch (basicType) switch (basicType)
{ {
...@@ -856,7 +857,7 @@ TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics) ...@@ -856,7 +857,7 @@ TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
return CreateFoldedNode(constArray, this, resultQualifier); return CreateFoldedNode(constArray, this, resultQualifier);
} }
TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
{ {
TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
if (operandConstant == nullptr) if (operandConstant == nullptr)
...@@ -879,11 +880,11 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) ...@@ -879,11 +880,11 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
case EOpUnpackUnorm2x16: case EOpUnpackUnorm2x16:
case EOpPackHalf2x16: case EOpPackHalf2x16:
case EOpUnpackHalf2x16: case EOpUnpackHalf2x16:
constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink); constArray = operandConstant->foldUnaryNonComponentWise(mOp);
break; break;
default: default:
constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink); constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
break; break;
} }
// Nodes may be constant folded without being qualified as constant. // Nodes may be constant folded without being qualified as constant.
...@@ -891,7 +892,7 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) ...@@ -891,7 +892,7 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
return CreateFoldedNode(constArray, this, resultQualifier); return CreateFoldedNode(constArray, this, resultQualifier);
} }
TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
{ {
// Make sure that all params are constant before actual constant folding. // Make sure that all params are constant before actual constant folding.
for (auto *param : *getSequence()) for (auto *param : *getSequence())
...@@ -903,9 +904,9 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) ...@@ -903,9 +904,9 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
} }
TConstantUnion *constArray = nullptr; TConstantUnion *constArray = nullptr;
if (isConstructor()) if (isConstructor())
constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink); constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
else else
constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink); constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
// Nodes may be constant folded without being qualified as constant. // Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary; TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
...@@ -925,10 +926,7 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, ...@@ -925,10 +926,7 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
const TConstantUnion *leftArray = getUnionArrayPointer(); const TConstantUnion *leftArray = getUnionArrayPointer();
const TConstantUnion *rightArray = rightNode->getUnionArrayPointer(); const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
if (!leftArray) ASSERT(leftArray && rightArray);
return nullptr;
if (!rightArray)
return nullptr;
size_t objectSize = getType().getObjectSize(); size_t objectSize = getType().getObjectSize();
...@@ -1224,29 +1222,22 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, ...@@ -1224,29 +1222,22 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
return resultArray; return resultArray;
} }
// // The fold functions do operations on a constant at GLSL compile time, without generating run-time
// The fold functions see if an operation on a constant can be done in place, // code. Returns the constant value to keep using. Nullptr should not be returned.
// without generating run-time code. TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
//
// Returns the constant value to keep using or nullptr.
//
TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
{ {
// // Do operations where the return type may have a different number of components compared to the
// Do operations where the return type has a different number of components compared to the operand type. // operand type.
//
const TConstantUnion *operandArray = getUnionArrayPointer(); const TConstantUnion *operandArray = getUnionArrayPointer();
if (!operandArray) ASSERT(operandArray);
return nullptr;
size_t objectSize = getType().getObjectSize(); size_t objectSize = getType().getObjectSize();
TConstantUnion *resultArray = nullptr; TConstantUnion *resultArray = nullptr;
switch (op) switch (op)
{ {
case EOpAny: case EOpAny:
if (getType().getBasicType() == EbtBool) ASSERT(getType().getBasicType() == EbtBool);
{
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setBConst(false); resultArray->setBConst(false);
for (size_t i = 0; i < objectSize; i++) for (size_t i = 0; i < objectSize; i++)
...@@ -1258,16 +1249,9 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator ...@@ -1258,16 +1249,9 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
} }
} }
break; break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpAll: case EOpAll:
if (getType().getBasicType() == EbtBool) ASSERT(getType().getBasicType() == EbtBool);
{
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setBConst(true); resultArray->setBConst(true);
for (size_t i = 0; i < objectSize; i++) for (size_t i = 0; i < objectSize; i++)
...@@ -1279,89 +1263,55 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator ...@@ -1279,89 +1263,55 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
} }
} }
break; break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpLength: case EOpLength:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setFConst(VectorLength(operandArray, objectSize)); resultArray->setFConst(VectorLength(operandArray, objectSize));
break; break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpTranspose: case EOpTranspose:
if (getType().getBasicType() == EbtFloat)
{ {
ASSERT(getType().getBasicType() == EbtFloat);
resultArray = new TConstantUnion[objectSize]; resultArray = new TConstantUnion[objectSize];
angle::Matrix<float> result = angle::Matrix<float> result =
GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose(); GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
SetUnionArrayFromMatrix(result, resultArray); SetUnionArrayFromMatrix(result, resultArray);
break; break;
} }
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpDeterminant: case EOpDeterminant:
if (getType().getBasicType() == EbtFloat)
{ {
ASSERT(getType().getBasicType() == EbtFloat);
unsigned int size = getType().getNominalSize(); unsigned int size = getType().getNominalSize();
ASSERT(size >= 2 && size <= 4); ASSERT(size >= 2 && size <= 4);
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setFConst(GetMatrix(operandArray, size).determinant()); resultArray->setFConst(GetMatrix(operandArray, size).determinant());
break; break;
} }
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpInverse: case EOpInverse:
if (getType().getBasicType() == EbtFloat)
{ {
ASSERT(getType().getBasicType() == EbtFloat);
unsigned int size = getType().getNominalSize(); unsigned int size = getType().getNominalSize();
ASSERT(size >= 2 && size <= 4); ASSERT(size >= 2 && size <= 4);
resultArray = new TConstantUnion[objectSize]; resultArray = new TConstantUnion[objectSize];
angle::Matrix<float> result = GetMatrix(operandArray, size).inverse(); angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
SetUnionArrayFromMatrix(result, resultArray); SetUnionArrayFromMatrix(result, resultArray);
break; break;
} }
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpPackSnorm2x16: case EOpPackSnorm2x16:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
ASSERT(getType().getNominalSize() == 2); ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); resultArray->setUConst(
gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break; break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpUnpackSnorm2x16: case EOpUnpackSnorm2x16:
if (getType().getBasicType() == EbtUInt)
{ {
ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2]; resultArray = new TConstantUnion[2];
float f1, f2; float f1, f2;
gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2); gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
...@@ -1369,29 +1319,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator ...@@ -1369,29 +1319,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
resultArray[1].setFConst(f2); resultArray[1].setFConst(f2);
break; break;
} }
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpPackUnorm2x16: case EOpPackUnorm2x16:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
ASSERT(getType().getNominalSize() == 2); ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); resultArray->setUConst(
gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break; break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpUnpackUnorm2x16: case EOpUnpackUnorm2x16:
if (getType().getBasicType() == EbtUInt)
{ {
ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2]; resultArray = new TConstantUnion[2];
float f1, f2; float f1, f2;
gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2); gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
...@@ -1399,29 +1338,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator ...@@ -1399,29 +1338,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
resultArray[1].setFConst(f2); resultArray[1].setFConst(f2);
break; break;
} }
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpPackHalf2x16: case EOpPackHalf2x16:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
ASSERT(getType().getNominalSize() == 2); ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); resultArray->setUConst(
gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break; break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpUnpackHalf2x16: case EOpUnpackHalf2x16:
if (getType().getBasicType() == EbtUInt)
{ {
ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2]; resultArray = new TConstantUnion[2];
float f1, f2; float f1, f2;
gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2); gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
...@@ -1429,29 +1357,24 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator ...@@ -1429,29 +1357,24 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
resultArray[1].setFConst(f2); resultArray[1].setFConst(f2);
break; break;
} }
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
break;
default: default:
break; UNREACHABLE();
break;
} }
return resultArray; return resultArray;
} }
TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink) TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
TDiagnostics *diagnostics)
{ {
// // Do unary operations where each component of the result is computed based on the corresponding
// Do unary operations where the return type is the same as operand type. // component of the operand. Also folds normalize, though the divisor in that case takes all
// // components into account.
const TConstantUnion *operandArray = getUnionArrayPointer(); const TConstantUnion *operandArray = getUnionArrayPointer();
if (!operandArray) ASSERT(operandArray);
return nullptr;
size_t objectSize = getType().getObjectSize(); size_t objectSize = getType().getObjectSize();
...@@ -1460,243 +1383,213 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, ...@@ -1460,243 +1383,213 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
{ {
switch(op) switch(op)
{ {
case EOpNegative: case EOpNegative:
switch (getType().getBasicType()) switch (getType().getBasicType())
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setFConst(-operandArray[i].getFConst()); resultArray[i].setFConst(-operandArray[i].getFConst());
break; break;
case EbtInt: case EbtInt:
resultArray[i].setIConst(-operandArray[i].getIConst()); resultArray[i].setIConst(-operandArray[i].getIConst());
break; break;
case EbtUInt: case EbtUInt:
resultArray[i].setUConst(static_cast<unsigned int>( resultArray[i].setUConst(static_cast<unsigned int>(
-static_cast<int>(operandArray[i].getUConst()))); -static_cast<int>(operandArray[i].getUConst())));
break;
default:
UNREACHABLE();
return nullptr;
}
break; break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
}
break;
case EOpPositive: case EOpPositive:
switch (getType().getBasicType()) switch (getType().getBasicType())
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setFConst(operandArray[i].getFConst()); resultArray[i].setFConst(operandArray[i].getFConst());
break; break;
case EbtInt: case EbtInt:
resultArray[i].setIConst(operandArray[i].getIConst()); resultArray[i].setIConst(operandArray[i].getIConst());
break; break;
case EbtUInt: case EbtUInt:
resultArray[i].setUConst(static_cast<unsigned int>( resultArray[i].setUConst(static_cast<unsigned int>(
static_cast<int>(operandArray[i].getUConst()))); static_cast<int>(operandArray[i].getUConst())));
break;
default:
UNREACHABLE();
return nullptr;
}
break; break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
}
break;
case EOpLogicalNot: case EOpLogicalNot:
// this code is written for possible future use, switch (getType().getBasicType())
// will not get executed currently {
switch (getType().getBasicType()) case EbtBool:
{ resultArray[i].setBConst(!operandArray[i].getBConst());
case EbtBool: break;
resultArray[i].setBConst(!operandArray[i].getBConst()); default:
UNREACHABLE();
return nullptr;
}
break; break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
}
break;
case EOpBitwiseNot: case EOpBitwiseNot:
switch (getType().getBasicType()) switch (getType().getBasicType())
{ {
case EbtInt: case EbtInt:
resultArray[i].setIConst(~operandArray[i].getIConst()); resultArray[i].setIConst(~operandArray[i].getIConst());
break; break;
case EbtUInt: case EbtUInt:
resultArray[i].setUConst(~operandArray[i].getUConst()); resultArray[i].setUConst(~operandArray[i].getUConst());
break;
default:
UNREACHABLE();
return nullptr;
}
break; break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
}
break;
case EOpRadians: case EOpRadians:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst()); resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
break; break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpDegrees: case EOpDegrees:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst()); resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
break; break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpSin: case EOpSin:
if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
return nullptr; break;
break;
case EOpCos:
if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
return nullptr;
break;
case EOpTan:
if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
return nullptr;
break;
case EOpAsin: case EOpCos:
// For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0. foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f) break;
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
return nullptr;
break;
case EOpAcos: case EOpTan:
// For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0. foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f) break;
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
return nullptr;
break;
case EOpAtan: case EOpAsin:
if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i])) // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
return nullptr; // 0.
break; if (fabsf(operandArray[i].getFConst()) > 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
break;
case EOpSinh: case EOpAcos:
if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i])) // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
return nullptr; // 0.
break; if (fabsf(operandArray[i].getFConst()) > 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
break;
case EOpCosh: case EOpAtan:
if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
return nullptr; break;
break;
case EOpTanh: case EOpSinh:
if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
return nullptr; break;
break;
case EOpAsinh: case EOpCosh:
if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
return nullptr; break;
break;
case EOpAcosh: case EOpTanh:
// For acosh(x), results are undefined if x < 1, we are choosing to set result to 0. foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f) break;
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
return nullptr;
break;
case EOpAtanh: case EOpAsinh:
// For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0. foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f) break;
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
return nullptr;
break;
case EOpAbs: case EOpAcosh:
switch (getType().getBasicType()) // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
{ if (operandArray[i].getFConst() < 1.0f)
case EbtFloat: UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
resultArray[i].setFConst(fabsf(operandArray[i].getFConst())); diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
break; break;
case EbtInt:
resultArray[i].setIConst(abs(operandArray[i].getIConst())); case EOpAtanh:
// For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
// 0.
if (fabsf(operandArray[i].getFConst()) >= 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
break; break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
}
break;
case EOpSign: case EOpAbs:
switch (getType().getBasicType()) switch (getType().getBasicType())
{
case EbtFloat:
{ {
float fConst = operandArray[i].getFConst(); case EbtFloat:
float fResult = 0.0f; resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
if (fConst > 0.0f) break;
fResult = 1.0f; case EbtInt:
else if (fConst < 0.0f) resultArray[i].setIConst(abs(operandArray[i].getIConst()));
fResult = -1.0f; break;
resultArray[i].setFConst(fResult); default:
UNREACHABLE();
return nullptr;
} }
break; break;
case EbtInt:
case EOpSign:
switch (getType().getBasicType())
{ {
int iConst = operandArray[i].getIConst(); case EbtFloat:
int iResult = 0; {
if (iConst > 0) float fConst = operandArray[i].getFConst();
iResult = 1; float fResult = 0.0f;
else if (iConst < 0) if (fConst > 0.0f)
iResult = -1; fResult = 1.0f;
resultArray[i].setIConst(iResult); else if (fConst < 0.0f)
fResult = -1.0f;
resultArray[i].setFConst(fResult);
break;
}
case EbtInt:
{
int iConst = operandArray[i].getIConst();
int iResult = 0;
if (iConst > 0)
iResult = 1;
else if (iConst < 0)
iResult = -1;
resultArray[i].setIConst(iResult);
break;
}
default:
UNREACHABLE();
return nullptr;
} }
break; break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
}
break;
case EOpFloor: case EOpFloor:
if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
return nullptr; break;
break;
case EOpTrunc: case EOpTrunc:
if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
return nullptr; break;
break;
case EOpRound: case EOpRound:
if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
return nullptr; break;
break;
case EOpRoundEven: case EOpRoundEven:
if (getType().getBasicType() == EbtFloat)
{ {
ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst(); float x = operandArray[i].getFConst();
float result; float result;
float fractPart = modff(x, &result); float fractPart = modff(x, &result);
...@@ -1707,197 +1600,151 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, ...@@ -1707,197 +1600,151 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
resultArray[i].setFConst(result); resultArray[i].setFConst(result);
break; break;
} }
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpCeil: case EOpCeil:
if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
return nullptr; break;
break;
case EOpFract: case EOpFract:
if (getType().getBasicType() == EbtFloat)
{ {
ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst(); float x = operandArray[i].getFConst();
resultArray[i].setFConst(x - floorf(x)); resultArray[i].setFConst(x - floorf(x));
break; break;
} }
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpIsNan: case EOpIsNan:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst())); resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpIsInf: case EOpIsInf:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst())); resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpFloatBitsToInt: case EOpFloatBitsToInt:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst())); resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpFloatBitsToUint: case EOpFloatBitsToUint:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst())); resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpIntBitsToFloat: case EOpIntBitsToFloat:
if (getType().getBasicType() == EbtInt) ASSERT(getType().getBasicType() == EbtInt);
{
resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst())); resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpUintBitsToFloat: case EOpUintBitsToFloat:
if (getType().getBasicType() == EbtUInt) ASSERT(getType().getBasicType() == EbtUInt);
{
resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst())); resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpExp: case EOpExp:
if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
return nullptr; break;
break;
case EOpLog: case EOpLog:
// For log(x), results are undefined if x <= 0, we are choosing to set result to 0. // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f) if (operandArray[i].getFConst() <= 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i])) diagnostics, &resultArray[i]);
return nullptr; else
break; foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
break;
case EOpExp2: case EOpExp2:
if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i])) foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
return nullptr; break;
break;
case EOpLog2: case EOpLog2:
// For log2(x), results are undefined if x <= 0, we are choosing to set result to 0. // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
// And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here. // And log2f is not available on some plarforms like old android, so just using
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f) // log(x)/log(2) here.
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); if (operandArray[i].getFConst() <= 0.0f)
else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i])) UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
return nullptr; diagnostics, &resultArray[i]);
else else
resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f)); {
break; foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
}
break;
case EOpSqrt: case EOpSqrt:
// For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0. // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f) if (operandArray[i].getFConst() < 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i])) diagnostics, &resultArray[i]);
return nullptr; else
break; foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
break;
case EOpInverseSqrt: case EOpInverseSqrt:
// There is no stdlib built-in function equavalent for GLES built-in inversesqrt(), // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
// so getting the square root first using builtin function sqrt() and then taking its inverse. // so getting the square root first using builtin function sqrt() and then taking
// Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0. // its inverse.
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f) // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); // result to 0.
else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i])) if (operandArray[i].getFConst() <= 0.0f)
return nullptr; UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
else diagnostics, &resultArray[i]);
resultArray[i].setFConst(1.0f / resultArray[i].getFConst()); else
break; {
foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
}
break;
case EOpVectorLogicalNot: case EOpVectorLogicalNot:
if (getType().getBasicType() == EbtBool) ASSERT(getType().getBasicType() == EbtBool);
{
resultArray[i].setBConst(!operandArray[i].getBConst()); resultArray[i].setBConst(!operandArray[i].getBConst());
break; break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpNormalize: case EOpNormalize:
if (getType().getBasicType() == EbtFloat)
{ {
float x = operandArray[i].getFConst(); ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst();
float length = VectorLength(operandArray, objectSize); float length = VectorLength(operandArray, objectSize);
if (length) if (length)
resultArray[i].setFConst(x / length); resultArray[i].setFConst(x / length);
else else
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
&resultArray[i]); diagnostics, &resultArray[i]);
break; break;
} }
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpDFdx: case EOpDFdx:
case EOpDFdy: case EOpDFdy:
case EOpFwidth: case EOpFwidth:
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{
// Derivatives of constant arguments should be 0. // Derivatives of constant arguments should be 0.
resultArray[i].setFConst(0.0f); resultArray[i].setFConst(0.0f);
break; break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
default: default:
return nullptr; return nullptr;
} }
} }
return resultArray; return resultArray;
} }
bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc, void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
TInfoSink &infoSink, TConstantUnion *result) const FloatTypeUnaryFunc builtinFunc,
TConstantUnion *result) const
{ {
ASSERT(builtinFunc); ASSERT(builtinFunc);
if (getType().getBasicType() == EbtFloat) ASSERT(getType().getBasicType() == EbtFloat);
{ result->setFConst(builtinFunc(parameter.getFConst()));
result->setFConst(builtinFunc(parameter.getFConst()));
return true;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return false;
} }
// static // static
TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate, TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
TInfoSink &infoSink)
{ {
ASSERT(aggregate->getSequence()->size() > 0u); ASSERT(aggregate->getSequence()->size() > 0u);
size_t resultSize = aggregate->getType().getObjectSize(); size_t resultSize = aggregate->getType().getObjectSize();
...@@ -1996,7 +1843,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate ...@@ -1996,7 +1843,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate
} }
// static // static
TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink) TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics)
{ {
TOperator op = aggregate->getOp(); TOperator op = aggregate->getOp();
TIntermSequence *sequence = aggregate->getSequence(); TIntermSequence *sequence = aggregate->getSequence();
...@@ -2037,284 +1885,298 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg ...@@ -2037,284 +1885,298 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
// //
switch (op) switch (op)
{ {
case EOpAtan: case EOpAtan:
{ {
if (basicType == EbtFloat) ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{ {
resultArray = new TConstantUnion[maxObjectSize]; float y = unionArrays[0][i].getFConst();
for (size_t i = 0; i < maxObjectSize; i++) float x = unionArrays[1][i].getFConst();
{ // Results are undefined if x and y are both 0.
float y = unionArrays[0][i].getFConst(); if (x == 0.0f && y == 0.0f)
float x = unionArrays[1][i].getFConst(); UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
// Results are undefined if x and y are both 0. &resultArray[i]);
if (x == 0.0f && y == 0.0f) else
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); resultArray[i].setFConst(atan2f(y, x));
else
resultArray[i].setFConst(atan2f(y, x));
}
} }
else break;
UNREACHABLE();
} }
break;
case EOpPow: case EOpPow:
{ {
if (basicType == EbtFloat) ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{ {
resultArray = new TConstantUnion[maxObjectSize]; float x = unionArrays[0][i].getFConst();
for (size_t i = 0; i < maxObjectSize; i++) float y = unionArrays[1][i].getFConst();
{ // Results are undefined if x < 0.
float x = unionArrays[0][i].getFConst(); // Results are undefined if x = 0 and y <= 0.
float y = unionArrays[1][i].getFConst(); if (x < 0.0f)
// Results are undefined if x < 0. UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
// Results are undefined if x = 0 and y <= 0. &resultArray[i]);
if (x < 0.0f) else if (x == 0.0f && y <= 0.0f)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
else if (x == 0.0f && y <= 0.0f) &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); else
else resultArray[i].setFConst(powf(x, y));
resultArray[i].setFConst(powf(x, y));
}
} }
else break;
UNREACHABLE();
} }
break;
case EOpMod: case EOpMod:
{ {
if (basicType == EbtFloat) ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{ {
resultArray = new TConstantUnion[maxObjectSize]; float x = unionArrays[0][i].getFConst();
for (size_t i = 0; i < maxObjectSize; i++) float y = unionArrays[1][i].getFConst();
{ resultArray[i].setFConst(x - y * floorf(x / y));
float x = unionArrays[0][i].getFConst();
float y = unionArrays[1][i].getFConst();
resultArray[i].setFConst(x - y * floorf(x / y));
}
} }
else break;
UNREACHABLE();
} }
break;
case EOpMin: case EOpMin:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
break; unionArrays[1][i].getFConst()));
case EbtInt: break;
resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst())); case EbtInt:
break; resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
case EbtUInt: unionArrays[1][i].getIConst()));
resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); break;
break; case EbtUInt:
default: resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
UNREACHABLE(); unionArrays[1][i].getUConst()));
break; break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break;
case EOpMax: case EOpMax:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
break; unionArrays[1][i].getFConst()));
case EbtInt: break;
resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst())); case EbtInt:
break; resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
case EbtUInt: unionArrays[1][i].getIConst()));
resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); break;
break; case EbtUInt:
default: resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
UNREACHABLE(); unionArrays[1][i].getUConst()));
break; break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break;
case EOpStep: case EOpStep:
{ {
if (basicType == EbtFloat) ASSERT(basicType == EbtFloat);
{ resultArray = new TConstantUnion[maxObjectSize];
resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++)
for (size_t i = 0; i < maxObjectSize; i++) resultArray[i].setFConst(
resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f); unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
} : 1.0f);
else break;
UNREACHABLE();
} }
break;
case EOpLessThan: case EOpLessThan:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst()); resultArray[i].setBConst(unionArrays[0][i].getFConst() <
break; unionArrays[1][i].getFConst());
case EbtInt: break;
resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst()); case EbtInt:
break; resultArray[i].setBConst(unionArrays[0][i].getIConst() <
case EbtUInt: unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst()); break;
break; case EbtUInt:
default: resultArray[i].setBConst(unionArrays[0][i].getUConst() <
UNREACHABLE(); unionArrays[1][i].getUConst());
break; break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break;
case EOpLessThanEqual: case EOpLessThanEqual:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst()); resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
break; unionArrays[1][i].getFConst());
case EbtInt: break;
resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst()); case EbtInt:
break; resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
case EbtUInt: unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst()); break;
break; case EbtUInt:
default: resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
UNREACHABLE(); unionArrays[1][i].getUConst());
break; break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break;
case EOpGreaterThan: case EOpGreaterThan:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst()); resultArray[i].setBConst(unionArrays[0][i].getFConst() >
break; unionArrays[1][i].getFConst());
case EbtInt: break;
resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst()); case EbtInt:
break; resultArray[i].setBConst(unionArrays[0][i].getIConst() >
case EbtUInt: unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst()); break;
break; case EbtUInt:
default: resultArray[i].setBConst(unionArrays[0][i].getUConst() >
UNREACHABLE(); unionArrays[1][i].getUConst());
break; break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break; case EOpGreaterThanEqual:
case EOpGreaterThanEqual:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst()); resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
break; unionArrays[1][i].getFConst());
case EbtInt: break;
resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst()); case EbtInt:
break; resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
case EbtUInt: unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst()); break;
break; case EbtUInt:
default: resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
UNREACHABLE(); unionArrays[1][i].getUConst());
break; break;
default:
UNREACHABLE();
break;
} }
} }
} }
break; break;
case EOpVectorEqual: case EOpVectorEqual:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst()); resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
break; unionArrays[1][i].getFConst());
case EbtInt: break;
resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst()); case EbtInt:
break; resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
case EbtUInt: unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst()); break;
break; case EbtUInt:
case EbtBool: resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst()); unionArrays[1][i].getUConst());
break; break;
default: case EbtBool:
UNREACHABLE(); resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
break; unionArrays[1][i].getBConst());
break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break;
case EOpVectorNotEqual: case EOpVectorNotEqual:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst()); resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
break; unionArrays[1][i].getFConst());
case EbtInt: break;
resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst()); case EbtInt:
break; resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
case EbtUInt: unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst()); break;
break; case EbtUInt:
case EbtBool: resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst()); unionArrays[1][i].getUConst());
break; break;
default: case EbtBool:
UNREACHABLE(); resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
break; unionArrays[1][i].getBConst());
break;
default:
UNREACHABLE();
break;
} }
} }
break;
} }
break;
case EOpDistance: case EOpDistance:
if (basicType == EbtFloat)
{ {
ASSERT(basicType == EbtFloat);
TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize]; TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
float x = unionArrays[0][i].getFConst(); float x = unionArrays[0][i].getFConst();
...@@ -2322,47 +2184,40 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg ...@@ -2322,47 +2184,40 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
distanceArray[i].setFConst(x - y); distanceArray[i].setFConst(x - y);
} }
resultArray->setFConst(VectorLength(distanceArray, maxObjectSize)); resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
break;
} }
else
UNREACHABLE();
break;
case EOpDot:
if (basicType == EbtFloat) case EOpDot:
{ ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion(); resultArray = new TConstantUnion();
resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); resultArray->setFConst(
} VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
else break;
UNREACHABLE();
break;
case EOpCross: case EOpCross:
if (basicType == EbtFloat && maxObjectSize == 3)
{ {
ASSERT(basicType == EbtFloat && maxObjectSize == 3);
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
float x0 = unionArrays[0][0].getFConst(); float x0 = unionArrays[0][0].getFConst();
float x1 = unionArrays[0][1].getFConst(); float x1 = unionArrays[0][1].getFConst();
float x2 = unionArrays[0][2].getFConst(); float x2 = unionArrays[0][2].getFConst();
float y0 = unionArrays[1][0].getFConst(); float y0 = unionArrays[1][0].getFConst();
float y1 = unionArrays[1][1].getFConst(); float y1 = unionArrays[1][1].getFConst();
float y2 = unionArrays[1][2].getFConst(); float y2 = unionArrays[1][2].getFConst();
resultArray[0].setFConst(x1 * y2 - y1 * x2); resultArray[0].setFConst(x1 * y2 - y1 * x2);
resultArray[1].setFConst(x2 * y0 - y2 * x0); resultArray[1].setFConst(x2 * y0 - y2 * x0);
resultArray[2].setFConst(x0 * y1 - y0 * x1); resultArray[2].setFConst(x0 * y1 - y0 * x1);
break;
} }
else
UNREACHABLE();
break;
case EOpReflect: case EOpReflect:
if (basicType == EbtFloat)
{ {
ASSERT(basicType == EbtFloat);
// genType reflect (genType I, genType N) : // genType reflect (genType I, genType N) :
// For the incident vector I and surface orientation N, returns the reflection direction: // For the incident vector I and surface orientation N, returns the reflection
// direction:
// I - 2 * dot(N, I) * N. // I - 2 * dot(N, I) * N.
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
...@@ -2370,45 +2225,40 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg ...@@ -2370,45 +2225,40 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
2.0f * dotProduct * unionArrays[1][i].getFConst(); 2.0f * dotProduct * unionArrays[1][i].getFConst();
resultArray[i].setFConst(result); resultArray[i].setFConst(result);
} }
break;
} }
else
UNREACHABLE();
break;
case EOpMul: case EOpMul:
if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
(*sequence)[1]->getAsTyped()->isMatrix())
{ {
ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
(*sequence)[1]->getAsTyped()->isMatrix());
// Perform component-wise matrix multiplication. // Perform component-wise matrix multiplication.
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
int size = (*sequence)[0]->getAsTyped()->getNominalSize(); int size = (*sequence)[0]->getAsTyped()->getNominalSize();
angle::Matrix<float> result = angle::Matrix<float> result =
GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size)); GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
SetUnionArrayFromMatrix(result, resultArray); SetUnionArrayFromMatrix(result, resultArray);
break;
} }
else
UNREACHABLE();
break;
case EOpOuterProduct: case EOpOuterProduct:
if (basicType == EbtFloat)
{ {
ASSERT(basicType == EbtFloat);
size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize(); size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize(); size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
resultArray = new TConstantUnion[numRows * numCols]; resultArray = new TConstantUnion[numRows * numCols];
angle::Matrix<float> result = angle::Matrix<float> result =
GetMatrix(unionArrays[0], static_cast<int>(numRows), 1) GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
.outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols))); .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
SetUnionArrayFromMatrix(result, resultArray); SetUnionArrayFromMatrix(result, resultArray);
break;
} }
else
UNREACHABLE();
break;
default: default:
UNREACHABLE(); UNREACHABLE();
// TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above. // TODO: Add constant folding support for other built-in operations that take 2
return nullptr; // parameters and not handled above.
return nullptr;
} }
} }
else if (paramsCount == 3) else if (paramsCount == 3)
...@@ -2418,124 +2268,123 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg ...@@ -2418,124 +2268,123 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
// //
switch (op) switch (op)
{ {
case EOpClamp: case EOpClamp:
{ {
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
switch (basicType) switch (basicType)
{ {
case EbtFloat: case EbtFloat:
{ {
float x = unionArrays[0][i].getFConst(); float x = unionArrays[0][i].getFConst();
float min = unionArrays[1][i].getFConst(); float min = unionArrays[1][i].getFConst();
float max = unionArrays[2][i].getFConst(); float max = unionArrays[2][i].getFConst();
// Results are undefined if min > max. // Results are undefined if min > max.
if (min > max) if (min > max)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else else
resultArray[i].setFConst(gl::clamp(x, min, max)); resultArray[i].setFConst(gl::clamp(x, min, max));
break;
} }
break;
case EbtInt: case EbtInt:
{ {
int x = unionArrays[0][i].getIConst(); int x = unionArrays[0][i].getIConst();
int min = unionArrays[1][i].getIConst(); int min = unionArrays[1][i].getIConst();
int max = unionArrays[2][i].getIConst(); int max = unionArrays[2][i].getIConst();
// Results are undefined if min > max. // Results are undefined if min > max.
if (min > max) if (min > max)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else else
resultArray[i].setIConst(gl::clamp(x, min, max)); resultArray[i].setIConst(gl::clamp(x, min, max));
break;
} }
break; case EbtUInt:
case EbtUInt:
{ {
unsigned int x = unionArrays[0][i].getUConst(); unsigned int x = unionArrays[0][i].getUConst();
unsigned int min = unionArrays[1][i].getUConst(); unsigned int min = unionArrays[1][i].getUConst();
unsigned int max = unionArrays[2][i].getUConst(); unsigned int max = unionArrays[2][i].getUConst();
// Results are undefined if min > max. // Results are undefined if min > max.
if (min > max) if (min > max)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else else
resultArray[i].setUConst(gl::clamp(x, min, max)); resultArray[i].setUConst(gl::clamp(x, min, max));
break;
} }
break; default:
default: UNREACHABLE();
UNREACHABLE(); break;
break;
} }
} }
break;
} }
break;
case EOpMix: case EOpMix:
{ {
if (basicType == EbtFloat) ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{ {
resultArray = new TConstantUnion[maxObjectSize]; float x = unionArrays[0][i].getFConst();
for (size_t i = 0; i < maxObjectSize; i++) float y = unionArrays[1][i].getFConst();
TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
if (type == EbtFloat)
{ {
float x = unionArrays[0][i].getFConst(); // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
float y = unionArrays[1][i].getFConst(); float a = unionArrays[2][i].getFConst();
TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType(); resultArray[i].setFConst(x * (1.0f - a) + y * a);
if (type == EbtFloat) }
{ else // 3rd parameter is EbtBool
// Returns the linear blend of x and y, i.e., x * (1 - a) + y * a. {
float a = unionArrays[2][i].getFConst(); ASSERT(type == EbtBool);
resultArray[i].setFConst(x * (1.0f - a) + y * a); // Selects which vector each returned component comes from.
} // For a component of a that is false, the corresponding component of x is
else // 3rd parameter is EbtBool // returned.
{ // For a component of a that is true, the corresponding component of y is
ASSERT(type == EbtBool); // returned.
// Selects which vector each returned component comes from. bool a = unionArrays[2][i].getBConst();
// For a component of a that is false, the corresponding component of x is returned. resultArray[i].setFConst(a ? y : x);
// For a component of a that is true, the corresponding component of y is returned.
bool a = unionArrays[2][i].getBConst();
resultArray[i].setFConst(a ? y : x);
}
} }
} }
else break;
UNREACHABLE();
} }
break;
case EOpSmoothStep: case EOpSmoothStep:
{ {
if (basicType == EbtFloat) ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{ {
resultArray = new TConstantUnion[maxObjectSize]; float edge0 = unionArrays[0][i].getFConst();
for (size_t i = 0; i < maxObjectSize; i++) float edge1 = unionArrays[1][i].getFConst();
float x = unionArrays[2][i].getFConst();
// Results are undefined if edge0 >= edge1.
if (edge0 >= edge1)
{ {
float edge0 = unionArrays[0][i].getFConst(); UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
float edge1 = unionArrays[1][i].getFConst(); &resultArray[i]);
float x = unionArrays[2][i].getFConst(); }
// Results are undefined if edge0 >= edge1. else
if (edge0 >= edge1) {
{ // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
} float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
else resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
{
// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
// Hermite interpolation between 0 and 1 when edge0 < x < edge1.
float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
}
} }
} }
else break;
UNREACHABLE();
} }
break;
case EOpFaceForward: case EOpFaceForward:
if (basicType == EbtFloat)
{ {
ASSERT(basicType == EbtFloat);
// genType faceforward(genType N, genType I, genType Nref) : // genType faceforward(genType N, genType I, genType Nref) :
// If dot(Nref, I) < 0 return N, otherwise return -N. // If dot(Nref, I) < 0 return N, otherwise return -N.
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize); float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
...@@ -2544,43 +2393,42 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg ...@@ -2544,43 +2393,42 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
else else
resultArray[i].setFConst(-unionArrays[0][i].getFConst()); resultArray[i].setFConst(-unionArrays[0][i].getFConst());
} }
break;
} }
else
UNREACHABLE();
break;
case EOpRefract: case EOpRefract:
if (basicType == EbtFloat)
{ {
ASSERT(basicType == EbtFloat);
// genType refract(genType I, genType N, float eta) : // genType refract(genType I, genType N, float eta) :
// For the incident vector I and surface normal N, and the ratio of indices of refraction eta, // For the incident vector I and surface normal N, and the ratio of indices of
// refraction eta,
// return the refraction vector. The result is computed by // return the refraction vector. The result is computed by
// k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)) // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
// if (k < 0.0) // if (k < 0.0)
// return genType(0.0) // return genType(0.0)
// else // else
// return eta * I - (eta * dot(N, I) + sqrt(k)) * N // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
resultArray = new TConstantUnion[maxObjectSize]; resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
for (size_t i = 0; i < maxObjectSize; i++) for (size_t i = 0; i < maxObjectSize; i++)
{ {
float eta = unionArrays[2][i].getFConst(); float eta = unionArrays[2][i].getFConst();
float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct); float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
if (k < 0.0f) if (k < 0.0f)
resultArray[i].setFConst(0.0f); resultArray[i].setFConst(0.0f);
else else
resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() - resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
(eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst()); (eta * dotProduct + sqrtf(k)) *
unionArrays[1][i].getFConst());
} }
break;
} }
else
UNREACHABLE();
break;
default: default:
UNREACHABLE(); UNREACHABLE();
// TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above. // TODO: Add constant folding support for other built-in operations that take 3
return nullptr; // parameters and not handled above.
return nullptr;
} }
} }
return resultArray; return resultArray;
......
...@@ -319,6 +319,7 @@ class TIntermConstantUnion : public TIntermTyped ...@@ -319,6 +319,7 @@ class TIntermConstantUnion : public TIntermTyped
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type) TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
: TIntermTyped(type), mUnionArrayPointer(unionPointer) : TIntermTyped(type), mUnionArrayPointer(unionPointer)
{ {
ASSERT(unionPointer);
} }
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); } TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
...@@ -346,6 +347,7 @@ class TIntermConstantUnion : public TIntermTyped ...@@ -346,6 +347,7 @@ class TIntermConstantUnion : public TIntermTyped
void replaceConstantUnion(const TConstantUnion *safeConstantUnion) void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
{ {
ASSERT(safeConstantUnion);
// Previous union pointer freed on pool deallocation. // Previous union pointer freed on pool deallocation.
mUnionArrayPointer = safeConstantUnion; mUnionArrayPointer = safeConstantUnion;
} }
...@@ -357,12 +359,12 @@ class TIntermConstantUnion : public TIntermTyped ...@@ -357,12 +359,12 @@ class TIntermConstantUnion : public TIntermTyped
TConstantUnion *foldBinary(TOperator op, TConstantUnion *foldBinary(TOperator op,
TIntermConstantUnion *rightNode, TIntermConstantUnion *rightNode,
TDiagnostics *diagnostics); TDiagnostics *diagnostics);
TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink); TConstantUnion *foldUnaryNonComponentWise(TOperator op);
TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink); TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate, static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
TInfoSink &infoSink); static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink); TDiagnostics *diagnostics);
protected: protected:
// Same data may be shared between multiple constant unions, so it can't be modified. // Same data may be shared between multiple constant unions, so it can't be modified.
...@@ -370,7 +372,9 @@ class TIntermConstantUnion : public TIntermTyped ...@@ -370,7 +372,9 @@ class TIntermConstantUnion : public TIntermTyped
private: private:
typedef float(*FloatTypeUnaryFunc) (float); typedef float(*FloatTypeUnaryFunc) (float);
bool foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const; void foldFloatTypeUnary(const TConstantUnion &parameter,
FloatTypeUnaryFunc builtinFunc,
TConstantUnion *result) const;
TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
}; };
...@@ -468,6 +472,11 @@ class TIntermUnary : public TIntermOperator ...@@ -468,6 +472,11 @@ class TIntermUnary : public TIntermOperator
mOperand(NULL), mOperand(NULL),
mUseEmulatedFunction(false) {} mUseEmulatedFunction(false) {}
TIntermUnary(TOperator op, TIntermTyped *operand)
: TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
{
}
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); } TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
...@@ -479,7 +488,7 @@ class TIntermUnary : public TIntermOperator ...@@ -479,7 +488,7 @@ class TIntermUnary : public TIntermOperator
void setOperand(TIntermTyped *operand) { mOperand = operand; } void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; } TIntermTyped *getOperand() { return mOperand; }
void promote(const TType *funcReturnType); void promote(const TType *funcReturnType);
TIntermTyped *fold(TInfoSink &infoSink); TIntermTyped *fold(TDiagnostics *diagnostics);
void setUseEmulatedFunction() { mUseEmulatedFunction = true; } void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
...@@ -532,7 +541,7 @@ class TIntermAggregate : public TIntermOperator ...@@ -532,7 +541,7 @@ class TIntermAggregate : public TIntermOperator
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions); bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects // Conservatively assume function calls and other aggregate operators have side-effects
bool hasSideEffects() const override { return true; } bool hasSideEffects() const override { return true; }
TIntermTyped *fold(TInfoSink &infoSink); TIntermTyped *fold(TDiagnostics *diagnostics);
TIntermSequence *getSequence() { return &mSequence; } TIntermSequence *getSequence() { return &mSequence; }
const TIntermSequence *getSequence() const { return &mSequence; } const TIntermSequence *getSequence() const { return &mSequence; }
......
...@@ -58,29 +58,6 @@ TIntermTyped *TIntermediate::addIndex( ...@@ -58,29 +58,6 @@ TIntermTyped *TIntermediate::addIndex(
} }
// //
// Add one node as the parent of another that it operates on.
//
// Returns the added node.
//
TIntermTyped *TIntermediate::addUnaryMath(
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType)
{
//
// Make a new node for the operator.
//
TIntermUnary *node = new TIntermUnary(op);
node->setLine(line);
node->setOperand(child);
node->promote(funcReturnType);
TIntermTyped *foldedNode = node->fold(mInfoSink);
if (foldedNode)
return foldedNode;
return node;
}
//
// This is the safe way to change the operator on an aggregate, as it // This is the safe way to change the operator on an aggregate, as it
// does lots of error checking and fixing. Especially for establishing // does lots of error checking and fixing. Especially for establishing
// a function call's operation on it's set of parameters. Sequences // a function call's operation on it's set of parameters. Sequences
...@@ -388,7 +365,7 @@ TIntermBranch* TIntermediate::addBranch( ...@@ -388,7 +365,7 @@ TIntermBranch* TIntermediate::addBranch(
// This is to be executed once the final root is put on top by the parsing // This is to be executed once the final root is put on top by the parsing
// process. // process.
// //
TIntermAggregate *TIntermediate::postProcess(TIntermNode *root) TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root)
{ {
if (root == nullptr) if (root == nullptr)
return nullptr; return nullptr;
...@@ -411,7 +388,8 @@ TIntermAggregate *TIntermediate::postProcess(TIntermNode *root) ...@@ -411,7 +388,8 @@ TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
return aggRoot; return aggRoot;
} }
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate) TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics)
{ {
switch (aggregate->getOp()) switch (aggregate->getOp())
{ {
...@@ -438,12 +416,12 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate) ...@@ -438,12 +416,12 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
case EOpFaceForward: case EOpFaceForward:
case EOpReflect: case EOpReflect:
case EOpRefract: case EOpRefract:
return aggregate->fold(mInfoSink); return aggregate->fold(diagnostics);
default: default:
// TODO: Add support for folding array constructors // TODO: Add support for folding array constructors
if (aggregate->isConstructor() && !aggregate->isArray()) if (aggregate->isConstructor() && !aggregate->isArray())
{ {
return aggregate->fold(mInfoSink); return aggregate->fold(diagnostics);
} }
// Constant folding not supported for the built-in. // Constant folding not supported for the built-in.
return nullptr; return nullptr;
......
...@@ -16,15 +16,13 @@ struct TVectorFields ...@@ -16,15 +16,13 @@ struct TVectorFields
}; };
// //
// Set of helper functions to help parse and build the tree. // Set of helper functions to help build the tree.
// //
class TInfoSink;
class TIntermediate class TIntermediate
{ {
public: public:
POOL_ALLOCATOR_NEW_DELETE(); POOL_ALLOCATOR_NEW_DELETE();
TIntermediate(TInfoSink &i) TIntermediate() {}
: mInfoSink(i) { }
TIntermSymbol *addSymbol( TIntermSymbol *addSymbol(
int id, const TString &, const TType &, const TSourceLoc &); int id, const TString &, const TType &, const TSourceLoc &);
...@@ -56,16 +54,14 @@ class TIntermediate ...@@ -56,16 +54,14 @@ class TIntermediate
TIntermBranch *addBranch(TOperator, const TSourceLoc &); TIntermBranch *addBranch(TOperator, const TSourceLoc &);
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &); TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &); TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
TIntermAggregate *postProcess(TIntermNode *root); static TIntermAggregate *PostProcess(TIntermNode *root);
static void outputTree(TIntermNode *, TInfoSinkBase &); static void outputTree(TIntermNode *, TInfoSinkBase &);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate); TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
private: private:
void operator=(TIntermediate &); // prevent assignments void operator=(TIntermediate &); // prevent assignments
TInfoSink & mInfoSink;
}; };
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ #endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_
...@@ -2376,7 +2376,7 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, ...@@ -2376,7 +2376,7 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
constructor->setType(type); constructor->setType(type);
TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor); TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
if (constConstructor) if (constConstructor)
{ {
return constConstructor; return constConstructor;
...@@ -3425,7 +3425,15 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, ...@@ -3425,7 +3425,15 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op,
break; break;
} }
return intermediate.addUnaryMath(op, child, loc, funcReturnType); TIntermUnary *node = new TIntermUnary(op, child);
node->setLine(loc);
node->promote(funcReturnType);
TIntermTyped *foldedNode = node->fold(&mDiagnostics);
if (foldedNode)
return foldedNode;
return node;
} }
TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
...@@ -4054,7 +4062,8 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, ...@@ -4054,7 +4062,8 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
// See if we can constant fold a built-in. Note that this may be possible even // See if we can constant fold a built-in. Note that this may be possible even
// if it is not const-qualified. // if it is not const-qualified.
TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate); TIntermTyped *foldedNode =
intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics);
if (foldedNode) if (foldedNode)
{ {
callNode = foldedNode; callNode = foldedNode;
......
...@@ -31,14 +31,13 @@ class TParseContext : angle::NonCopyable ...@@ -31,14 +31,13 @@ class TParseContext : angle::NonCopyable
public: public:
TParseContext(TSymbolTable &symt, TParseContext(TSymbolTable &symt,
TExtensionBehavior &ext, TExtensionBehavior &ext,
TIntermediate &interm,
sh::GLenum type, sh::GLenum type,
ShShaderSpec spec, ShShaderSpec spec,
int options, int options,
bool checksPrecErrors, bool checksPrecErrors,
TInfoSink &is, TInfoSink &is,
const ShBuiltInResources &resources) const ShBuiltInResources &resources)
: intermediate(interm), : intermediate(),
symbolTable(symt), symbolTable(symt),
mDeferredSingleDeclarationErrorCheck(false), mDeferredSingleDeclarationErrorCheck(false),
mShaderType(type), mShaderType(type),
...@@ -367,7 +366,7 @@ class TParseContext : angle::NonCopyable ...@@ -367,7 +366,7 @@ class TParseContext : angle::NonCopyable
TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line); TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line);
// TODO(jmadill): make these private // TODO(jmadill): make these private
TIntermediate &intermediate; // to hold and build a parse tree TIntermediate intermediate; // to build a parse tree
TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
private: private:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment