summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp393
1 files changed, 170 insertions, 223 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
index ba8cdd0aa8..941f79ae51 100644
--- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
@@ -5,14 +5,29 @@
//
#include "compiler/translator/ValidateLimitations.h"
-#include "compiler/translator/InfoSink.h"
-#include "compiler/translator/InitializeParseContext.h"
-#include "compiler/translator/ParseContext.h"
+
#include "angle_gl.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/ParseContext.h"
+
+namespace sh
+{
namespace
{
+int GetLoopSymbolId(TIntermLoop *loop)
+{
+ // Here we assume all the operations are valid, because the loop node is
+ // already validated before this call.
+ TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
+ TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+
+ return symbol->getId();
+}
+
// Traverses a node to check if it represents a constant index expression.
// Definition:
// constant-index-expressions are a superset of constant-expressions.
@@ -25,10 +40,8 @@ namespace
class ValidateConstIndexExpr : public TIntermTraverser
{
public:
- ValidateConstIndexExpr(TLoopStack& stack)
- : TIntermTraverser(true, false, false),
- mValid(true),
- mLoopStack(stack)
+ ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
+ : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
{
}
@@ -41,93 +54,93 @@ class ValidateConstIndexExpr : public TIntermTraverser
// constant index expression.
if (mValid)
{
- mValid = (symbol->getQualifier() == EvqConst) ||
- (mLoopStack.findLoop(symbol));
+ bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
+ symbol->getId()) != mLoopSymbolIds.end();
+ mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
}
}
private:
bool mValid;
- TLoopStack& mLoopStack;
+ const std::vector<int> mLoopSymbolIds;
};
-} // namespace anonymous
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitationsTraverser : public TLValueTrackingTraverser
+{
+ public:
+ ValidateLimitationsTraverser(sh::GLenum shaderType,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ TDiagnostics *diagnostics);
-ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
- : TIntermTraverser(true, false, false),
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitBinary(Visit, TIntermBinary *) override;
+ bool visitLoop(Visit, TIntermLoop *) override;
+
+ private:
+ void error(TSourceLoc loc, const char *reason, const char *token);
+
+ bool withinLoopBody() const;
+ bool isLoopIndex(TIntermSymbol *symbol);
+ bool validateLoopType(TIntermLoop *node);
+
+ bool validateForLoopHeader(TIntermLoop *node);
+ // If valid, return the index symbol id; Otherwise, return -1.
+ int validateForLoopInit(TIntermLoop *node);
+ bool validateForLoopCond(TIntermLoop *node, int indexSymbolId);
+ bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId);
+
+ // Returns true if indexing does not exceed the minimum functionality
+ // mandated in GLSL 1.0 spec, Appendix A, Section 5.
+ bool isConstExpr(TIntermNode *node);
+ bool isConstIndexExpr(TIntermNode *node);
+ bool validateIndexing(TIntermBinary *node);
+
+ sh::GLenum mShaderType;
+ TDiagnostics *mDiagnostics;
+ std::vector<int> mLoopSymbolIds;
+};
+
+ValidateLimitationsTraverser::ValidateLimitationsTraverser(sh::GLenum shaderType,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ TDiagnostics *diagnostics)
+ : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
mShaderType(shaderType),
- mSink(sink),
- mNumErrors(0),
- mValidateIndexing(true),
- mValidateInnerLoops(true)
+ mDiagnostics(diagnostics)
{
+ ASSERT(diagnostics);
}
-// static
-bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
+void ValidateLimitationsTraverser::visitSymbol(TIntermSymbol *node)
{
- // The shader type doesn't matter in this case.
- ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
- validate.mValidateIndexing = false;
- validate.mValidateInnerLoops = false;
- if (!validate.validateLoopType(loop))
- return false;
- if (!validate.validateForLoopHeader(loop))
- return false;
- TIntermNode *body = loop->getBody();
- if (body != nullptr)
+ if (isLoopIndex(node) && isLValueRequiredHere())
{
- validate.mLoopStack.push(loop);
- body->traverse(&validate);
- validate.mLoopStack.pop();
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ node->getSymbol().c_str());
}
- return (validate.mNumErrors == 0);
}
-bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
+bool ValidateLimitationsTraverser::visitBinary(Visit, TIntermBinary *node)
{
- // Check if loop index is modified in the loop body.
- validateOperation(node, node->getLeft());
-
// Check indexing.
switch (node->getOp())
{
- case EOpIndexDirect:
- case EOpIndexIndirect:
- if (mValidateIndexing)
- validateIndexing(node);
- break;
- default:
- break;
- }
- return true;
-}
-
-bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
-{
- // Check if loop index is modified in the loop body.
- validateOperation(node, node->getOperand());
-
- return true;
-}
-
-bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
-{
- switch (node->getOp()) {
- case EOpFunctionCall:
- validateFunctionCall(node);
- break;
- default:
- break;
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ validateIndexing(node);
+ break;
+ default:
+ break;
}
return true;
}
-bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
+bool ValidateLimitationsTraverser::visitLoop(Visit, TIntermLoop *node)
{
- if (!mValidateInnerLoops)
- return true;
-
if (!validateLoopType(node))
return false;
@@ -135,53 +148,45 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
return false;
TIntermNode *body = node->getBody();
- if (body != NULL)
+ if (body != nullptr)
{
- mLoopStack.push(node);
+ mLoopSymbolIds.push_back(GetLoopSymbolId(node));
body->traverse(this);
- mLoopStack.pop();
+ mLoopSymbolIds.pop_back();
}
// The loop is fully processed - no need to visit children.
return false;
}
-void ValidateLimitations::error(TSourceLoc loc,
- const char *reason, const char *token)
+void ValidateLimitationsTraverser::error(TSourceLoc loc, const char *reason, const char *token)
{
- if (mSink)
- {
- mSink->prefix(EPrefixError);
- mSink->location(loc);
- (*mSink) << "'" << token << "' : " << reason << "\n";
- }
- ++mNumErrors;
+ mDiagnostics->error(loc, reason, token);
}
-bool ValidateLimitations::withinLoopBody() const
+bool ValidateLimitationsTraverser::withinLoopBody() const
{
- return !mLoopStack.empty();
+ return !mLoopSymbolIds.empty();
}
-bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
+bool ValidateLimitationsTraverser::isLoopIndex(TIntermSymbol *symbol)
{
- return mLoopStack.findLoop(symbol) != NULL;
+ return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
+ mLoopSymbolIds.end();
}
-bool ValidateLimitations::validateLoopType(TIntermLoop *node)
+bool ValidateLimitationsTraverser::validateLoopType(TIntermLoop *node)
{
TLoopType type = node->getType();
if (type == ELoopFor)
return true;
// Reject while and do-while loops.
- error(node->getLine(),
- "This type of loop is not allowed",
- type == ELoopWhile ? "while" : "do");
+ error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do");
return false;
}
-bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
+bool ValidateLimitationsTraverser::validateForLoopHeader(TIntermLoop *node)
{
ASSERT(node->getType() == ELoopFor);
@@ -200,10 +205,10 @@ bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
return true;
}
-int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
+int ValidateLimitationsTraverser::validateForLoopInit(TIntermLoop *node)
{
TIntermNode *init = node->getInit();
- if (init == NULL)
+ if (init == nullptr)
{
error(node->getLine(), "Missing init declaration", "for");
return -1;
@@ -213,8 +218,8 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
// init-declaration has the form:
// type-specifier identifier = constant-expression
//
- TIntermAggregate *decl = init->getAsAggregate();
- if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
+ TIntermDeclaration *decl = init->getAsDeclarationNode();
+ if (decl == nullptr)
{
error(init->getLine(), "Invalid init declaration", "for");
return -1;
@@ -227,29 +232,28 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
return -1;
}
TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
- if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
+ if ((declInit == nullptr) || (declInit->getOp() != EOpInitialize))
{
error(decl->getLine(), "Invalid init declaration", "for");
return -1;
}
TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
- if (symbol == NULL)
+ if (symbol == nullptr)
{
error(declInit->getLine(), "Invalid init declaration", "for");
return -1;
}
// The loop index has type int or float.
TBasicType type = symbol->getBasicType();
- if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
- error(symbol->getLine(),
- "Invalid type for loop index", getBasicString(type));
+ if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat))
+ {
+ error(symbol->getLine(), "Invalid type for loop index", getBasicString(type));
return -1;
}
// The loop index is initialized with constant expression.
if (!isConstExpr(declInit->getRight()))
{
- error(declInit->getLine(),
- "Loop index cannot be initialized with non-constant expression",
+ error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression",
symbol->getSymbol().c_str());
return -1;
}
@@ -257,11 +261,10 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
return symbol->getId();
}
-bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
- int indexSymbolId)
+bool ValidateLimitationsTraverser::validateForLoopCond(TIntermLoop *node, int indexSymbolId)
{
TIntermNode *cond = node->getCondition();
- if (cond == NULL)
+ if (cond == nullptr)
{
error(node->getLine(), "Missing condition", "for");
return false;
@@ -271,45 +274,42 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
// loop_index relational_operator constant_expression
//
TIntermBinary *binOp = cond->getAsBinaryNode();
- if (binOp == NULL)
+ if (binOp == nullptr)
{
error(node->getLine(), "Invalid condition", "for");
return false;
}
// Loop index should be to the left of relational operator.
TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
- if (symbol == NULL)
+ if (symbol == nullptr)
{
error(binOp->getLine(), "Invalid condition", "for");
return false;
}
if (symbol->getId() != indexSymbolId)
{
- error(symbol->getLine(),
- "Expected loop index", symbol->getSymbol().c_str());
+ error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
return false;
}
// Relational operator is one of: > >= < <= == or !=.
switch (binOp->getOp())
{
- case EOpEqual:
- case EOpNotEqual:
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- break;
- default:
- error(binOp->getLine(),
- "Invalid relational operator",
- GetOperatorString(binOp->getOp()));
- break;
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ default:
+ error(binOp->getLine(), "Invalid relational operator",
+ GetOperatorString(binOp->getOp()));
+ break;
}
// Loop index must be compared with a constant.
if (!isConstExpr(binOp->getRight()))
{
- error(binOp->getLine(),
- "Loop index cannot be compared with non-constant expression",
+ error(binOp->getLine(), "Loop index cannot be compared with non-constant expression",
symbol->getSymbol().c_str());
return false;
}
@@ -317,11 +317,10 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
return true;
}
-bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
- int indexSymbolId)
+bool ValidateLimitationsTraverser::validateForLoopExpr(TIntermLoop *node, int indexSymbolId)
{
TIntermNode *expr = node->getExpression();
- if (expr == NULL)
+ if (expr == nullptr)
{
error(node->getLine(), "Missing expression", "for");
return false;
@@ -336,60 +335,58 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
// --loop_index
// The last two forms are not specified in the spec, but I am assuming
// its an oversight.
- TIntermUnary *unOp = expr->getAsUnaryNode();
- TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
+ TIntermUnary *unOp = expr->getAsUnaryNode();
+ TIntermBinary *binOp = unOp ? nullptr : expr->getAsBinaryNode();
- TOperator op = EOpNull;
- TIntermSymbol *symbol = NULL;
- if (unOp != NULL)
+ TOperator op = EOpNull;
+ TIntermSymbol *symbol = nullptr;
+ if (unOp != nullptr)
{
- op = unOp->getOp();
+ op = unOp->getOp();
symbol = unOp->getOperand()->getAsSymbolNode();
}
- else if (binOp != NULL)
+ else if (binOp != nullptr)
{
- op = binOp->getOp();
+ op = binOp->getOp();
symbol = binOp->getLeft()->getAsSymbolNode();
}
// The operand must be loop index.
- if (symbol == NULL)
+ if (symbol == nullptr)
{
error(expr->getLine(), "Invalid expression", "for");
return false;
}
if (symbol->getId() != indexSymbolId)
{
- error(symbol->getLine(),
- "Expected loop index", symbol->getSymbol().c_str());
+ error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
return false;
}
// The operator is one of: ++ -- += -=.
switch (op)
{
- case EOpPostIncrement:
- case EOpPostDecrement:
- case EOpPreIncrement:
- case EOpPreDecrement:
- ASSERT((unOp != NULL) && (binOp == NULL));
- break;
- case EOpAddAssign:
- case EOpSubAssign:
- ASSERT((unOp == NULL) && (binOp != NULL));
- break;
- default:
- error(expr->getLine(), "Invalid operator", GetOperatorString(op));
- return false;
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != nullptr) && (binOp == nullptr));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == nullptr) && (binOp != nullptr));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", GetOperatorString(op));
+ return false;
}
// Loop index must be incremented/decremented with a constant.
- if (binOp != NULL)
+ if (binOp != nullptr)
{
if (!isConstExpr(binOp->getRight()))
{
- error(binOp->getLine(),
- "Loop index cannot be modified by non-constant expression",
+ error(binOp->getLine(), "Loop index cannot be modified by non-constant expression",
symbol->getSymbol().c_str());
return false;
}
@@ -398,95 +395,31 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
return true;
}
-bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
-{
- ASSERT(node->getOp() == EOpFunctionCall);
-
- // If not within loop body, there is nothing to check.
- if (!withinLoopBody())
- return true;
-
- // List of param indices for which loop indices are used as argument.
- typedef std::vector<size_t> ParamIndex;
- ParamIndex pIndex;
- TIntermSequence *params = node->getSequence();
- for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
- {
- TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
- if (symbol && isLoopIndex(symbol))
- pIndex.push_back(i);
- }
- // If none of the loop indices are used as arguments,
- // there is nothing to check.
- if (pIndex.empty())
- return true;
-
- bool valid = true;
- TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
- TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->getShaderVersion());
- ASSERT(symbol && symbol->isFunction());
- TFunction *function = static_cast<TFunction *>(symbol);
- for (ParamIndex::const_iterator i = pIndex.begin();
- i != pIndex.end(); ++i)
- {
- const TConstParameter &param = function->getParam(*i);
- TQualifier qual = param.type->getQualifier();
- if ((qual == EvqOut) || (qual == EvqInOut))
- {
- error((*params)[*i]->getLine(),
- "Loop index cannot be used as argument to a function out or inout parameter",
- (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
- valid = false;
- }
- }
-
- return valid;
-}
-
-bool ValidateLimitations::validateOperation(TIntermOperator *node,
- TIntermNode* operand)
-{
- // Check if loop index is modified in the loop body.
- if (!withinLoopBody() || !node->isAssignment())
- return true;
-
- TIntermSymbol *symbol = operand->getAsSymbolNode();
- if (symbol && isLoopIndex(symbol))
- {
- error(node->getLine(),
- "Loop index cannot be statically assigned to within the body of the loop",
- symbol->getSymbol().c_str());
- }
- return true;
-}
-
-bool ValidateLimitations::isConstExpr(TIntermNode *node)
+bool ValidateLimitationsTraverser::isConstExpr(TIntermNode *node)
{
ASSERT(node != nullptr);
return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
}
-bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
+bool ValidateLimitationsTraverser::isConstIndexExpr(TIntermNode *node)
{
- ASSERT(node != NULL);
+ ASSERT(node != nullptr);
- ValidateConstIndexExpr validate(mLoopStack);
+ ValidateConstIndexExpr validate(mLoopSymbolIds);
node->traverse(&validate);
return validate.isValid();
}
-bool ValidateLimitations::validateIndexing(TIntermBinary *node)
+bool ValidateLimitationsTraverser::validateIndexing(TIntermBinary *node)
{
- ASSERT((node->getOp() == EOpIndexDirect) ||
- (node->getOp() == EOpIndexIndirect));
+ ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect));
- bool valid = true;
+ bool valid = true;
TIntermTyped *index = node->getRight();
// The index expession must be a constant-index-expression unless
// the operand is a uniform in a vertex shader.
TIntermTyped *operand = node->getLeft();
- bool skip = (mShaderType == GL_VERTEX_SHADER) &&
- (operand->getQualifier() == EvqUniform);
+ bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform);
if (!skip && !isConstIndexExpr(index))
{
error(index->getLine(), "Index expression must be constant", "[]");
@@ -495,3 +428,17 @@ bool ValidateLimitations::validateIndexing(TIntermBinary *node)
return valid;
}
+} // namespace anonymous
+
+bool ValidateLimitations(TIntermNode *root,
+ GLenum shaderType,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ TDiagnostics *diagnostics)
+{
+ ValidateLimitationsTraverser validate(shaderType, symbolTable, shaderVersion, diagnostics);
+ root->traverse(&validate);
+ return diagnostics->numErrors() == 0;
+}
+
+} // namespace sh