LCOV - app.info - gfx/angle/src/compiler/ValidateLimitations.cpp

LCOV - code coverage report
| Current view: | directory - gfx/angle/src/compiler - ValidateLimitations.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 229 | 0 | 0.0 %
| Date: | 2012-06-02 | Functions: | 24 | 0 | 0.0 %

           1                 : //
           2                 : // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
           3                 : // Use of this source code is governed by a BSD-style license that can be
           4                 : // found in the LICENSE file.
           5                 : //
           6                 :
           7                 : #include "compiler/ValidateLimitations.h"
           8                 : #include "compiler/InfoSink.h"
           9                 : #include "compiler/ParseHelper.h"
          10                 :
          11                 : namespace {
          12               0 : bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) {
          13               0 :     for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) {
          14               0 :         if (i->index.id == symbol->getId())
          15               0 :             return true;
          16                 :     }
          17               0 :     return false;
          18                 : }
          19                 :
          20               0 : void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) {
          21               0 :     for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) {
          22               0 :         if (i->index.id == symbol->getId()) {
          23               0 :             ASSERT(i->loop != NULL);
          24               0 :             i->loop->setUnrollFlag(true);
          25                 :             return;
          26                 :         }
          27                 :     }
          28               0 :     UNREACHABLE();
          29                 : }
          30                 :
          31                 : // Traverses a node to check if it represents a constant index expression.
          32                 : // Definition:
          33                 : // constant-index-expressions are a superset of constant-expressions.
          34                 : // Constant-index-expressions can include loop indices as defined in
          35                 : // GLSL ES 1.0 spec, Appendix A, section 4.
          36                 : // The following are constant-index-expressions:
          37                 : // - Constant expressions
          38                 : // - Loop indices as defined in section 4
          39                 : // - Expressions composed of both of the above
          40                 : class ValidateConstIndexExpr : public TIntermTraverser {
          41                 : public:
          42               0 :     ValidateConstIndexExpr(const TLoopStack& stack)
          43               0 :         : mValid(true), mLoopStack(stack) {}
          44                 :
          45                 :     // Returns true if the parsed node represents a constant index expression.
          46               0 :     bool isValid() const { return mValid; }
          47                 :
          48               0 :     virtual void visitSymbol(TIntermSymbol* symbol) {
          49                 :         // Only constants and loop indices are allowed in a
          50                 :         // constant index expression.
          51               0 :         if (mValid) {
          52               0 :             mValid = (symbol->getQualifier() == EvqConst) ||
          53               0 :                      IsLoopIndex(symbol, mLoopStack);
          54                 :         }
          55               0 :     }
          56                 :
          57                 : private:
          58                 :     bool mValid;
          59                 :     const TLoopStack& mLoopStack;
          60                 : };
          61                 :
          62                 : // Traverses a node to check if it uses a loop index.
          63                 : // If an int loop index is used in its body as a sampler array index,
          64                 : // mark the loop for unroll.
          65                 : class ValidateLoopIndexExpr : public TIntermTraverser {
          66                 : public:
          67                 :     ValidateLoopIndexExpr(TLoopStack& stack)
          68                 :         : mUsesFloatLoopIndex(false),
          69                 :           mUsesIntLoopIndex(false),
          70                 :           mLoopStack(stack) {}
          71                 :
          72                 :     bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; }
          73                 :     bool usesIntLoopIndex() const { return mUsesIntLoopIndex; }
          74                 :
          75               0 :     virtual void visitSymbol(TIntermSymbol* symbol) {
          76               0 :         if (IsLoopIndex(symbol, mLoopStack)) {
          77               0 :             switch (symbol->getBasicType()) {
          78                 :               case EbtFloat:
          79               0 :                 mUsesFloatLoopIndex = true;
          80               0 :                 break;
          81                 :               case EbtInt:
          82               0 :                 mUsesIntLoopIndex = true;
          83               0 :                 MarkLoopForUnroll(symbol, mLoopStack);
          84               0 :                 break;
          85                 :               default:
          86               0 :                 UNREACHABLE();
          87                 :             }
          88                 :         }
          89               0 :     }
          90                 :
          91                 : private:
          92                 :     bool mUsesFloatLoopIndex;
          93                 :     bool mUsesIntLoopIndex;
          94                 :     TLoopStack& mLoopStack;
          95                 : };
          96                 : }  // namespace
          97                 :
          98               0 : ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
          99                 :                                          TInfoSinkBase& sink)
         100                 :     : mShaderType(shaderType),
         101                 :       mSink(sink),
         102               0 :       mNumErrors(0)
         103                 : {
         104               0 : }
         105                 :
         106               0 : bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node)
         107                 : {
         108                 :     // Check if loop index is modified in the loop body.
         109               0 :     validateOperation(node, node->getLeft());
         110                 :
         111                 :     // Check indexing.
         112               0 :     switch (node->getOp()) {
         113                 :       case EOpIndexDirect:
         114               0 :         validateIndexing(node);
         115               0 :         break;
         116                 :       case EOpIndexIndirect:
         117                 : #if defined(__APPLE__)
         118                 :         // Loop unrolling is a work-around for a Mac Cg compiler bug where it
         119                 :         // crashes when a sampler array's index is also the loop index.
         120                 :         // Once Apple fixes this bug, we should remove the code in this CL.
         121                 :         // See http://codereview.appspot.com/4331048/.
         122                 :         if ((node->getLeft() != NULL) && (node->getRight() != NULL) &&
         123                 :             (node->getLeft()->getAsSymbolNode())) {
         124                 :             TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode();
         125                 :             if (IsSampler(symbol->getBasicType()) && symbol->isArray()) {
         126                 :                 ValidateLoopIndexExpr validate(mLoopStack);
         127                 :                 node->getRight()->traverse(&validate);
         128                 :                 if (validate.usesFloatLoopIndex()) {
         129                 :                     error(node->getLine(),
         130                 :                           "sampler array index is float loop index",
         131                 :                           "for");
         132                 :                 }
         133                 :             }
         134                 :         }
         135                 : #endif
         136               0 :         validateIndexing(node);
         137               0 :         break;
         138               0 :       default: break;
         139                 :     }
         140               0 :     return true;
         141                 : }
         142                 :
         143               0 : bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node)
         144                 : {
         145                 :     // Check if loop index is modified in the loop body.
         146               0 :     validateOperation(node, node->getOperand());
         147                 :
         148               0 :     return true;
         149                 : }
         150                 :
         151               0 : bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node)
         152                 : {
         153               0 :     switch (node->getOp()) {
         154                 :       case EOpFunctionCall:
         155               0 :         validateFunctionCall(node);
         156               0 :         break;
         157                 :       default:
         158               0 :         break;
         159                 :     }
         160               0 :     return true;
         161                 : }
         162                 :
         163               0 : bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node)
         164                 : {
         165               0 :     if (!validateLoopType(node))
         166               0 :         return false;
         167                 :
         168                 :     TLoopInfo info;
         169               0 :     memset(&info, 0, sizeof(TLoopInfo));
         170               0 :     info.loop = node;
         171               0 :     if (!validateForLoopHeader(node, &info))
         172               0 :         return false;
         173                 :
         174               0 :     TIntermNode* body = node->getBody();
         175               0 :     if (body != NULL) {
         176               0 :         mLoopStack.push_back(info);
         177               0 :         body->traverse(this);
         178               0 :         mLoopStack.pop_back();
         179                 :     }
         180                 :
         181                 :     // The loop is fully processed - no need to visit children.
         182               0 :     return false;
         183                 : }
         184                 :
         185               0 : void ValidateLimitations::error(TSourceLoc loc,
         186                 :                                 const char *reason, const char* token)
         187                 : {
         188               0 :     mSink.prefix(EPrefixError);
         189               0 :     mSink.location(loc);
         190               0 :     mSink << "'" << token << "' : " << reason << "\n";
         191               0 :     ++mNumErrors;
         192               0 : }
         193                 :
         194               0 : bool ValidateLimitations::withinLoopBody() const
         195                 : {
         196               0 :     return !mLoopStack.empty();
         197                 : }
         198                 :
         199               0 : bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const
         200                 : {
         201               0 :     return IsLoopIndex(symbol, mLoopStack);
         202                 : }
         203                 :
         204               0 : bool ValidateLimitations::validateLoopType(TIntermLoop* node) {
         205               0 :     TLoopType type = node->getType();
         206               0 :     if (type == ELoopFor)
         207               0 :         return true;
         208                 :
         209                 :     // Reject while and do-while loops.
         210                 :     error(node->getLine(),
         211                 :           "This type of loop is not allowed",
         212               0 :           type == ELoopWhile ? "while" : "do");
         213               0 :     return false;
         214                 : }
         215                 :
         216               0 : bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node,
         217                 :                                                 TLoopInfo* info)
         218                 : {
         219               0 :     ASSERT(node->getType() == ELoopFor);
         220                 :
         221                 :     //
         222                 :     // The for statement has the form:
         223                 :     //    for ( init-declaration ; condition ; expression ) statement
         224                 :     //
         225               0 :     if (!validateForLoopInit(node, info))
         226               0 :         return false;
         227               0 :     if (!validateForLoopCond(node, info))
         228               0 :         return false;
         229               0 :     if (!validateForLoopExpr(node, info))
         230               0 :         return false;
         231                 :
         232               0 :     return true;
         233                 : }
         234                 :
         235               0 : bool ValidateLimitations::validateForLoopInit(TIntermLoop* node,
         236                 :                                               TLoopInfo* info)
         237                 : {
         238               0 :     TIntermNode* init = node->getInit();
         239               0 :     if (init == NULL) {
         240               0 :         error(node->getLine(), "Missing init declaration", "for");
         241               0 :         return false;
         242                 :     }
         243                 :
         244                 :     //
         245                 :     // init-declaration has the form:
         246                 :     //     type-specifier identifier = constant-expression
         247                 :     //
         248               0 :     TIntermAggregate* decl = init->getAsAggregate();
         249               0 :     if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) {
         250               0 :         error(init->getLine(), "Invalid init declaration", "for");
         251               0 :         return false;
         252                 :     }
         253                 :     // To keep things simple do not allow declaration list.
         254               0 :     TIntermSequence& declSeq = decl->getSequence();
         255               0 :     if (declSeq.size() != 1) {
         256               0 :         error(decl->getLine(), "Invalid init declaration", "for");
         257               0 :         return false;
         258                 :     }
         259               0 :     TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
         260               0 :     if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) {
         261               0 :         error(decl->getLine(), "Invalid init declaration", "for");
         262               0 :         return false;
         263                 :     }
         264               0 :     TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
         265               0 :     if (symbol == NULL) {
         266               0 :         error(declInit->getLine(), "Invalid init declaration", "for");
         267               0 :         return false;
         268                 :     }
         269                 :     // The loop index has type int or float.
         270               0 :     TBasicType type = symbol->getBasicType();
         271               0 :     if ((type != EbtInt) && (type != EbtFloat)) {
         272                 :         error(symbol->getLine(),
         273               0 :               "Invalid type for loop index", getBasicString(type));
         274               0 :         return false;
         275                 :     }
         276                 :     // The loop index is initialized with constant expression.
         277               0 :     if (!isConstExpr(declInit->getRight())) {
         278                 :         error(declInit->getLine(),
         279                 :               "Loop index cannot be initialized with non-constant expression",
         280               0 :               symbol->getSymbol().c_str());
         281               0 :         return false;
         282                 :     }
         283                 :
         284               0 :     info->index.id = symbol->getId();
         285               0 :     return true;
         286                 : }
         287                 :
         288               0 : bool ValidateLimitations::validateForLoopCond(TIntermLoop* node,
         289                 :                                               TLoopInfo* info)
         290                 : {
         291               0 :     TIntermNode* cond = node->getCondition();
         292               0 :     if (cond == NULL) {
         293               0 :         error(node->getLine(), "Missing condition", "for");
         294               0 :         return false;
         295                 :     }
         296                 :     //
         297                 :     // condition has the form:
         298                 :     //     loop_index relational_operator constant_expression
         299                 :     //
         300               0 :     TIntermBinary* binOp = cond->getAsBinaryNode();
         301               0 :     if (binOp == NULL) {
         302               0 :         error(node->getLine(), "Invalid condition", "for");
         303               0 :         return false;
         304                 :     }
         305                 :     // Loop index should be to the left of relational operator.
         306               0 :     TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode();
         307               0 :     if (symbol == NULL) {
         308               0 :         error(binOp->getLine(), "Invalid condition", "for");
         309               0 :         return false;
         310                 :     }
         311               0 :     if (symbol->getId() != info->index.id) {
         312                 :         error(symbol->getLine(),
         313               0 :               "Expected loop index", symbol->getSymbol().c_str());
         314               0 :         return false;
         315                 :     }
         316                 :     // Relational operator is one of: > >= < <= == or !=.
         317               0 :     switch (binOp->getOp()) {
         318                 :       case EOpEqual:
         319                 :       case EOpNotEqual:
         320                 :       case EOpLessThan:
         321                 :       case EOpGreaterThan:
         322                 :       case EOpLessThanEqual:
         323                 :       case EOpGreaterThanEqual:
         324               0 :         break;
         325                 :       default:
         326                 :         error(binOp->getLine(),
         327                 :               "Invalid relational operator",
         328               0 :               getOperatorString(binOp->getOp()));
         329               0 :         break;
         330                 :     }
         331                 :     // Loop index must be compared with a constant.
         332               0 :     if (!isConstExpr(binOp->getRight())) {
         333                 :         error(binOp->getLine(),
         334                 :               "Loop index cannot be compared with non-constant expression",
         335               0 :               symbol->getSymbol().c_str());
         336               0 :         return false;
         337                 :     }
         338                 :
         339               0 :     return true;
         340                 : }
         341                 :
         342               0 : bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node,
         343                 :                                               TLoopInfo* info)
         344                 : {
         345               0 :     TIntermNode* expr = node->getExpression();
         346               0 :     if (expr == NULL) {
         347               0 :         error(node->getLine(), "Missing expression", "for");
         348               0 :         return false;
         349                 :     }
         350                 :
         351                 :     // for expression has one of the following forms:
         352                 :     //     loop_index++
         353                 :     //     loop_index--
         354                 :     //     loop_index += constant_expression
         355                 :     //     loop_index -= constant_expression
         356                 :     //     ++loop_index
         357                 :     //     --loop_index
         358                 :     // The last two forms are not specified in the spec, but I am assuming
         359                 :     // its an oversight.
         360               0 :     TIntermUnary* unOp = expr->getAsUnaryNode();
         361               0 :     TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
         362                 :
         363               0 :     TOperator op = EOpNull;
         364               0 :     TIntermSymbol* symbol = NULL;
         365               0 :     if (unOp != NULL) {
         366               0 :         op = unOp->getOp();
         367               0 :         symbol = unOp->getOperand()->getAsSymbolNode();
         368               0 :     } else if (binOp != NULL) {
         369               0 :         op = binOp->getOp();
         370               0 :         symbol = binOp->getLeft()->getAsSymbolNode();
         371                 :     }
         372                 :
         373                 :     // The operand must be loop index.
         374               0 :     if (symbol == NULL) {
         375               0 :         error(expr->getLine(), "Invalid expression", "for");
         376               0 :         return false;
         377                 :     }
         378               0 :     if (symbol->getId() != info->index.id) {
         379                 :         error(symbol->getLine(),
         380               0 :               "Expected loop index", symbol->getSymbol().c_str());
         381               0 :         return false;
         382                 :     }
         383                 :
         384                 :     // The operator is one of: ++ -- += -=.
         385               0 :     switch (op) {
         386                 :         case EOpPostIncrement:
         387                 :         case EOpPostDecrement:
         388                 :         case EOpPreIncrement:
         389                 :         case EOpPreDecrement:
         390               0 :             ASSERT((unOp != NULL) && (binOp == NULL));
         391               0 :             break;
         392                 :         case EOpAddAssign:
         393                 :         case EOpSubAssign:
         394               0 :             ASSERT((unOp == NULL) && (binOp != NULL));
         395               0 :             break;
         396                 :         default:
         397               0 :             error(expr->getLine(), "Invalid operator", getOperatorString(op));
         398               0 :             return false;
         399                 :     }
         400                 :
         401                 :     // Loop index must be incremented/decremented with a constant.
         402               0 :     if (binOp != NULL) {
         403               0 :         if (!isConstExpr(binOp->getRight())) {
         404                 :             error(binOp->getLine(),
         405                 :                   "Loop index cannot be modified by non-constant expression",
         406               0 :                   symbol->getSymbol().c_str());
         407               0 :             return false;
         408                 :         }
         409                 :     }
         410                 :
         411               0 :     return true;
         412                 : }
         413                 :
         414               0 : bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node)
         415                 : {
         416               0 :     ASSERT(node->getOp() == EOpFunctionCall);
         417                 :
         418                 :     // If not within loop body, there is nothing to check.
         419               0 :     if (!withinLoopBody())
         420               0 :         return true;
         421                 :
         422                 :     // List of param indices for which loop indices are used as argument.
         423                 :     typedef std::vector<int> ParamIndex;
         424               0 :     ParamIndex pIndex;
         425               0 :     TIntermSequence& params = node->getSequence();
         426               0 :     for (TIntermSequence::size_type i = 0; i < params.size(); ++i) {
         427               0 :         TIntermSymbol* symbol = params[i]->getAsSymbolNode();
         428               0 :         if (symbol && isLoopIndex(symbol))
         429               0 :             pIndex.push_back(i);
         430                 :     }
         431                 :     // If none of the loop indices are used as arguments,
         432                 :     // there is nothing to check.
         433               0 :     if (pIndex.empty())
         434               0 :         return true;
         435                 :
         436               0 :     bool valid = true;
         437               0 :     TSymbolTable& symbolTable = GlobalParseContext->symbolTable;
         438               0 :     TSymbol* symbol = symbolTable.find(node->getName());
         439               0 :     ASSERT(symbol && symbol->isFunction());
         440               0 :     TFunction* function = static_cast<TFunction*>(symbol);
         441               0 :     for (ParamIndex::const_iterator i = pIndex.begin();
         442               0 :          i != pIndex.end(); ++i) {
         443               0 :         const TParameter& param = function->getParam(*i);
         444               0 :         TQualifier qual = param.type->getQualifier();
         445               0 :         if ((qual == EvqOut) || (qual == EvqInOut)) {
         446               0 :             error(params[*i]->getLine(),
         447                 :                   "Loop index cannot be used as argument to a function out or inout parameter",
         448               0 :                   params[*i]->getAsSymbolNode()->getSymbol().c_str());
         449               0 :             valid = false;
         450                 :         }
         451                 :     }
         452                 :
         453               0 :     return valid;
         454                 : }
         455                 :
         456               0 : bool ValidateLimitations::validateOperation(TIntermOperator* node,
         457                 :                                             TIntermNode* operand) {
         458                 :     // Check if loop index is modified in the loop body.
         459               0 :     if (!withinLoopBody() || !node->modifiesState())
         460               0 :         return true;
         461                 :
         462               0 :     const TIntermSymbol* symbol = operand->getAsSymbolNode();
         463               0 :     if (symbol && isLoopIndex(symbol)) {
         464                 :         error(node->getLine(),
         465                 :               "Loop index cannot be statically assigned to within the body of the loop",
         466               0 :               symbol->getSymbol().c_str());
         467                 :     }
         468               0 :     return true;
         469                 : }
         470                 :
         471               0 : bool ValidateLimitations::isConstExpr(TIntermNode* node)
         472                 : {
         473               0 :     ASSERT(node != NULL);
         474               0 :     return node->getAsConstantUnion() != NULL;
         475                 : }
         476                 :
         477               0 : bool ValidateLimitations::isConstIndexExpr(TIntermNode* node)
         478                 : {
         479               0 :     ASSERT(node != NULL);
         480                 :
         481               0 :     ValidateConstIndexExpr validate(mLoopStack);
         482               0 :     node->traverse(&validate);
         483               0 :     return validate.isValid();
         484                 : }
         485                 :
         486               0 : bool ValidateLimitations::validateIndexing(TIntermBinary* node)
         487                 : {
         488               0 :     ASSERT((node->getOp() == EOpIndexDirect) ||
         489                 :            (node->getOp() == EOpIndexIndirect));
         490                 :
         491               0 :     bool valid = true;
         492               0 :     TIntermTyped* index = node->getRight();
         493                 :     // The index expression must have integral type.
         494               0 :     if (!index->isScalar() || (index->getBasicType() != EbtInt)) {
         495                 :         error(index->getLine(),
         496                 :               "Index expression must have integral type",
         497               0 :               index->getCompleteString().c_str());
         498               0 :         valid = false;
         499                 :     }
         500                 :     // The index expession must be a constant-index-expression unless
         501                 :     // the operand is a uniform in a vertex shader.
         502               0 :     TIntermTyped* operand = node->getLeft();
         503                 :     bool skip = (mShaderType == SH_VERTEX_SHADER) &&
         504               0 :                 (operand->getQualifier() == EvqUniform);
         505               0 :     if (!skip && !isConstIndexExpr(index)) {
         506               0 :         error(index->getLine(), "Index expression must be constant", "[]");
         507               0 :         valid = false;
         508                 :     }
         509               0 :     return valid;
         510                 : }
         511                 :

Generated by: LCOV version 1.7