| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- //
- // Copyright (C) 2013 LunarG, Inc.
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- //
- // Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- //
- // Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following
- // disclaimer in the documentation and/or other materials provided
- // with the distribution.
- //
- // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
- // contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //
- //
- // Do sub tree walks for
- // 1) inductive loop bodies to see if the inductive variable is modified
- // 2) array-index expressions to see if they are "constant-index-expression"
- //
- // These are per Appendix A of ES 2.0:
- //
- // "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
- // argument to a function out or inout parameter."
- //
- // "The following are constant-index-expressions:
- // - Constant expressions
- // - Loop indices as defined in section 4
- // - Expressions composed of both of the above"
- //
- // N.B.: assuming the last rule excludes function calls
- //
- #include "ParseHelper.h"
- namespace glslang {
- //
- // The inductive loop-body traverser.
- //
- // Just look at things that might modify the loop index.
- //
- class TInductiveTraverser : public TIntermTraverser {
- public:
- TInductiveTraverser(int id, TSymbolTable& st)
- : loopId(id), symbolTable(st), bad(false) { }
- virtual bool visitBinary(TVisit, TIntermBinary* node);
- virtual bool visitUnary(TVisit, TIntermUnary* node);
- virtual bool visitAggregate(TVisit, TIntermAggregate* node);
- int loopId; // unique ID of the symbol that's the loop inductive variable
- TSymbolTable& symbolTable;
- bool bad;
- TSourceLoc badLoc;
- protected:
- TInductiveTraverser(TInductiveTraverser&);
- TInductiveTraverser& operator=(TInductiveTraverser&);
- };
- // check binary operations for those modifying the loop index
- bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
- {
- if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
- node->getLeft()->getAsSymbolNode()->getId() == loopId) {
- bad = true;
- badLoc = node->getLoc();
- }
- return true;
- }
- // check unary operations for those modifying the loop index
- bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
- {
- if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
- node->getOperand()->getAsSymbolNode()->getId() == loopId) {
- bad = true;
- badLoc = node->getLoc();
- }
- return true;
- }
- // check function calls for arguments modifying the loop index
- bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
- {
- if (node->getOp() == EOpFunctionCall) {
- // see if an out or inout argument is the loop index
- const TIntermSequence& args = node->getSequence();
- for (int i = 0; i < (int)args.size(); ++i) {
- if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == loopId) {
- TSymbol* function = symbolTable.find(node->getName());
- const TType* type = (*function->getAsFunction())[i].type;
- if (type->getQualifier().storage == EvqOut ||
- type->getQualifier().storage == EvqInOut) {
- bad = true;
- badLoc = node->getLoc();
- }
- }
- }
- }
- return true;
- }
- //
- // External function to call for loop check.
- //
- void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
- {
- TInductiveTraverser it(loopId, symbolTable);
- if (body == nullptr)
- return;
- body->traverse(&it);
- if (it.bad)
- error(it.badLoc, "inductive loop index modified", "limitations", "");
- }
- //
- // The "constant-index-expression" tranverser.
- //
- // Just look at things that can form an index.
- //
- class TIndexTraverser : public TIntermTraverser {
- public:
- TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
- virtual void visitSymbol(TIntermSymbol* symbol);
- virtual bool visitAggregate(TVisit, TIntermAggregate* node);
- const TIdSetType& inductiveLoopIds;
- bool bad;
- TSourceLoc badLoc;
- protected:
- TIndexTraverser(TIndexTraverser&);
- TIndexTraverser& operator=(TIndexTraverser&);
- };
- // make sure symbols are inductive-loop indexes
- void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
- {
- if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
- bad = true;
- badLoc = symbol->getLoc();
- }
- }
- // check for function calls, assuming they are bad; spec. doesn't really say
- bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
- {
- if (node->getOp() == EOpFunctionCall) {
- bad = true;
- badLoc = node->getLoc();
- }
- return true;
- }
- //
- // External function to call for loop check.
- //
- void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
- {
- #ifndef GLSLANG_WEB
- TIndexTraverser it(inductiveLoopIds);
- index->traverse(&it);
- if (it.bad)
- error(it.badLoc, "Non-constant-index-expression", "limitations", "");
- #endif
- }
- } // end namespace glslang
|