blob: 75a0c5156220309c65cb7702f516d05b887cab13 [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"
8#include "compiler/translator/InfoSink.h"
9#include "compiler/translator/InitializeParseContext.h"
Jamie Madill6b9cb252013-10-17 10:45:47 -040010#include "compiler/translator/ParseContext.h"
Jamie Madill183bde52014-07-02 15:31:19 -040011#include "angle_gl.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000012
Jamie Madill45bcc782016-11-07 13:58:48 -050013namespace sh
14{
15
Zhenyao Mo550c6002014-02-26 15:40:48 -080016namespace
17{
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000018
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000019// Traverses a node to check if it represents a constant index expression.
20// Definition:
21// constant-index-expressions are a superset of constant-expressions.
22// Constant-index-expressions can include loop indices as defined in
23// GLSL ES 1.0 spec, Appendix A, section 4.
24// The following are constant-index-expressions:
25// - Constant expressions
26// - Loop indices as defined in section 4
27// - Expressions composed of both of the above
Zhenyao Mo550c6002014-02-26 15:40:48 -080028class ValidateConstIndexExpr : public TIntermTraverser
29{
30 public:
31 ValidateConstIndexExpr(TLoopStack& stack)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030032 : TIntermTraverser(true, false, false),
33 mValid(true),
34 mLoopStack(stack)
35 {
36 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000037
38 // Returns true if the parsed node represents a constant index expression.
39 bool isValid() const { return mValid; }
40
Corentin Walleze5a1f272015-08-21 02:58:25 +020041 void visitSymbol(TIntermSymbol *symbol) override
Zhenyao Mo550c6002014-02-26 15:40:48 -080042 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000043 // Only constants and loop indices are allowed in a
44 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080045 if (mValid)
46 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000047 mValid = (symbol->getQualifier() == EvqConst) ||
Zhenyao Mo550c6002014-02-26 15:40:48 -080048 (mLoopStack.findLoop(symbol));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000049 }
50 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000051
Zhenyao Mo550c6002014-02-26 15:40:48 -080052 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000053 bool mValid;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000054 TLoopStack& mLoopStack;
55};
Zhenyao Mo550c6002014-02-26 15:40:48 -080056
57} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000058
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020059ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030060 : TIntermTraverser(true, false, false),
61 mShaderType(shaderType),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000062 mSink(sink),
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020063 mNumErrors(0),
64 mValidateIndexing(true),
65 mValidateInnerLoops(true)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000066{
67}
68
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020069// static
70bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
71{
72 // The shader type doesn't matter in this case.
73 ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
74 validate.mValidateIndexing = false;
75 validate.mValidateInnerLoops = false;
76 if (!validate.validateLoopType(loop))
77 return false;
78 if (!validate.validateForLoopHeader(loop))
79 return false;
80 TIntermNode *body = loop->getBody();
81 if (body != nullptr)
82 {
83 validate.mLoopStack.push(loop);
84 body->traverse(&validate);
85 validate.mLoopStack.pop();
86 }
87 return (validate.mNumErrors == 0);
88}
89
Zhenyao Mo550c6002014-02-26 15:40:48 -080090bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000091{
92 // Check if loop index is modified in the loop body.
93 validateOperation(node, node->getLeft());
94
95 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -080096 switch (node->getOp())
97 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000098 case EOpIndexDirect:
99 case EOpIndexIndirect:
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200100 if (mValidateIndexing)
101 validateIndexing(node);
102 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800103 default:
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200104 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000105 }
106 return true;
107}
108
Zhenyao Mo550c6002014-02-26 15:40:48 -0800109bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000110{
111 // Check if loop index is modified in the loop body.
112 validateOperation(node, node->getOperand());
113
114 return true;
115}
116
Zhenyao Mo550c6002014-02-26 15:40:48 -0800117bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000118{
119 switch (node->getOp()) {
120 case EOpFunctionCall:
121 validateFunctionCall(node);
122 break;
123 default:
124 break;
125 }
126 return true;
127}
128
Zhenyao Mo550c6002014-02-26 15:40:48 -0800129bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000130{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200131 if (!mValidateInnerLoops)
132 return true;
133
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000134 if (!validateLoopType(node))
135 return false;
136
Zhenyao Mo550c6002014-02-26 15:40:48 -0800137 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000138 return false;
139
Zhenyao Mo550c6002014-02-26 15:40:48 -0800140 TIntermNode *body = node->getBody();
141 if (body != NULL)
142 {
143 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000144 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800145 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000146 }
147
148 // The loop is fully processed - no need to visit children.
149 return false;
150}
151
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000152void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800153 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000154{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200155 if (mSink)
156 {
157 mSink->prefix(EPrefixError);
158 mSink->location(loc);
159 (*mSink) << "'" << token << "' : " << reason << "\n";
160 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000161 ++mNumErrors;
162}
163
164bool ValidateLimitations::withinLoopBody() const
165{
166 return !mLoopStack.empty();
167}
168
Zhenyao Mo550c6002014-02-26 15:40:48 -0800169bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000170{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800171 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000172}
173
Zhenyao Mo550c6002014-02-26 15:40:48 -0800174bool ValidateLimitations::validateLoopType(TIntermLoop *node)
175{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000176 TLoopType type = node->getType();
177 if (type == ELoopFor)
178 return true;
179
180 // Reject while and do-while loops.
181 error(node->getLine(),
182 "This type of loop is not allowed",
183 type == ELoopWhile ? "while" : "do");
184 return false;
185}
186
Zhenyao Mo550c6002014-02-26 15:40:48 -0800187bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000188{
189 ASSERT(node->getType() == ELoopFor);
190
191 //
192 // The for statement has the form:
193 // for ( init-declaration ; condition ; expression ) statement
194 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800195 int indexSymbolId = validateForLoopInit(node);
196 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000197 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800198 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000199 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800200 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000201 return false;
202
203 return true;
204}
205
Zhenyao Mo550c6002014-02-26 15:40:48 -0800206int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000207{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800208 TIntermNode *init = node->getInit();
209 if (init == NULL)
210 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000211 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800212 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000213 }
214
215 //
216 // init-declaration has the form:
217 // type-specifier identifier = constant-expression
218 //
Olli Etuaho13389b62016-10-16 11:48:18 +0100219 TIntermDeclaration *decl = init->getAsDeclarationNode();
220 if (decl == nullptr)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800221 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000222 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800223 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000224 }
225 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700226 TIntermSequence *declSeq = decl->getSequence();
227 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800228 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000229 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800230 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000231 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700232 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800233 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
234 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000235 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800236 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000237 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800238 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
239 if (symbol == NULL)
240 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000241 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800242 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000243 }
244 // The loop index has type int or float.
245 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000246 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000247 error(symbol->getLine(),
248 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800249 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000250 }
251 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800252 if (!isConstExpr(declInit->getRight()))
253 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000254 error(declInit->getLine(),
255 "Loop index cannot be initialized with non-constant expression",
256 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000258 }
259
Zhenyao Mo550c6002014-02-26 15:40:48 -0800260 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000261}
262
Zhenyao Mo550c6002014-02-26 15:40:48 -0800263bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
264 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000265{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800266 TIntermNode *cond = node->getCondition();
267 if (cond == NULL)
268 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000269 error(node->getLine(), "Missing condition", "for");
270 return false;
271 }
272 //
273 // condition has the form:
274 // loop_index relational_operator constant_expression
275 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800276 TIntermBinary *binOp = cond->getAsBinaryNode();
277 if (binOp == NULL)
278 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000279 error(node->getLine(), "Invalid condition", "for");
280 return false;
281 }
282 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800283 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
284 if (symbol == NULL)
285 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000286 error(binOp->getLine(), "Invalid condition", "for");
287 return false;
288 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800289 if (symbol->getId() != indexSymbolId)
290 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000291 error(symbol->getLine(),
292 "Expected loop index", symbol->getSymbol().c_str());
293 return false;
294 }
295 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800296 switch (binOp->getOp())
297 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000298 case EOpEqual:
299 case EOpNotEqual:
300 case EOpLessThan:
301 case EOpGreaterThan:
302 case EOpLessThanEqual:
303 case EOpGreaterThanEqual:
304 break;
305 default:
306 error(binOp->getLine(),
307 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700308 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000309 break;
310 }
311 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800312 if (!isConstExpr(binOp->getRight()))
313 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000314 error(binOp->getLine(),
315 "Loop index cannot be compared with non-constant expression",
316 symbol->getSymbol().c_str());
317 return false;
318 }
319
320 return true;
321}
322
Zhenyao Mo550c6002014-02-26 15:40:48 -0800323bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
324 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000325{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800326 TIntermNode *expr = node->getExpression();
327 if (expr == NULL)
328 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000329 error(node->getLine(), "Missing expression", "for");
330 return false;
331 }
332
333 // for expression has one of the following forms:
334 // loop_index++
335 // loop_index--
336 // loop_index += constant_expression
337 // loop_index -= constant_expression
338 // ++loop_index
339 // --loop_index
340 // The last two forms are not specified in the spec, but I am assuming
341 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800342 TIntermUnary *unOp = expr->getAsUnaryNode();
343 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000344
345 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800346 TIntermSymbol *symbol = NULL;
347 if (unOp != NULL)
348 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000349 op = unOp->getOp();
350 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800351 }
352 else if (binOp != NULL)
353 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000354 op = binOp->getOp();
355 symbol = binOp->getLeft()->getAsSymbolNode();
356 }
357
358 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800359 if (symbol == NULL)
360 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000361 error(expr->getLine(), "Invalid expression", "for");
362 return false;
363 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800364 if (symbol->getId() != indexSymbolId)
365 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000366 error(symbol->getLine(),
367 "Expected loop index", symbol->getSymbol().c_str());
368 return false;
369 }
370
371 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800372 switch (op)
373 {
374 case EOpPostIncrement:
375 case EOpPostDecrement:
376 case EOpPreIncrement:
377 case EOpPreDecrement:
378 ASSERT((unOp != NULL) && (binOp == NULL));
379 break;
380 case EOpAddAssign:
381 case EOpSubAssign:
382 ASSERT((unOp == NULL) && (binOp != NULL));
383 break;
384 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700385 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800386 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000387 }
388
389 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800390 if (binOp != NULL)
391 {
392 if (!isConstExpr(binOp->getRight()))
393 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000394 error(binOp->getLine(),
395 "Loop index cannot be modified by non-constant expression",
396 symbol->getSymbol().c_str());
397 return false;
398 }
399 }
400
401 return true;
402}
403
Zhenyao Mo550c6002014-02-26 15:40:48 -0800404bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000405{
406 ASSERT(node->getOp() == EOpFunctionCall);
407
408 // If not within loop body, there is nothing to check.
409 if (!withinLoopBody())
410 return true;
411
412 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000413 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000414 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700415 TIntermSequence *params = node->getSequence();
416 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800417 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700418 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000419 if (symbol && isLoopIndex(symbol))
420 pIndex.push_back(i);
421 }
422 // If none of the loop indices are used as arguments,
423 // there is nothing to check.
424 if (pIndex.empty())
425 return true;
426
427 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400428 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
Olli Etuahobd674552016-10-06 13:28:42 +0100429 TSymbol *symbol = symbolTable.find(node->getFunctionSymbolInfo()->getName(),
430 GetGlobalParseContext()->getShaderVersion());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000431 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800432 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000433 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800434 i != pIndex.end(); ++i)
435 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700436 const TConstParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000437 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800438 if ((qual == EvqOut) || (qual == EvqInOut))
439 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700440 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000441 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700442 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000443 valid = false;
444 }
445 }
446
447 return valid;
448}
449
Zhenyao Mo550c6002014-02-26 15:40:48 -0800450bool ValidateLimitations::validateOperation(TIntermOperator *node,
451 TIntermNode* operand)
452{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000453 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500454 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000455 return true;
456
Zhenyao Mo550c6002014-02-26 15:40:48 -0800457 TIntermSymbol *symbol = operand->getAsSymbolNode();
458 if (symbol && isLoopIndex(symbol))
459 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000460 error(node->getLine(),
461 "Loop index cannot be statically assigned to within the body of the loop",
462 symbol->getSymbol().c_str());
463 }
464 return true;
465}
466
Zhenyao Mo550c6002014-02-26 15:40:48 -0800467bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000468{
Olli Etuahod5610572015-12-10 19:42:09 +0200469 ASSERT(node != nullptr);
470 return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000471}
472
Zhenyao Mo550c6002014-02-26 15:40:48 -0800473bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000474{
475 ASSERT(node != NULL);
476
477 ValidateConstIndexExpr validate(mLoopStack);
478 node->traverse(&validate);
479 return validate.isValid();
480}
481
Zhenyao Mo550c6002014-02-26 15:40:48 -0800482bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000483{
484 ASSERT((node->getOp() == EOpIndexDirect) ||
485 (node->getOp() == EOpIndexIndirect));
486
487 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800488 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000489 // The index expession must be a constant-index-expression unless
490 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800491 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400492 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000493 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800494 if (!skip && !isConstIndexExpr(index))
495 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000496 error(index->getLine(), "Index expression must be constant", "[]");
497 valid = false;
498 }
499 return valid;
500}
501
Jamie Madill45bcc782016-11-07 13:58:48 -0500502} // namespace sh