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