Commit 274f0709 by Arun Patole Committed by Olli Etuaho

Add constant folding support for min,max and clamp

This change adds necessary mechanism to support constant folding of built-ins that take more than one parameter and also adds constant folding support for min, max and clamp built-ins. BUG=angleproject:913 TESTS=dEQP tests (126 tests started passing with this change) dEQP-GLES3.functional.shaders.constant_expressions.builtin_functions.common.min_* dEQP-GLES3.functional.shaders.constant_expressions.builtin_functions.common.max_* dEQP-GLES3.functional.shaders.constant_expressions.builtin_functions.common.clamp_* Change-Id: Iccc9bf503a536f2e3c144627e64572f2f95db9db Reviewed-on: https://chromium-review.googlesource.com/271251Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 8befcff5
......@@ -13,7 +13,9 @@
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include "common/mathutil.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
......@@ -130,6 +132,15 @@ bool CompareStructure(const TType &leftNodeType,
return true;
}
TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
{
TConstantUnion *constUnion = new TConstantUnion[size];
for (unsigned int i = 0; i < size; ++i)
constUnion[i] = constant;
return constUnion;
}
} // namespace anonymous
......@@ -702,21 +713,13 @@ TIntermTyped *TIntermConstantUnion::fold(
// for a case like float f = vec4(2, 3, 4, 5) + 1.2;
if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
{
rightUnionArray = new TConstantUnion[objectSize];
for (size_t i = 0; i < objectSize; ++i)
{
rightUnionArray[i] = *rightNode->getUnionArrayPointer();
}
rightUnionArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
returnType = getType();
}
else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
{
// for a case like float f = 1.2 + vec4(2, 3, 4, 5);
unionArray = new TConstantUnion[rightNode->getType().getObjectSize()];
for (size_t i = 0; i < rightNode->getType().getObjectSize(); ++i)
{
unionArray[i] = *getUnionArrayPointer();
}
unionArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
returnType = rightNode->getType();
objectSize = rightNode->getType().getObjectSize();
}
......@@ -1490,6 +1493,176 @@ bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, F
}
// static
TIntermTyped *TIntermConstantUnion::FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate)
{
TIntermSequence *sequence = aggregate->getSequence();
unsigned int paramsCount = sequence->size();
std::vector<TConstantUnion *> unionArrays(paramsCount);
std::vector<size_t> objectSizes(paramsCount);
TType *maxSizeType = nullptr;
TBasicType basicType = EbtVoid;
TSourceLoc loc;
for (unsigned int i = 0; i < paramsCount; i++)
{
TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
// Make sure that all params are constant before actual constant folding.
if (!paramConstant)
return nullptr;
if (i == 0)
{
basicType = paramConstant->getType().getBasicType();
loc = paramConstant->getLine();
}
unionArrays[i] = paramConstant->getUnionArrayPointer();
objectSizes[i] = paramConstant->getType().getObjectSize();
if (maxSizeType == nullptr || (objectSizes[i] >= maxSizeType->getObjectSize()))
maxSizeType = paramConstant->getTypePointer();
}
size_t maxObjectSize = maxSizeType->getObjectSize();
for (unsigned int i = 0; i < paramsCount; i++)
if (objectSizes[i] != maxObjectSize)
unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
TConstantUnion *tempConstArray = nullptr;
TIntermConstantUnion *tempNode = nullptr;
TType returnType = *maxSizeType;
if (paramsCount == 2)
{
//
// Binary built-in
//
switch (op)
{
case EOpMin:
{
tempConstArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
case EbtFloat:
tempConstArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
break;
case EbtInt:
tempConstArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
break;
case EbtUInt:
tempConstArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
break;
default:
UNREACHABLE();
break;
}
}
}
break;
case EOpMax:
{
tempConstArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
case EbtFloat:
tempConstArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
break;
case EbtInt:
tempConstArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
break;
case EbtUInt:
tempConstArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
break;
default:
UNREACHABLE();
break;
}
}
}
break;
default:
UNREACHABLE();
// TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
return nullptr;
}
}
else if (paramsCount == 3)
{
//
// Ternary built-in
//
switch (op)
{
case EOpClamp:
{
tempConstArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
case EbtFloat:
{
float x = unionArrays[0][i].getFConst();
float min = unionArrays[1][i].getFConst();
float max = unionArrays[2][i].getFConst();
// Results are undefined if min > max.
if (min > max)
tempConstArray[i].setFConst(0.0f);
else
tempConstArray[i].setFConst(gl::clamp(x, min, max));
}
break;
case EbtInt:
{
int x = unionArrays[0][i].getIConst();
int min = unionArrays[1][i].getIConst();
int max = unionArrays[2][i].getIConst();
// Results are undefined if min > max.
if (min > max)
tempConstArray[i].setIConst(0);
else
tempConstArray[i].setIConst(gl::clamp(x, min, max));
}
break;
case EbtUInt:
{
unsigned int x = unionArrays[0][i].getUConst();
unsigned int min = unionArrays[1][i].getUConst();
unsigned int max = unionArrays[2][i].getUConst();
// Results are undefined if min > max.
if (min > max)
tempConstArray[i].setUConst(0u);
else
tempConstArray[i].setUConst(gl::clamp(x, min, max));
}
break;
default:
UNREACHABLE();
break;
}
}
}
break;
default:
UNREACHABLE();
// TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
return nullptr;
}
}
if (tempConstArray)
{
tempNode = new TIntermConstantUnion(tempConstArray, returnType);
tempNode->setLine(loc);
}
return tempNode;
}
// static
TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
{
if (hashFunction == NULL || name.empty())
......
......@@ -301,6 +301,8 @@ class TIntermConstantUnion : public TIntermTyped
TIntermTyped *fold(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink);
static TIntermTyped *FoldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate);
protected:
TConstantUnion *mUnionArrayPointer;
......
......@@ -441,3 +441,19 @@ bool TIntermediate::postProcess(TIntermNode *root)
return true;
}
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate)
{
switch (op)
{
case EOpMin:
case EOpMax:
case EOpClamp:
return TIntermConstantUnion::FoldAggregateBuiltIn(op, aggregate);
default:
// Constant folding not supported for the built-in.
return nullptr;
}
return nullptr;
}
......@@ -63,6 +63,8 @@ class TIntermediate
static void outputTree(TIntermNode *, TInfoSinkBase &);
TIntermTyped *foldAggregateBuiltIn(TOperator op, TIntermAggregate *aggregate);
private:
void operator=(TIntermediate &); // prevent assignments
......
......@@ -3323,6 +3323,15 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
// Some built-in functions have out parameters too.
functionCallLValueErrorCheck(fnCandidate, aggregate);
// See if we can constant fold a built-in.
TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(op, aggregate);
if (foldedNode)
{
foldedNode->setType(callNode->getType());
foldedNode->getTypePointer()->setQualifier(EvqConst);
callNode = foldedNode;
}
}
}
else
......
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