blob: e647e4cb64897a98e55a11a999fc1b3e11c3ed31 [file] [log] [blame]
alokp@chromium.orgb59a7782010-11-24 18:38:33 +00001//
shannonwoods@chromium.org96e7ba12013-05-30 00:02:41 +00002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
alokp@chromium.orgb59a7782010-11-24 18:38:33 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/ValidateLimitations.h"
Olli Etuaho77ba4082016-12-16 12:01:18 +00008
9#include "compiler/translator/Diagnostics.h"
Geoff Lang17732822013-08-29 13:46:49 -040010#include "compiler/translator/InitializeParseContext.h"
Jamie Madill6b9cb252013-10-17 10:45:47 -040011#include "compiler/translator/ParseContext.h"
Jamie Madill183bde52014-07-02 15:31:19 -040012#include "angle_gl.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000013
Jamie Madill45bcc782016-11-07 13:58:48 -050014namespace sh
15{
16
Zhenyao Mo550c6002014-02-26 15:40:48 -080017namespace
18{
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000019
Corentin Wallez1b896c62016-11-16 13:10:44 -050020int GetLoopSymbolId(TIntermLoop *loop)
21{
22 // Here we assume all the operations are valid, because the loop node is
23 // already validated before this call.
24 TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
25 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
26 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
27
28 return symbol->getId();
29}
30
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000031// Traverses a node to check if it represents a constant index expression.
32// Definition:
33// constant-index-expressions are a superset of constant-expressions.
34// Constant-index-expressions can include loop indices as defined in
35// GLSL ES 1.0 spec, Appendix A, section 4.
36// The following are constant-index-expressions:
37// - Constant expressions
38// - Loop indices as defined in section 4
39// - Expressions composed of both of the above
Zhenyao Mo550c6002014-02-26 15:40:48 -080040class ValidateConstIndexExpr : public TIntermTraverser
41{
42 public:
Corentin Wallez1b896c62016-11-16 13:10:44 -050043 ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
44 : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030045 {
46 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000047
48 // Returns true if the parsed node represents a constant index expression.
49 bool isValid() const { return mValid; }
50
Corentin Walleze5a1f272015-08-21 02:58:25 +020051 void visitSymbol(TIntermSymbol *symbol) override
Zhenyao Mo550c6002014-02-26 15:40:48 -080052 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000053 // Only constants and loop indices are allowed in a
54 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080055 if (mValid)
56 {
Corentin Wallez1b896c62016-11-16 13:10:44 -050057 bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
58 symbol->getId()) != mLoopSymbolIds.end();
59 mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000060 }
61 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000062
Zhenyao Mo550c6002014-02-26 15:40:48 -080063 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000064 bool mValid;
Corentin Wallez1b896c62016-11-16 13:10:44 -050065 const std::vector<int> mLoopSymbolIds;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000066};
Zhenyao Mo550c6002014-02-26 15:40:48 -080067
68} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000069
Olli Etuaho77ba4082016-12-16 12:01:18 +000070ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TDiagnostics *diagnostics)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030071 : TIntermTraverser(true, false, false),
72 mShaderType(shaderType),
Olli Etuaho77ba4082016-12-16 12:01:18 +000073 mDiagnostics(diagnostics),
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020074 mValidateIndexing(true),
75 mValidateInnerLoops(true)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000076{
Olli Etuaho77ba4082016-12-16 12:01:18 +000077 ASSERT(diagnostics);
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020078}
79
Zhenyao Mo550c6002014-02-26 15:40:48 -080080bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000081{
82 // Check if loop index is modified in the loop body.
83 validateOperation(node, node->getLeft());
84
85 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -080086 switch (node->getOp())
87 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050088 case EOpIndexDirect:
89 case EOpIndexIndirect:
90 if (mValidateIndexing)
91 validateIndexing(node);
92 break;
93 default:
94 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000095 }
96 return true;
97}
98
Zhenyao Mo550c6002014-02-26 15:40:48 -080099bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000100{
101 // Check if loop index is modified in the loop body.
102 validateOperation(node, node->getOperand());
103
104 return true;
105}
106
Zhenyao Mo550c6002014-02-26 15:40:48 -0800107bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000108{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500109 switch (node->getOp())
110 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800111 case EOpCallFunctionInAST:
112 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500113 validateFunctionCall(node);
114 break;
115 default:
116 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000117 }
118 return true;
119}
120
Zhenyao Mo550c6002014-02-26 15:40:48 -0800121bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000122{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200123 if (!mValidateInnerLoops)
124 return true;
125
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000126 if (!validateLoopType(node))
127 return false;
128
Zhenyao Mo550c6002014-02-26 15:40:48 -0800129 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000130 return false;
131
Zhenyao Mo550c6002014-02-26 15:40:48 -0800132 TIntermNode *body = node->getBody();
133 if (body != NULL)
134 {
Corentin Wallez1b896c62016-11-16 13:10:44 -0500135 mLoopSymbolIds.push_back(GetLoopSymbolId(node));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000136 body->traverse(this);
Corentin Wallez1b896c62016-11-16 13:10:44 -0500137 mLoopSymbolIds.pop_back();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000138 }
139
140 // The loop is fully processed - no need to visit children.
141 return false;
142}
143
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500144void ValidateLimitations::error(TSourceLoc loc, const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000145{
Olli Etuaho77ba4082016-12-16 12:01:18 +0000146 mDiagnostics->error(loc, reason, token);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000147}
148
149bool ValidateLimitations::withinLoopBody() const
150{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500151 return !mLoopSymbolIds.empty();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000152}
153
Zhenyao Mo550c6002014-02-26 15:40:48 -0800154bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000155{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500156 return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
157 mLoopSymbolIds.end();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000158}
159
Zhenyao Mo550c6002014-02-26 15:40:48 -0800160bool ValidateLimitations::validateLoopType(TIntermLoop *node)
161{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000162 TLoopType type = node->getType();
163 if (type == ELoopFor)
164 return true;
165
166 // Reject while and do-while loops.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500167 error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do");
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000168 return false;
169}
170
Zhenyao Mo550c6002014-02-26 15:40:48 -0800171bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000172{
173 ASSERT(node->getType() == ELoopFor);
174
175 //
176 // The for statement has the form:
177 // for ( init-declaration ; condition ; expression ) statement
178 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800179 int indexSymbolId = validateForLoopInit(node);
180 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000181 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800182 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000183 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800184 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000185 return false;
186
187 return true;
188}
189
Zhenyao Mo550c6002014-02-26 15:40:48 -0800190int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000191{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800192 TIntermNode *init = node->getInit();
193 if (init == NULL)
194 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000195 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800196 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000197 }
198
199 //
200 // init-declaration has the form:
201 // type-specifier identifier = constant-expression
202 //
Olli Etuaho13389b62016-10-16 11:48:18 +0100203 TIntermDeclaration *decl = init->getAsDeclarationNode();
204 if (decl == nullptr)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800205 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000206 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800207 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000208 }
209 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700210 TIntermSequence *declSeq = decl->getSequence();
211 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800212 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000213 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800214 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000215 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700216 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800217 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
218 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000219 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800220 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000221 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800222 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
223 if (symbol == NULL)
224 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000225 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800226 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000227 }
228 // The loop index has type int or float.
229 TBasicType type = symbol->getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500230 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat))
231 {
232 error(symbol->getLine(), "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800233 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000234 }
235 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800236 if (!isConstExpr(declInit->getRight()))
237 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500238 error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000239 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800240 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000241 }
242
Zhenyao Mo550c6002014-02-26 15:40:48 -0800243 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000244}
245
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500246bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000247{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800248 TIntermNode *cond = node->getCondition();
249 if (cond == NULL)
250 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000251 error(node->getLine(), "Missing condition", "for");
252 return false;
253 }
254 //
255 // condition has the form:
256 // loop_index relational_operator constant_expression
257 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800258 TIntermBinary *binOp = cond->getAsBinaryNode();
259 if (binOp == NULL)
260 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000261 error(node->getLine(), "Invalid condition", "for");
262 return false;
263 }
264 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800265 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
266 if (symbol == NULL)
267 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000268 error(binOp->getLine(), "Invalid condition", "for");
269 return false;
270 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800271 if (symbol->getId() != indexSymbolId)
272 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500273 error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000274 return false;
275 }
276 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800277 switch (binOp->getOp())
278 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500279 case EOpEqual:
280 case EOpNotEqual:
281 case EOpLessThan:
282 case EOpGreaterThan:
283 case EOpLessThanEqual:
284 case EOpGreaterThanEqual:
285 break;
286 default:
287 error(binOp->getLine(), "Invalid relational operator",
288 GetOperatorString(binOp->getOp()));
289 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000290 }
291 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800292 if (!isConstExpr(binOp->getRight()))
293 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500294 error(binOp->getLine(), "Loop index cannot be compared with non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000295 symbol->getSymbol().c_str());
296 return false;
297 }
298
299 return true;
300}
301
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500302bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000303{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800304 TIntermNode *expr = node->getExpression();
305 if (expr == NULL)
306 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000307 error(node->getLine(), "Missing expression", "for");
308 return false;
309 }
310
311 // for expression has one of the following forms:
312 // loop_index++
313 // loop_index--
314 // loop_index += constant_expression
315 // loop_index -= constant_expression
316 // ++loop_index
317 // --loop_index
318 // The last two forms are not specified in the spec, but I am assuming
319 // its an oversight.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500320 TIntermUnary *unOp = expr->getAsUnaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800321 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000322
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500323 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800324 TIntermSymbol *symbol = NULL;
325 if (unOp != NULL)
326 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500327 op = unOp->getOp();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000328 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800329 }
330 else if (binOp != NULL)
331 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500332 op = binOp->getOp();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000333 symbol = binOp->getLeft()->getAsSymbolNode();
334 }
335
336 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800337 if (symbol == NULL)
338 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000339 error(expr->getLine(), "Invalid expression", "for");
340 return false;
341 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800342 if (symbol->getId() != indexSymbolId)
343 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500344 error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000345 return false;
346 }
347
348 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800349 switch (op)
350 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500351 case EOpPostIncrement:
352 case EOpPostDecrement:
353 case EOpPreIncrement:
354 case EOpPreDecrement:
355 ASSERT((unOp != NULL) && (binOp == NULL));
356 break;
357 case EOpAddAssign:
358 case EOpSubAssign:
359 ASSERT((unOp == NULL) && (binOp != NULL));
360 break;
361 default:
362 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
363 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000364 }
365
366 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800367 if (binOp != NULL)
368 {
369 if (!isConstExpr(binOp->getRight()))
370 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500371 error(binOp->getLine(), "Loop index cannot be modified by non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000372 symbol->getSymbol().c_str());
373 return false;
374 }
375 }
376
377 return true;
378}
379
Zhenyao Mo550c6002014-02-26 15:40:48 -0800380bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000381{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800382 ASSERT(node->getOp() == EOpCallFunctionInAST || node->getOp() == EOpCallBuiltInFunction);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000383
384 // If not within loop body, there is nothing to check.
385 if (!withinLoopBody())
386 return true;
387
388 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000389 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000390 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700391 TIntermSequence *params = node->getSequence();
392 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800393 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700394 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000395 if (symbol && isLoopIndex(symbol))
396 pIndex.push_back(i);
397 }
398 // If none of the loop indices are used as arguments,
399 // there is nothing to check.
400 if (pIndex.empty())
401 return true;
402
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500403 bool valid = true;
404 TSymbolTable &symbolTable = GetGlobalParseContext()->symbolTable;
Olli Etuahoec9232b2017-03-27 17:01:37 +0300405 // TODO(oetuaho@nvidia.com): It would be neater to leverage TIntermLValueTrackingTraverser to
406 // keep track of out parameters, rather than doing a symbol table lookup here.
407 TString mangledName = TFunction::GetMangledNameFromCall(
408 node->getFunctionSymbolInfo()->getName(), *node->getSequence());
409 TSymbol *symbol = symbolTable.find(mangledName, GetGlobalParseContext()->getShaderVersion());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000410 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800411 TFunction *function = static_cast<TFunction *>(symbol);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500412 for (ParamIndex::const_iterator i = pIndex.begin(); i != pIndex.end(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800413 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700414 const TConstParameter &param = function->getParam(*i);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500415 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800416 if ((qual == EvqOut) || (qual == EvqInOut))
417 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700418 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000419 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700420 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000421 valid = false;
422 }
423 }
424
425 return valid;
426}
427
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500428bool ValidateLimitations::validateOperation(TIntermOperator *node, TIntermNode *operand)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800429{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000430 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500431 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000432 return true;
433
Zhenyao Mo550c6002014-02-26 15:40:48 -0800434 TIntermSymbol *symbol = operand->getAsSymbolNode();
435 if (symbol && isLoopIndex(symbol))
436 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000437 error(node->getLine(),
438 "Loop index cannot be statically assigned to within the body of the loop",
439 symbol->getSymbol().c_str());
440 }
441 return true;
442}
443
Zhenyao Mo550c6002014-02-26 15:40:48 -0800444bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000445{
Olli Etuahod5610572015-12-10 19:42:09 +0200446 ASSERT(node != nullptr);
447 return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000448}
449
Zhenyao Mo550c6002014-02-26 15:40:48 -0800450bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000451{
452 ASSERT(node != NULL);
453
Corentin Wallez1b896c62016-11-16 13:10:44 -0500454 ValidateConstIndexExpr validate(mLoopSymbolIds);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000455 node->traverse(&validate);
456 return validate.isValid();
457}
458
Zhenyao Mo550c6002014-02-26 15:40:48 -0800459bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000460{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500461 ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000462
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500463 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800464 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000465 // The index expession must be a constant-index-expression unless
466 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800467 TIntermTyped *operand = node->getLeft();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500468 bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800469 if (!skip && !isConstIndexExpr(index))
470 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000471 error(index->getLine(), "Index expression must be constant", "[]");
472 valid = false;
473 }
474 return valid;
475}
476
Jamie Madill45bcc782016-11-07 13:58:48 -0500477} // namespace sh