Commit 7c3848e5 by Olli Etuaho

Allow constant folding some non-constant expressions

This requires removing the assumption that constant folding implies constness in the constant expression sense from various places in the code. This particularly benefits ternary operators, which can now be simplified if just the condition is a compile-time constant. In the future, the groundwork that is laid here could be used to implement more aggressive constant folding of user-defined functions for example. TEST=angle_unittests BUG=angleproject:851 Change-Id: I0eede806570d56746c3dad1e01aa89a91d66013d Reviewed-on: https://chromium-review.googlesource.com/310750Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org>
parent 0ed0d8ac
...@@ -188,14 +188,16 @@ float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, ...@@ -188,14 +188,16 @@ float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2,
return result; return result;
} }
TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode) TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
const TIntermTyped *originalNode,
TQualifier qualifier)
{ {
if (constArray == nullptr) if (constArray == nullptr)
{ {
return nullptr; return nullptr;
} }
TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType()); TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
folded->getTypePointer()->setQualifier(EvqConst); folded->getTypePointer()->setQualifier(qualifier);
folded->setLine(originalNode->getLine()); folded->setLine(originalNode->getLine());
return folded; return folded;
} }
...@@ -893,7 +895,14 @@ TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink) ...@@ -893,7 +895,14 @@ TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
return nullptr; return nullptr;
} }
TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink); TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
return CreateFoldedNode(constArray, this);
// Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = EvqConst;
if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
{
resultQualifier = EvqTemporary;
}
return CreateFoldedNode(constArray, this, resultQualifier);
} }
TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
...@@ -925,7 +934,10 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) ...@@ -925,7 +934,10 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink); constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
break; break;
} }
return CreateFoldedNode(constArray, this);
// Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
return CreateFoldedNode(constArray, this, resultQualifier);
} }
TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
...@@ -939,7 +951,10 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) ...@@ -939,7 +951,10 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
} }
} }
TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink); TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
return CreateFoldedNode(constArray, this);
// Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
return CreateFoldedNode(constArray, this, resultQualifier);
} }
// //
......
...@@ -294,6 +294,12 @@ class TIntermRaw : public TIntermTyped ...@@ -294,6 +294,12 @@ class TIntermRaw : public TIntermTyped
TString mRawText; TString mRawText;
}; };
// Constant folded node.
// Note that nodes may be constant folded and not be constant expressions with the EvqConst
// qualifier. This happens for example when the following expression is processed:
// "true ? 1.0 : non_constant"
// Other nodes than TIntermConstantUnion may also be constant expressions.
//
class TIntermConstantUnion : public TIntermTyped class TIntermConstantUnion : public TIntermTyped
{ {
public: public:
......
...@@ -260,7 +260,7 @@ TIntermNode *TIntermediate::addSelection( ...@@ -260,7 +260,7 @@ TIntermNode *TIntermediate::addSelection(
// test now. // test now.
// //
if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) if (cond->getAsConstantUnion())
{ {
if (cond->getAsConstantUnion()->getBConst(0) == true) if (cond->getAsConstantUnion()->getBConst(0) == true)
{ {
...@@ -325,20 +325,21 @@ TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *true ...@@ -325,20 +325,21 @@ TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *true
{ {
resultQualifier = EvqConst; resultQualifier = EvqConst;
} }
// Right now it's safe to fold ternary operators only when all operands // Note that the node resulting from here can be a constant union without being qualified as
// are constant. If only the condition is constant, it's theoretically // constant.
// possible to fold the ternary operator, but that requires making sure if (cond->getAsConstantUnion())
// that the node returned from here won't be treated as a constant
// expression in case the node that gets eliminated was not a constant
// expression.
if (resultQualifier == EvqConst && cond->getAsConstantUnion() &&
trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion())
{ {
if (cond->getAsConstantUnion()->getBConst(0)) if (cond->getAsConstantUnion()->getBConst(0))
{
trueBlock->getTypePointer()->setQualifier(resultQualifier);
return trueBlock; return trueBlock;
}
else else
{
falseBlock->getTypePointer()->setQualifier(resultQualifier);
return falseBlock; return falseBlock;
} }
}
// //
// Make a selection node. // Make a selection node.
......
...@@ -77,6 +77,13 @@ class TParseContext : angle::NonCopyable ...@@ -77,6 +77,13 @@ class TParseContext : angle::NonCopyable
void warning(const TSourceLoc &loc, const char *reason, const char *token, void warning(const TSourceLoc &loc, const char *reason, const char *token,
const char *extraInfo=""); const char *extraInfo="");
// If isError is false, a warning will be reported instead.
void outOfRangeError(bool isError,
const TSourceLoc &loc,
const char *reason,
const char *token,
const char *extraInfo = "");
void recover(); void recover();
TIntermNode *getTreeRoot() const { return mTreeRoot; } TIntermNode *getTreeRoot() const { return mTreeRoot; }
void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; } void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
...@@ -158,7 +165,7 @@ class TParseContext : angle::NonCopyable ...@@ -158,7 +165,7 @@ class TParseContext : angle::NonCopyable
void handlePragmaDirective(const TSourceLoc &loc, const char *name, const char *value, bool stdgl); void handlePragmaDirective(const TSourceLoc &loc, const char *name, const char *value, bool stdgl);
bool containsSampler(const TType &type); bool containsSampler(const TType &type);
bool areAllChildConst(TIntermAggregate *aggrNode); bool areAllChildrenConstantFolded(TIntermAggregate *aggrNode);
const TFunction* findFunction( const TFunction* findFunction(
const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0); const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line, bool executeInitializer(const TSourceLoc &line,
...@@ -241,9 +248,18 @@ class TParseContext : angle::NonCopyable ...@@ -241,9 +248,18 @@ class TParseContext : angle::NonCopyable
TFunction *fnCall, TFunction *fnCall,
const TSourceLoc &line); const TSourceLoc &line);
TIntermTyped *foldConstConstructor(TIntermAggregate *aggrNode, const TType &type); TIntermTyped *foldConstConstructor(TIntermAggregate *aggrNode, const TType &type);
TIntermTyped *addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&); TIntermTyped *addConstVectorNode(TVectorFields &fields,
TIntermTyped *addConstMatrixNode(int, TIntermTyped*, const TSourceLoc&); TIntermConstantUnion *node,
TIntermTyped *addConstArrayNode(int index, TIntermTyped *node, const TSourceLoc &line); const TSourceLoc &line,
bool outOfRangeIndexIsError);
TIntermTyped *addConstMatrixNode(int index,
TIntermConstantUnion *node,
const TSourceLoc &line,
bool outOfRangeIndexIsError);
TIntermTyped *addConstArrayNode(int index,
TIntermConstantUnion *node,
const TSourceLoc &line,
bool outOfRangeIndexIsError);
TIntermTyped *addConstStruct( TIntermTyped *addConstStruct(
const TString &identifier, TIntermTyped *node, const TSourceLoc& line); const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression, TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
......
...@@ -1067,3 +1067,21 @@ TEST_F(MalformedShaderTest, TernaryOperatorAppliedToArrayConstructorIsConst) ...@@ -1067,3 +1067,21 @@ TEST_F(MalformedShaderTest, TernaryOperatorAppliedToArrayConstructorIsConst)
FAIL() << "Shader compilation failed, expecting success " << mInfoLog; FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
} }
} }
// Test that a ternary operator with one unevaluated non-constant operand is not a constant
// expression.
TEST_F(MalformedShaderTest, TernaryOperatorNonConstantOperand)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float u;\n"
"void main()\n"
"{\n"
" const float f = true ? 1.0 : u;\n"
" gl_FragColor = vec4(f);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
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