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[],
++firstSource;
}
TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
compileOptions, true, infoSink, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
......@@ -254,7 +253,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
root = parseContext.getTreeRoot();
root = intermediate.postProcess(root);
root = TIntermediate::PostProcess(root);
// Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
......
......@@ -44,13 +44,14 @@ TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
return constUnion;
}
void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
TInfoSink &infoSink, TConstantUnion *result)
void UndefinedConstantFoldingError(const TSourceLoc &loc,
TOperator op,
TBasicType basicType,
TDiagnostics *diagnostics,
TConstantUnion *result)
{
std::stringstream constantFoldingErrorStream;
constantFoldingErrorStream << "'" << GetOperatorString(op)
<< "' operation result is undefined for the values passed in";
infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
diagnostics->warning(loc, "operation result is undefined for the values passed in",
GetOperatorString(op), "");
switch (basicType)
{
......@@ -856,7 +857,7 @@ TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
return CreateFoldedNode(constArray, this, resultQualifier);
}
TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
{
TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
if (operandConstant == nullptr)
......@@ -879,10 +880,10 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
case EOpUnpackUnorm2x16:
case EOpPackHalf2x16:
case EOpUnpackHalf2x16:
constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
constArray = operandConstant->foldUnaryNonComponentWise(mOp);
break;
default:
constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
break;
}
......@@ -891,7 +892,7 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
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.
for (auto *param : *getSequence())
......@@ -903,9 +904,9 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
}
TConstantUnion *constArray = nullptr;
if (isConstructor())
constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
else
constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
// Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
......@@ -925,10 +926,7 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
const TConstantUnion *leftArray = getUnionArrayPointer();
const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
if (!leftArray)
return nullptr;
if (!rightArray)
return nullptr;
ASSERT(leftArray && rightArray);
size_t objectSize = getType().getObjectSize();
......@@ -1224,29 +1222,22 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
return resultArray;
}
//
// The fold functions see if an operation on a constant can be done in place,
// without generating run-time code.
//
// Returns the constant value to keep using or nullptr.
//
TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
// The fold functions do operations on a constant at GLSL compile time, without generating run-time
// code. Returns the constant value to keep using. Nullptr should not be returned.
TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
{
//
// Do operations where the return type has a different number of components compared to the operand type.
//
// Do operations where the return type may have a different number of components compared to the
// operand type.
const TConstantUnion *operandArray = getUnionArrayPointer();
if (!operandArray)
return nullptr;
ASSERT(operandArray);
size_t objectSize = getType().getObjectSize();
TConstantUnion *resultArray = nullptr;
switch (op)
{
case EOpAny:
if (getType().getBasicType() == EbtBool)
{
ASSERT(getType().getBasicType() == EbtBool);
resultArray = new TConstantUnion();
resultArray->setBConst(false);
for (size_t i = 0; i < objectSize; i++)
......@@ -1258,16 +1249,9 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
}
}
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpAll:
if (getType().getBasicType() == EbtBool)
{
ASSERT(getType().getBasicType() == EbtBool);
resultArray = new TConstantUnion();
resultArray->setBConst(true);
for (size_t i = 0; i < objectSize; i++)
......@@ -1279,59 +1263,36 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
}
}
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpLength:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray = new TConstantUnion();
resultArray->setFConst(VectorLength(operandArray, objectSize));
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpTranspose:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray = new TConstantUnion[objectSize];
angle::Matrix<float> result =
GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
SetUnionArrayFromMatrix(result, resultArray);
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpDeterminant:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
unsigned int size = getType().getNominalSize();
ASSERT(size >= 2 && size <= 4);
resultArray = new TConstantUnion();
resultArray->setFConst(GetMatrix(operandArray, size).determinant());
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpInverse:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
unsigned int size = getType().getNominalSize();
ASSERT(size >= 2 && size <= 4);
resultArray = new TConstantUnion[objectSize];
......@@ -1339,29 +1300,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
SetUnionArrayFromMatrix(result, resultArray);
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpPackSnorm2x16:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion();
resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
resultArray->setUConst(
gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpUnpackSnorm2x16:
if (getType().getBasicType() == EbtUInt)
{
ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2];
float f1, f2;
gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
......@@ -1369,29 +1319,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
resultArray[1].setFConst(f2);
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpPackUnorm2x16:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion();
resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
resultArray->setUConst(
gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpUnpackUnorm2x16:
if (getType().getBasicType() == EbtUInt)
{
ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2];
float f1, f2;
gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
......@@ -1399,29 +1338,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
resultArray[1].setFConst(f2);
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpPackHalf2x16:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion();
resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
resultArray->setUConst(
gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
case EOpUnpackHalf2x16:
if (getType().getBasicType() == EbtUInt)
{
ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2];
float f1, f2;
gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
......@@ -1429,29 +1357,24 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator
resultArray[1].setFConst(f2);
break;
}
else
{
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
}
break;
default:
UNREACHABLE();
break;
}
return resultArray;
}
TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
TDiagnostics *diagnostics)
{
//
// Do unary operations where the return type is the same as operand type.
//
// Do unary operations where each component of the result is computed based on the corresponding
// component of the operand. Also folds normalize, though the divisor in that case takes all
// components into account.
const TConstantUnion *operandArray = getUnionArrayPointer();
if (!operandArray)
return nullptr;
ASSERT(operandArray);
size_t objectSize = getType().getObjectSize();
......@@ -1474,9 +1397,7 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
-static_cast<int>(operandArray[i].getUConst())));
break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
UNREACHABLE();
return nullptr;
}
break;
......@@ -1495,25 +1416,19 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
static_cast<int>(operandArray[i].getUConst())));
break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
UNREACHABLE();
return nullptr;
}
break;
case EOpLogicalNot:
// this code is written for possible future use,
// will not get executed currently
switch (getType().getBasicType())
{
case EbtBool:
resultArray[i].setBConst(!operandArray[i].getBConst());
break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
UNREACHABLE();
return nullptr;
}
break;
......@@ -1528,105 +1443,90 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
resultArray[i].setUConst(~operandArray[i].getUConst());
break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
UNREACHABLE();
return nullptr;
}
break;
case EOpRadians:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpDegrees:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpSin:
if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
break;
case EOpCos:
if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
break;
case EOpTan:
if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
break;
case EOpAsin:
// For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
return nullptr;
// For asin(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], &asinf, &resultArray[i]);
break;
case EOpAcos:
// For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
return nullptr;
// For acos(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], &acosf, &resultArray[i]);
break;
case EOpAtan:
if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
break;
case EOpSinh:
if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
break;
case EOpCosh:
if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
break;
case EOpTanh:
if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
break;
case EOpAsinh:
if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
break;
case EOpAcosh:
// For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
return nullptr;
if (operandArray[i].getFConst() < 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
break;
case EOpAtanh:
// For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
return nullptr;
// 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;
case EOpAbs:
......@@ -1639,9 +1539,7 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
resultArray[i].setIConst(abs(operandArray[i].getIConst()));
break;
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
UNREACHABLE();
return nullptr;
}
break;
......@@ -1658,8 +1556,8 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
else if (fConst < 0.0f)
fResult = -1.0f;
resultArray[i].setFConst(fResult);
}
break;
}
case EbtInt:
{
int iConst = operandArray[i].getIConst();
......@@ -1669,34 +1567,29 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
else if (iConst < 0)
iResult = -1;
resultArray[i].setIConst(iResult);
}
break;
}
default:
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
UNREACHABLE();
return nullptr;
}
break;
case EOpFloor:
if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
break;
case EOpTrunc:
if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
break;
case EOpRound:
if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
break;
case EOpRoundEven:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst();
float result;
float fractPart = modff(x, &result);
......@@ -1707,168 +1600,130 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
resultArray[i].setFConst(result);
break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpCeil:
if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
break;
case EOpFract:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst();
resultArray[i].setFConst(x - floorf(x));
break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpIsNan:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpIsInf:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpFloatBitsToInt:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpFloatBitsToUint:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpIntBitsToFloat:
if (getType().getBasicType() == EbtInt)
{
ASSERT(getType().getBasicType() == EbtInt);
resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpUintBitsToFloat:
if (getType().getBasicType() == EbtUInt)
{
ASSERT(getType().getBasicType() == EbtUInt);
resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpExp:
if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
break;
case EOpLog:
// 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)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
return nullptr;
if (operandArray[i].getFConst() <= 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
break;
case EOpExp2:
if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
return nullptr;
foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
break;
case EOpLog2:
// 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.
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
return nullptr;
// And log2f is not available on some plarforms like old android, so just using
// log(x)/log(2) here.
if (operandArray[i].getFConst() <= 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
{
foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
}
break;
case EOpSqrt:
// 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)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
return nullptr;
if (operandArray[i].getFConst() < 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
break;
case EOpInverseSqrt:
// 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.
// Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
return nullptr;
// so getting the square root first using builtin function sqrt() and then taking
// its inverse.
// Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
// result to 0.
if (operandArray[i].getFConst() <= 0.0f)
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
else
{
foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
}
break;
case EOpVectorLogicalNot:
if (getType().getBasicType() == EbtBool)
{
ASSERT(getType().getBasicType() == EbtBool);
resultArray[i].setBConst(!operandArray[i].getBConst());
break;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return nullptr;
case EOpNormalize:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst();
float length = VectorLength(operandArray, objectSize);
if (length)
resultArray[i].setFConst(x / length);
else
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
&resultArray[i]);
UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
diagnostics, &resultArray[i]);
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
case EOpDFdx:
case EOpDFdy:
case EOpFwidth:
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
// Derivatives of constant arguments should be 0.
resultArray[i].setFConst(0.0f);
break;
}
infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
return nullptr;
default:
return nullptr;
......@@ -1878,26 +1733,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op,
return resultArray;
}
bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
TInfoSink &infoSink, TConstantUnion *result) const
void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
FloatTypeUnaryFunc builtinFunc,
TConstantUnion *result) const
{
ASSERT(builtinFunc);
if (getType().getBasicType() == EbtFloat)
{
ASSERT(getType().getBasicType() == EbtFloat);
result->setFConst(builtinFunc(parameter.getFConst()));
return true;
}
infoSink.info.message(
EPrefixInternalError, getLine(),
"Unary operation not folded into constant");
return false;
}
// static
TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
TInfoSink &infoSink)
TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
{
ASSERT(aggregate->getSequence()->size() > 0u);
size_t resultSize = aggregate->getType().getObjectSize();
......@@ -1996,7 +1843,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate
}
// static
TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics)
{
TOperator op = aggregate->getOp();
TIntermSequence *sequence = aggregate->getSequence();
......@@ -2039,8 +1887,7 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
{
case EOpAtan:
{
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
......@@ -2048,20 +1895,17 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
float x = unionArrays[1][i].getFConst();
// Results are undefined if x and y are both 0.
if (x == 0.0f && y == 0.0f)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else
resultArray[i].setFConst(atan2f(y, x));
}
}
else
UNREACHABLE();
}
break;
}
case EOpPow:
{
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
......@@ -2070,22 +1914,20 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
// Results are undefined if x < 0.
// Results are undefined if x = 0 and y <= 0.
if (x < 0.0f)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else if (x == 0.0f && y <= 0.0f)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else
resultArray[i].setFConst(powf(x, y));
}
}
else
UNREACHABLE();
}
break;
}
case EOpMod:
{
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
......@@ -2093,11 +1935,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
float y = unionArrays[1][i].getFConst();
resultArray[i].setFConst(x - y * floorf(x / y));
}
}
else
UNREACHABLE();
}
break;
}
case EOpMin:
{
......@@ -2107,21 +1946,24 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
unionArrays[1][i].getFConst()));
break;
case EbtInt:
resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
unionArrays[1][i].getIConst()));
break;
case EbtUInt:
resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
unionArrays[1][i].getUConst()));
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpMax:
{
......@@ -2131,34 +1973,35 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
unionArrays[1][i].getFConst()));
break;
case EbtInt:
resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
unionArrays[1][i].getIConst()));
break;
case EbtUInt:
resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
unionArrays[1][i].getUConst()));
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpStep:
{
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
}
else
UNREACHABLE();
}
resultArray[i].setFConst(
unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
: 1.0f);
break;
}
case EOpLessThan:
{
......@@ -2168,21 +2011,24 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
resultArray[i].setBConst(unionArrays[0][i].getFConst() <
unionArrays[1][i].getFConst());
break;
case EbtInt:
resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getIConst() <
unionArrays[1][i].getIConst());
break;
case EbtUInt:
resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() <
unionArrays[1][i].getUConst());
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpLessThanEqual:
{
......@@ -2192,21 +2038,24 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
unionArrays[1][i].getFConst());
break;
case EbtInt:
resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
unionArrays[1][i].getIConst());
break;
case EbtUInt:
resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
unionArrays[1][i].getUConst());
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpGreaterThan:
{
......@@ -2216,22 +2065,24 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
resultArray[i].setBConst(unionArrays[0][i].getFConst() >
unionArrays[1][i].getFConst());
break;
case EbtInt:
resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getIConst() >
unionArrays[1][i].getIConst());
break;
case EbtUInt:
resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() >
unionArrays[1][i].getUConst());
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpGreaterThanEqual:
{
resultArray = new TConstantUnion[maxObjectSize];
......@@ -2240,13 +2091,16 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
unionArrays[1][i].getFConst());
break;
case EbtInt:
resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
unionArrays[1][i].getIConst());
break;
case EbtUInt:
resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
unionArrays[1][i].getUConst());
break;
default:
UNREACHABLE();
......@@ -2264,24 +2118,28 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
unionArrays[1][i].getFConst());
break;
case EbtInt:
resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
unionArrays[1][i].getIConst());
break;
case EbtUInt:
resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
unionArrays[1][i].getUConst());
break;
case EbtBool:
resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
unionArrays[1][i].getBConst());
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpVectorNotEqual:
{
......@@ -2291,28 +2149,32 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
switch (basicType)
{
case EbtFloat:
resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
unionArrays[1][i].getFConst());
break;
case EbtInt:
resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
unionArrays[1][i].getIConst());
break;
case EbtUInt:
resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
unionArrays[1][i].getUConst());
break;
case EbtBool:
resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
unionArrays[1][i].getBConst());
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpDistance:
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
resultArray = new TConstantUnion();
for (size_t i = 0; i < maxObjectSize; i++)
......@@ -2322,25 +2184,19 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
distanceArray[i].setFConst(x - y);
}
resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
}
else
UNREACHABLE();
break;
}
case EOpDot:
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion();
resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
}
else
UNREACHABLE();
resultArray->setFConst(
VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
break;
case EOpCross:
if (basicType == EbtFloat && maxObjectSize == 3)
{
ASSERT(basicType == EbtFloat && maxObjectSize == 3);
resultArray = new TConstantUnion[maxObjectSize];
float x0 = unionArrays[0][0].getFConst();
float x1 = unionArrays[0][1].getFConst();
......@@ -2351,16 +2207,15 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
resultArray[0].setFConst(x1 * y2 - y1 * x2);
resultArray[1].setFConst(x2 * y0 - y2 * x0);
resultArray[2].setFConst(x0 * y1 - y0 * x1);
}
else
UNREACHABLE();
break;
}
case EOpReflect:
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
// 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.
resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
......@@ -2370,29 +2225,25 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
2.0f * dotProduct * unionArrays[1][i].getFConst();
resultArray[i].setFConst(result);
}
}
else
UNREACHABLE();
break;
}
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.
resultArray = new TConstantUnion[maxObjectSize];
int size = (*sequence)[0]->getAsTyped()->getNominalSize();
angle::Matrix<float> result =
GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
SetUnionArrayFromMatrix(result, resultArray);
}
else
UNREACHABLE();
break;
}
case EOpOuterProduct:
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
resultArray = new TConstantUnion[numRows * numCols];
......@@ -2400,14 +2251,13 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
.outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
SetUnionArrayFromMatrix(result, resultArray);
}
else
UNREACHABLE();
break;
}
default:
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
// parameters and not handled above.
return nullptr;
}
}
......@@ -2432,11 +2282,13 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
float max = unionArrays[2][i].getFConst();
// Results are undefined if min > max.
if (min > max)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else
resultArray[i].setFConst(gl::clamp(x, min, max));
}
break;
}
case EbtInt:
{
int x = unionArrays[0][i].getIConst();
......@@ -2444,11 +2296,12 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
int max = unionArrays[2][i].getIConst();
// Results are undefined if min > max.
if (min > max)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else
resultArray[i].setIConst(gl::clamp(x, min, max));
}
break;
}
case EbtUInt:
{
unsigned int x = unionArrays[0][i].getUConst();
......@@ -2456,23 +2309,23 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
unsigned int max = unionArrays[2][i].getUConst();
// Results are undefined if min > max.
if (min > max)
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
else
resultArray[i].setUConst(gl::clamp(x, min, max));
}
break;
}
default:
UNREACHABLE();
break;
}
}
}
break;
}
case EOpMix:
{
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
......@@ -2489,22 +2342,20 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
{
ASSERT(type == EbtBool);
// Selects which vector each returned component comes from.
// For a component of a that is false, the corresponding component of x is returned.
// For a component of a that is true, the corresponding component of y is returned.
// For a component of a that is false, the corresponding component of x is
// returned.
// 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
UNREACHABLE();
}
break;
}
case EOpSmoothStep:
{
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
......@@ -2514,7 +2365,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
// Results are undefined if edge0 >= edge1.
if (edge0 >= edge1)
{
UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
&resultArray[i]);
}
else
{
......@@ -2524,15 +2376,12 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
}
}
}
else
UNREACHABLE();
}
break;
}
case EOpFaceForward:
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
// genType faceforward(genType N, genType I, genType Nref) :
// If dot(Nref, I) < 0 return N, otherwise return -N.
resultArray = new TConstantUnion[maxObjectSize];
......@@ -2544,16 +2393,15 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
else
resultArray[i].setFConst(-unionArrays[0][i].getFConst());
}
}
else
UNREACHABLE();
break;
}
case EOpRefract:
if (basicType == EbtFloat)
{
ASSERT(basicType == EbtFloat);
// 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
// k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
// if (k < 0.0)
......@@ -2570,16 +2418,16 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg
resultArray[i].setFConst(0.0f);
else
resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
(eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
(eta * dotProduct + sqrtf(k)) *
unionArrays[1][i].getFConst());
}
}
else
UNREACHABLE();
break;
}
default:
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
// parameters and not handled above.
return nullptr;
}
}
......
......@@ -319,6 +319,7 @@ class TIntermConstantUnion : public TIntermTyped
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
: TIntermTyped(type), mUnionArrayPointer(unionPointer)
{
ASSERT(unionPointer);
}
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
......@@ -346,6 +347,7 @@ class TIntermConstantUnion : public TIntermTyped
void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
{
ASSERT(safeConstantUnion);
// Previous union pointer freed on pool deallocation.
mUnionArrayPointer = safeConstantUnion;
}
......@@ -357,12 +359,12 @@ class TIntermConstantUnion : public TIntermTyped
TConstantUnion *foldBinary(TOperator op,
TIntermConstantUnion *rightNode,
TDiagnostics *diagnostics);
TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
TConstantUnion *foldUnaryNonComponentWise(TOperator op);
TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
TInfoSink &infoSink);
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics);
protected:
// Same data may be shared between multiple constant unions, so it can't be modified.
......@@ -370,7 +372,9 @@ class TIntermConstantUnion : public TIntermTyped
private:
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!
};
......@@ -468,6 +472,11 @@ class TIntermUnary : public TIntermOperator
mOperand(NULL),
mUseEmulatedFunction(false) {}
TIntermUnary(TOperator op, TIntermTyped *operand)
: TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
{
}
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
void traverse(TIntermTraverser *it) override;
......@@ -479,7 +488,7 @@ class TIntermUnary : public TIntermOperator
void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; }
void promote(const TType *funcReturnType);
TIntermTyped *fold(TInfoSink &infoSink);
TIntermTyped *fold(TDiagnostics *diagnostics);
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
......@@ -532,7 +541,7 @@ class TIntermAggregate : public TIntermOperator
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects
bool hasSideEffects() const override { return true; }
TIntermTyped *fold(TInfoSink &infoSink);
TIntermTyped *fold(TDiagnostics *diagnostics);
TIntermSequence *getSequence() { return &mSequence; }
const TIntermSequence *getSequence() const { return &mSequence; }
......
......@@ -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
// does lots of error checking and fixing. Especially for establishing
// a function call's operation on it's set of parameters. Sequences
......@@ -388,7 +365,7 @@ TIntermBranch* TIntermediate::addBranch(
// This is to be executed once the final root is put on top by the parsing
// process.
//
TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root)
{
if (root == nullptr)
return nullptr;
......@@ -411,7 +388,8 @@ TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
return aggRoot;
}
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics)
{
switch (aggregate->getOp())
{
......@@ -438,12 +416,12 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
case EOpFaceForward:
case EOpReflect:
case EOpRefract:
return aggregate->fold(mInfoSink);
return aggregate->fold(diagnostics);
default:
// TODO: Add support for folding array constructors
if (aggregate->isConstructor() && !aggregate->isArray())
{
return aggregate->fold(mInfoSink);
return aggregate->fold(diagnostics);
}
// Constant folding not supported for the built-in.
return nullptr;
......
......@@ -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
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TIntermediate(TInfoSink &i)
: mInfoSink(i) { }
TIntermediate() {}
TIntermSymbol *addSymbol(
int id, const TString &, const TType &, const TSourceLoc &);
......@@ -56,16 +54,14 @@ class TIntermediate
TIntermBranch *addBranch(TOperator, const TSourceLoc &);
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
TIntermAggregate *postProcess(TIntermNode *root);
static TIntermAggregate *PostProcess(TIntermNode *root);
static void outputTree(TIntermNode *, TInfoSinkBase &);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
private:
void operator=(TIntermediate &); // prevent assignments
TInfoSink & mInfoSink;
};
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_
......@@ -2376,7 +2376,7 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
constructor->setType(type);
TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor);
TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
if (constConstructor)
{
return constConstructor;
......@@ -3425,7 +3425,15 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op,
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)
......@@ -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
// if it is not const-qualified.
TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
TIntermTyped *foldedNode =
intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics);
if (foldedNode)
{
callNode = foldedNode;
......
......@@ -31,14 +31,13 @@ class TParseContext : angle::NonCopyable
public:
TParseContext(TSymbolTable &symt,
TExtensionBehavior &ext,
TIntermediate &interm,
sh::GLenum type,
ShShaderSpec spec,
int options,
bool checksPrecErrors,
TInfoSink &is,
const ShBuiltInResources &resources)
: intermediate(interm),
: intermediate(),
symbolTable(symt),
mDeferredSingleDeclarationErrorCheck(false),
mShaderType(type),
......@@ -367,7 +366,7 @@ class TParseContext : angle::NonCopyable
TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line);
// 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
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