limits.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. // Do sub tree walks for
  37. // 1) inductive loop bodies to see if the inductive variable is modified
  38. // 2) array-index expressions to see if they are "constant-index-expression"
  39. //
  40. // These are per Appendix A of ES 2.0:
  41. //
  42. // "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
  43. // argument to a function out or inout parameter."
  44. //
  45. // "The following are constant-index-expressions:
  46. // - Constant expressions
  47. // - Loop indices as defined in section 4
  48. // - Expressions composed of both of the above"
  49. //
  50. // N.B.: assuming the last rule excludes function calls
  51. //
  52. #include "ParseHelper.h"
  53. namespace glslang {
  54. //
  55. // The inductive loop-body traverser.
  56. //
  57. // Just look at things that might modify the loop index.
  58. //
  59. class TInductiveTraverser : public TIntermTraverser {
  60. public:
  61. TInductiveTraverser(int id, TSymbolTable& st)
  62. : loopId(id), symbolTable(st), bad(false) { }
  63. virtual bool visitBinary(TVisit, TIntermBinary* node);
  64. virtual bool visitUnary(TVisit, TIntermUnary* node);
  65. virtual bool visitAggregate(TVisit, TIntermAggregate* node);
  66. int loopId; // unique ID of the symbol that's the loop inductive variable
  67. TSymbolTable& symbolTable;
  68. bool bad;
  69. TSourceLoc badLoc;
  70. protected:
  71. TInductiveTraverser(TInductiveTraverser&);
  72. TInductiveTraverser& operator=(TInductiveTraverser&);
  73. };
  74. // check binary operations for those modifying the loop index
  75. bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
  76. {
  77. if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
  78. node->getLeft()->getAsSymbolNode()->getId() == loopId) {
  79. bad = true;
  80. badLoc = node->getLoc();
  81. }
  82. return true;
  83. }
  84. // check unary operations for those modifying the loop index
  85. bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
  86. {
  87. if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
  88. node->getOperand()->getAsSymbolNode()->getId() == loopId) {
  89. bad = true;
  90. badLoc = node->getLoc();
  91. }
  92. return true;
  93. }
  94. // check function calls for arguments modifying the loop index
  95. bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
  96. {
  97. if (node->getOp() == EOpFunctionCall) {
  98. // see if an out or inout argument is the loop index
  99. const TIntermSequence& args = node->getSequence();
  100. for (int i = 0; i < (int)args.size(); ++i) {
  101. if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == loopId) {
  102. TSymbol* function = symbolTable.find(node->getName());
  103. const TType* type = (*function->getAsFunction())[i].type;
  104. if (type->getQualifier().storage == EvqOut ||
  105. type->getQualifier().storage == EvqInOut) {
  106. bad = true;
  107. badLoc = node->getLoc();
  108. }
  109. }
  110. }
  111. }
  112. return true;
  113. }
  114. //
  115. // External function to call for loop check.
  116. //
  117. void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
  118. {
  119. TInductiveTraverser it(loopId, symbolTable);
  120. if (body == nullptr)
  121. return;
  122. body->traverse(&it);
  123. if (it.bad)
  124. error(it.badLoc, "inductive loop index modified", "limitations", "");
  125. }
  126. //
  127. // The "constant-index-expression" tranverser.
  128. //
  129. // Just look at things that can form an index.
  130. //
  131. class TIndexTraverser : public TIntermTraverser {
  132. public:
  133. TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
  134. virtual void visitSymbol(TIntermSymbol* symbol);
  135. virtual bool visitAggregate(TVisit, TIntermAggregate* node);
  136. const TIdSetType& inductiveLoopIds;
  137. bool bad;
  138. TSourceLoc badLoc;
  139. protected:
  140. TIndexTraverser(TIndexTraverser&);
  141. TIndexTraverser& operator=(TIndexTraverser&);
  142. };
  143. // make sure symbols are inductive-loop indexes
  144. void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
  145. {
  146. if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
  147. bad = true;
  148. badLoc = symbol->getLoc();
  149. }
  150. }
  151. // check for function calls, assuming they are bad; spec. doesn't really say
  152. bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
  153. {
  154. if (node->getOp() == EOpFunctionCall) {
  155. bad = true;
  156. badLoc = node->getLoc();
  157. }
  158. return true;
  159. }
  160. //
  161. // External function to call for loop check.
  162. //
  163. void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
  164. {
  165. #ifndef GLSLANG_WEB
  166. TIndexTraverser it(inductiveLoopIds);
  167. index->traverse(&it);
  168. if (it.bad)
  169. error(it.badLoc, "Non-constant-index-expression", "limitations", "");
  170. #endif
  171. }
  172. } // end namespace glslang