diff options
author | Tobias Hunger <tobias.hunger@qt.io> | 2019-04-16 16:32:08 +0200 |
---|---|---|
committer | Tobias Hunger <tobias.hunger@qt.io> | 2019-04-16 16:32:08 +0200 |
commit | 6630937e63ae5797487b86743a7733c8ae5cc42c (patch) | |
tree | 3d53dacf6430f9099e1fb20835881205de674961 /src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp | |
parent | 37ed6dae00640f9cc980ffda05347c12a7eb5d7e (diff) | |
parent | c7af193d2e49e9f10b86262e63d8d13abf72b5cf (diff) |
Merge commit 'dev' into 'wip/cmake-merge'
Change-Id: I176c40d031be26a1dd1cf08843e448a660598783
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp | 393 |
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 ¶m = 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 |