blob: 3a88d380e7ad7dfeed2e7e45a351a35873fce539 [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 {
111 case EOpFunctionCall:
112 validateFunctionCall(node);
113 break;
114 default:
115 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000116 }
117 return true;
118}
119
Zhenyao Mo550c6002014-02-26 15:40:48 -0800120bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000121{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200122 if (!mValidateInnerLoops)
123 return true;
124
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000125 if (!validateLoopType(node))
126 return false;
127
Zhenyao Mo550c6002014-02-26 15:40:48 -0800128 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000129 return false;
130
Zhenyao Mo550c6002014-02-26 15:40:48 -0800131 TIntermNode *body = node->getBody();
132 if (body != NULL)
133 {
Corentin Wallez1b896c62016-11-16 13:10:44 -0500134 mLoopSymbolIds.push_back(GetLoopSymbolId(node));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000135 body->traverse(this);
Corentin Wallez1b896c62016-11-16 13:10:44 -0500136 mLoopSymbolIds.pop_back();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000137 }
138
139 // The loop is fully processed - no need to visit children.
140 return false;
141}
142
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500143void ValidateLimitations::error(TSourceLoc loc, const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000144{
Olli Etuaho77ba4082016-12-16 12:01:18 +0000145 mDiagnostics->error(loc, reason, token);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000146}
147
148bool ValidateLimitations::withinLoopBody() const
149{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500150 return !mLoopSymbolIds.empty();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000151}
152
Zhenyao Mo550c6002014-02-26 15:40:48 -0800153bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000154{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500155 return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
156 mLoopSymbolIds.end();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000157}
158
Zhenyao Mo550c6002014-02-26 15:40:48 -0800159bool ValidateLimitations::validateLoopType(TIntermLoop *node)
160{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000161 TLoopType type = node->getType();
162 if (type == ELoopFor)
163 return true;
164
165 // Reject while and do-while loops.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500166 error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do");
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000167 return false;
168}
169
Zhenyao Mo550c6002014-02-26 15:40:48 -0800170bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000171{
172 ASSERT(node->getType() == ELoopFor);
173
174 //
175 // The for statement has the form:
176 // for ( init-declaration ; condition ; expression ) statement
177 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800178 int indexSymbolId = validateForLoopInit(node);
179 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000180 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800181 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000182 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800183 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000184 return false;
185
186 return true;
187}
188
Zhenyao Mo550c6002014-02-26 15:40:48 -0800189int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000190{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800191 TIntermNode *init = node->getInit();
192 if (init == NULL)
193 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000194 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800195 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000196 }
197
198 //
199 // init-declaration has the form:
200 // type-specifier identifier = constant-expression
201 //
Olli Etuaho13389b62016-10-16 11:48:18 +0100202 TIntermDeclaration *decl = init->getAsDeclarationNode();
203 if (decl == nullptr)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800204 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000205 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800206 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000207 }
208 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700209 TIntermSequence *declSeq = decl->getSequence();
210 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800211 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000212 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800213 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000214 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700215 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800216 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
217 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000218 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800219 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000220 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800221 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
222 if (symbol == NULL)
223 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000224 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800225 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000226 }
227 // The loop index has type int or float.
228 TBasicType type = symbol->getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500229 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat))
230 {
231 error(symbol->getLine(), "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800232 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000233 }
234 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800235 if (!isConstExpr(declInit->getRight()))
236 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500237 error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000238 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800239 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000240 }
241
Zhenyao Mo550c6002014-02-26 15:40:48 -0800242 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000243}
244
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500245bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000246{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800247 TIntermNode *cond = node->getCondition();
248 if (cond == NULL)
249 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000250 error(node->getLine(), "Missing condition", "for");
251 return false;
252 }
253 //
254 // condition has the form:
255 // loop_index relational_operator constant_expression
256 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257 TIntermBinary *binOp = cond->getAsBinaryNode();
258 if (binOp == NULL)
259 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000260 error(node->getLine(), "Invalid condition", "for");
261 return false;
262 }
263 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800264 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
265 if (symbol == NULL)
266 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000267 error(binOp->getLine(), "Invalid condition", "for");
268 return false;
269 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800270 if (symbol->getId() != indexSymbolId)
271 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500272 error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000273 return false;
274 }
275 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800276 switch (binOp->getOp())
277 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500278 case EOpEqual:
279 case EOpNotEqual:
280 case EOpLessThan:
281 case EOpGreaterThan:
282 case EOpLessThanEqual:
283 case EOpGreaterThanEqual:
284 break;
285 default:
286 error(binOp->getLine(), "Invalid relational operator",
287 GetOperatorString(binOp->getOp()));
288 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000289 }
290 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800291 if (!isConstExpr(binOp->getRight()))
292 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500293 error(binOp->getLine(), "Loop index cannot be compared with non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000294 symbol->getSymbol().c_str());
295 return false;
296 }
297
298 return true;
299}
300
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500301bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000302{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800303 TIntermNode *expr = node->getExpression();
304 if (expr == NULL)
305 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000306 error(node->getLine(), "Missing expression", "for");
307 return false;
308 }
309
310 // for expression has one of the following forms:
311 // loop_index++
312 // loop_index--
313 // loop_index += constant_expression
314 // loop_index -= constant_expression
315 // ++loop_index
316 // --loop_index
317 // The last two forms are not specified in the spec, but I am assuming
318 // its an oversight.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500319 TIntermUnary *unOp = expr->getAsUnaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800320 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000321
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500322 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800323 TIntermSymbol *symbol = NULL;
324 if (unOp != NULL)
325 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500326 op = unOp->getOp();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000327 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800328 }
329 else if (binOp != NULL)
330 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500331 op = binOp->getOp();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000332 symbol = binOp->getLeft()->getAsSymbolNode();
333 }
334
335 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800336 if (symbol == NULL)
337 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000338 error(expr->getLine(), "Invalid expression", "for");
339 return false;
340 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800341 if (symbol->getId() != indexSymbolId)
342 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500343 error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000344 return false;
345 }
346
347 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800348 switch (op)
349 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500350 case EOpPostIncrement:
351 case EOpPostDecrement:
352 case EOpPreIncrement:
353 case EOpPreDecrement:
354 ASSERT((unOp != NULL) && (binOp == NULL));
355 break;
356 case EOpAddAssign:
357 case EOpSubAssign:
358 ASSERT((unOp == NULL) && (binOp != NULL));
359 break;
360 default:
361 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
362 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000363 }
364
365 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800366 if (binOp != NULL)
367 {
368 if (!isConstExpr(binOp->getRight()))
369 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500370 error(binOp->getLine(), "Loop index cannot be modified by non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000371 symbol->getSymbol().c_str());
372 return false;
373 }
374 }
375
376 return true;
377}
378
Zhenyao Mo550c6002014-02-26 15:40:48 -0800379bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000380{
381 ASSERT(node->getOp() == EOpFunctionCall);
382
383 // If not within loop body, there is nothing to check.
384 if (!withinLoopBody())
385 return true;
386
387 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000388 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000389 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700390 TIntermSequence *params = node->getSequence();
391 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800392 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700393 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000394 if (symbol && isLoopIndex(symbol))
395 pIndex.push_back(i);
396 }
397 // If none of the loop indices are used as arguments,
398 // there is nothing to check.
399 if (pIndex.empty())
400 return true;
401
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500402 bool valid = true;
403 TSymbolTable &symbolTable = GetGlobalParseContext()->symbolTable;
Olli Etuahobd674552016-10-06 13:28:42 +0100404 TSymbol *symbol = symbolTable.find(node->getFunctionSymbolInfo()->getName(),
405 GetGlobalParseContext()->getShaderVersion());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000406 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800407 TFunction *function = static_cast<TFunction *>(symbol);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500408 for (ParamIndex::const_iterator i = pIndex.begin(); i != pIndex.end(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800409 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700410 const TConstParameter &param = function->getParam(*i);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500411 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800412 if ((qual == EvqOut) || (qual == EvqInOut))
413 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700414 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000415 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700416 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000417 valid = false;
418 }
419 }
420
421 return valid;
422}
423
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500424bool ValidateLimitations::validateOperation(TIntermOperator *node, TIntermNode *operand)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800425{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000426 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500427 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000428 return true;
429
Zhenyao Mo550c6002014-02-26 15:40:48 -0800430 TIntermSymbol *symbol = operand->getAsSymbolNode();
431 if (symbol && isLoopIndex(symbol))
432 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000433 error(node->getLine(),
434 "Loop index cannot be statically assigned to within the body of the loop",
435 symbol->getSymbol().c_str());
436 }
437 return true;
438}
439
Zhenyao Mo550c6002014-02-26 15:40:48 -0800440bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000441{
Olli Etuahod5610572015-12-10 19:42:09 +0200442 ASSERT(node != nullptr);
443 return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000444}
445
Zhenyao Mo550c6002014-02-26 15:40:48 -0800446bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000447{
448 ASSERT(node != NULL);
449
Corentin Wallez1b896c62016-11-16 13:10:44 -0500450 ValidateConstIndexExpr validate(mLoopSymbolIds);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000451 node->traverse(&validate);
452 return validate.isValid();
453}
454
Zhenyao Mo550c6002014-02-26 15:40:48 -0800455bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000456{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500457 ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000458
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500459 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800460 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000461 // The index expession must be a constant-index-expression unless
462 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800463 TIntermTyped *operand = node->getLeft();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500464 bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800465 if (!skip && !isConstIndexExpr(index))
466 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000467 error(index->getLine(), "Index expression must be constant", "[]");
468 valid = false;
469 }
470 return valid;
471}
472
Jamie Madill45bcc782016-11-07 13:58:48 -0500473} // namespace sh