2 // Copyright (C) 2013 LunarG, Inc.
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
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"
41 // These are per Appendix A of ES 2.0:
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."
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"
51 // N.B.: assuming the last rule excludes function calls
54 #include "ParseHelper.h"
59 // The inductive loop-body traverser.
61 // Just look at things that might modify the loop index.
64 class TInductiveTraverser : public TIntermTraverser {
66 TInductiveTraverser(long long id, TSymbolTable& st)
67 : loopId(id), symbolTable(st), bad(false) { }
69 virtual bool visitBinary(TVisit, TIntermBinary* node);
70 virtual bool visitUnary(TVisit, TIntermUnary* node);
71 virtual bool visitAggregate(TVisit, TIntermAggregate* node);
73 long long loopId; // unique ID of the symbol that's the loop inductive variable
74 TSymbolTable& symbolTable;
79 TInductiveTraverser(TInductiveTraverser&);
80 TInductiveTraverser& operator=(TInductiveTraverser&);
83 // check binary operations for those modifying the loop index
84 bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
86 if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
87 node->getLeft()->getAsSymbolNode()->getId() == loopId) {
89 badLoc = node->getLoc();
95 // check unary operations for those modifying the loop index
96 bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
98 if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
99 node->getOperand()->getAsSymbolNode()->getId() == loopId) {
101 badLoc = node->getLoc();
107 // check function calls for arguments modifying the loop index
108 bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
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) {
120 badLoc = node->getLoc();
130 // External function to call for loop check.
132 void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, long long loopId, TSymbolTable& symbolTable)
134 TInductiveTraverser it(loopId, symbolTable);
142 error(it.badLoc, "inductive loop index modified", "limitations", "");
146 // The "constant-index-expression" tranverser.
148 // Just look at things that can form an index.
151 class TIndexTraverser : public TIntermTraverser {
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;
161 TIndexTraverser(TIndexTraverser&);
162 TIndexTraverser& operator=(TIndexTraverser&);
165 // make sure symbols are inductive-loop indexes
166 void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
168 if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
170 badLoc = symbol->getLoc();
174 // check for function calls, assuming they are bad; spec. doesn't really say
175 bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
177 if (node->getOp() == EOpFunctionCall) {
179 badLoc = node->getLoc();
186 // External function to call for loop check.
188 void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
191 TIndexTraverser it(inductiveLoopIds);
193 index->traverse(&it);
196 error(it.badLoc, "Non-constant-index-expression", "limitations", "");
200 } // end namespace glslang