Home | History | Annotate | Download | only in MachineIndependent
      1 //
      2 // Copyright (C) 2013 LunarG, Inc.
      3 //
      4 // All rights reserved.
      5 //
      6 // Redistribution and use in source and binary forms, with or without
      7 // modification, are permitted provided that the following conditions
      8 // are met:
      9 //
     10 //    Redistributions of source code must retain the above copyright
     11 //    notice, this list of conditions and the following disclaimer.
     12 //
     13 //    Redistributions in binary form must reproduce the above
     14 //    copyright notice, this list of conditions and the following
     15 //    disclaimer in the documentation and/or other materials provided
     16 //    with the distribution.
     17 //
     18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     19 //    contributors may be used to endorse or promote products derived
     20 //    from this software without specific prior written permission.
     21 //
     22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33 // POSSIBILITY OF SUCH DAMAGE.
     34 //
     35 
     36 //
     37 // Do sub tree walks for
     38 // 1) inductive loop bodies to see if the inductive variable is modified
     39 // 2) array-index expressions to see if they are "constant-index-expression"
     40 //
     41 // These are per Appendix A of ES 2.0:
     42 //
     43 // "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
     44 // argument to a function out or inout parameter."
     45 //
     46 // "The following are constant-index-expressions:
     47 //  - Constant expressions
     48 //  - Loop indices as defined in section 4
     49 //  - Expressions composed of both of the above"
     50 //
     51 // N.B.: assuming the last rule excludes function calls
     52 //
     53 
     54 #include "ParseHelper.h"
     55 
     56 namespace glslang {
     57 
     58 //
     59 // The inductive loop-body traverser.
     60 //
     61 // Just look at things that might modify the loop index.
     62 //
     63 
     64 class TInductiveTraverser : public TIntermTraverser {
     65 public:
     66     TInductiveTraverser(int id, TSymbolTable& st)
     67     : loopId(id), symbolTable(st), bad(false)  { }
     68 
     69     virtual bool visitBinary(TVisit, TIntermBinary* node);
     70     virtual bool visitUnary(TVisit, TIntermUnary* node);
     71     virtual bool visitAggregate(TVisit, TIntermAggregate* node);
     72 
     73     int loopId;           // unique ID of the symbol that's the loop inductive variable
     74     TSymbolTable& symbolTable;
     75     bool bad;
     76     TSourceLoc badLoc;
     77 
     78 protected:
     79     TInductiveTraverser(TInductiveTraverser&);
     80     TInductiveTraverser& operator=(TInductiveTraverser&);
     81 };
     82 
     83 // check binary operations for those modifying the loop index
     84 bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
     85 {
     86     if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
     87                                  node->getLeft()->getAsSymbolNode()->getId() == loopId) {
     88         bad = true;
     89         badLoc = node->getLoc();
     90     }
     91 
     92     return true;
     93 }
     94 
     95 // check unary operations for those modifying the loop index
     96 bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
     97 {
     98     if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
     99                                  node->getOperand()->getAsSymbolNode()->getId() == loopId) {
    100         bad = true;
    101         badLoc = node->getLoc();
    102     }
    103 
    104     return true;
    105 }
    106 
    107 // check function calls for arguments modifying the loop index
    108 bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
    109 {
    110     if (node->getOp() == EOpFunctionCall) {
    111         // see if an out or inout argument is the loop index
    112         const TIntermSequence& args = node->getSequence();
    113         for (int i = 0; i < (int)args.size(); ++i) {
    114             if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == loopId) {
    115                 TSymbol* function = symbolTable.find(node->getName());
    116                 const TType* type = (*function->getAsFunction())[i].type;
    117                 if (type->getQualifier().storage == EvqOut ||
    118                     type->getQualifier().storage == EvqInOut) {
    119                     bad = true;
    120                     badLoc = node->getLoc();
    121                 }
    122             }
    123         }
    124     }
    125 
    126     return true;
    127 }
    128 
    129 //
    130 // External function to call for loop check.
    131 //
    132 void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
    133 {
    134     TInductiveTraverser it(loopId, symbolTable);
    135 
    136     if (body == nullptr)
    137         return;
    138 
    139     body->traverse(&it);
    140 
    141     if (it.bad)
    142         error(it.badLoc, "inductive loop index modified", "limitations", "");
    143 }
    144 
    145 //
    146 // The "constant-index-expression" tranverser.
    147 //
    148 // Just look at things that can form an index.
    149 //
    150 
    151 class TIndexTraverser : public TIntermTraverser {
    152 public:
    153     TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
    154     virtual void visitSymbol(TIntermSymbol* symbol);
    155     virtual bool visitAggregate(TVisit, TIntermAggregate* node);
    156     const TIdSetType& inductiveLoopIds;
    157     bool bad;
    158     TSourceLoc badLoc;
    159 
    160 protected:
    161     TIndexTraverser(TIndexTraverser&);
    162     TIndexTraverser& operator=(TIndexTraverser&);
    163 };
    164 
    165 // make sure symbols are inductive-loop indexes
    166 void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
    167 {
    168     if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
    169         bad = true;
    170         badLoc = symbol->getLoc();
    171     }
    172 }
    173 
    174 // check for function calls, assuming they are bad; spec. doesn't really say
    175 bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
    176 {
    177     if (node->getOp() == EOpFunctionCall) {
    178         bad = true;
    179         badLoc = node->getLoc();
    180     }
    181 
    182     return true;
    183 }
    184 
    185 //
    186 // External function to call for loop check.
    187 //
    188 void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
    189 {
    190     TIndexTraverser it(inductiveLoopIds);
    191 
    192     index->traverse(&it);
    193 
    194     if (it.bad)
    195         error(it.badLoc, "Non-constant-index-expression", "limitations", "");
    196 }
    197 
    198 } // end namespace glslang
    199