blob: 29f1aa37b38efd4a71647aa359152b04dc344077 [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
Corentin Wallez1b896c62016-11-16 13:10:44 -050019int GetLoopSymbolId(TIntermLoop *loop)
20{
21 // Here we assume all the operations are valid, because the loop node is
22 // already validated before this call.
23 TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
24 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
25 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
26
27 return symbol->getId();
28}
29
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000030// Traverses a node to check if it represents a constant index expression.
31// Definition:
32// constant-index-expressions are a superset of constant-expressions.
33// Constant-index-expressions can include loop indices as defined in
34// GLSL ES 1.0 spec, Appendix A, section 4.
35// The following are constant-index-expressions:
36// - Constant expressions
37// - Loop indices as defined in section 4
38// - Expressions composed of both of the above
Zhenyao Mo550c6002014-02-26 15:40:48 -080039class ValidateConstIndexExpr : public TIntermTraverser
40{
41 public:
Corentin Wallez1b896c62016-11-16 13:10:44 -050042 ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
43 : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030044 {
45 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000046
47 // Returns true if the parsed node represents a constant index expression.
48 bool isValid() const { return mValid; }
49
Corentin Walleze5a1f272015-08-21 02:58:25 +020050 void visitSymbol(TIntermSymbol *symbol) override
Zhenyao Mo550c6002014-02-26 15:40:48 -080051 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000052 // Only constants and loop indices are allowed in a
53 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080054 if (mValid)
55 {
Corentin Wallez1b896c62016-11-16 13:10:44 -050056 bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
57 symbol->getId()) != mLoopSymbolIds.end();
58 mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000059 }
60 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000061
Zhenyao Mo550c6002014-02-26 15:40:48 -080062 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000063 bool mValid;
Corentin Wallez1b896c62016-11-16 13:10:44 -050064 const std::vector<int> mLoopSymbolIds;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000065};
Zhenyao Mo550c6002014-02-26 15:40:48 -080066
67} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000068
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020069ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030070 : TIntermTraverser(true, false, false),
71 mShaderType(shaderType),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000072 mSink(sink),
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020073 mNumErrors(0),
74 mValidateIndexing(true),
75 mValidateInnerLoops(true)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000076{
77}
78
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020079// static
80bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
81{
82 // The shader type doesn't matter in this case.
83 ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
84 validate.mValidateIndexing = false;
85 validate.mValidateInnerLoops = false;
86 if (!validate.validateLoopType(loop))
87 return false;
88 if (!validate.validateForLoopHeader(loop))
89 return false;
90 TIntermNode *body = loop->getBody();
91 if (body != nullptr)
92 {
Corentin Wallez1b896c62016-11-16 13:10:44 -050093 validate.mLoopSymbolIds.push_back(GetLoopSymbolId(loop));
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020094 body->traverse(&validate);
Corentin Wallez1b896c62016-11-16 13:10:44 -050095 validate.mLoopSymbolIds.pop_back();
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020096 }
97 return (validate.mNumErrors == 0);
98}
99
Zhenyao Mo550c6002014-02-26 15:40:48 -0800100bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000101{
102 // Check if loop index is modified in the loop body.
103 validateOperation(node, node->getLeft());
104
105 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800106 switch (node->getOp())
107 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000108 case EOpIndexDirect:
109 case EOpIndexIndirect:
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200110 if (mValidateIndexing)
111 validateIndexing(node);
112 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800113 default:
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200114 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000115 }
116 return true;
117}
118
Zhenyao Mo550c6002014-02-26 15:40:48 -0800119bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000120{
121 // Check if loop index is modified in the loop body.
122 validateOperation(node, node->getOperand());
123
124 return true;
125}
126
Zhenyao Mo550c6002014-02-26 15:40:48 -0800127bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000128{
129 switch (node->getOp()) {
130 case EOpFunctionCall:
131 validateFunctionCall(node);
132 break;
133 default:
134 break;
135 }
136 return true;
137}
138
Zhenyao Mo550c6002014-02-26 15:40:48 -0800139bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000140{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200141 if (!mValidateInnerLoops)
142 return true;
143
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000144 if (!validateLoopType(node))
145 return false;
146
Zhenyao Mo550c6002014-02-26 15:40:48 -0800147 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000148 return false;
149
Zhenyao Mo550c6002014-02-26 15:40:48 -0800150 TIntermNode *body = node->getBody();
151 if (body != NULL)
152 {
Corentin Wallez1b896c62016-11-16 13:10:44 -0500153 mLoopSymbolIds.push_back(GetLoopSymbolId(node));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000154 body->traverse(this);
Corentin Wallez1b896c62016-11-16 13:10:44 -0500155 mLoopSymbolIds.pop_back();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000156 }
157
158 // The loop is fully processed - no need to visit children.
159 return false;
160}
161
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000162void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800163 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000164{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200165 if (mSink)
166 {
167 mSink->prefix(EPrefixError);
168 mSink->location(loc);
169 (*mSink) << "'" << token << "' : " << reason << "\n";
170 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000171 ++mNumErrors;
172}
173
174bool ValidateLimitations::withinLoopBody() const
175{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500176 return !mLoopSymbolIds.empty();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000177}
178
Zhenyao Mo550c6002014-02-26 15:40:48 -0800179bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000180{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500181 return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
182 mLoopSymbolIds.end();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000183}
184
Zhenyao Mo550c6002014-02-26 15:40:48 -0800185bool ValidateLimitations::validateLoopType(TIntermLoop *node)
186{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000187 TLoopType type = node->getType();
188 if (type == ELoopFor)
189 return true;
190
191 // Reject while and do-while loops.
192 error(node->getLine(),
193 "This type of loop is not allowed",
194 type == ELoopWhile ? "while" : "do");
195 return false;
196}
197
Zhenyao Mo550c6002014-02-26 15:40:48 -0800198bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000199{
200 ASSERT(node->getType() == ELoopFor);
201
202 //
203 // The for statement has the form:
204 // for ( init-declaration ; condition ; expression ) statement
205 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800206 int indexSymbolId = validateForLoopInit(node);
207 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000208 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800209 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000210 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800211 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000212 return false;
213
214 return true;
215}
216
Zhenyao Mo550c6002014-02-26 15:40:48 -0800217int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000218{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800219 TIntermNode *init = node->getInit();
220 if (init == NULL)
221 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000222 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800223 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000224 }
225
226 //
227 // init-declaration has the form:
228 // type-specifier identifier = constant-expression
229 //
Olli Etuaho13389b62016-10-16 11:48:18 +0100230 TIntermDeclaration *decl = init->getAsDeclarationNode();
231 if (decl == nullptr)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800232 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000233 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800234 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000235 }
236 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700237 TIntermSequence *declSeq = decl->getSequence();
238 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800239 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000240 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800241 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000242 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700243 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800244 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
245 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000246 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800247 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000248 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800249 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
250 if (symbol == NULL)
251 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000252 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800253 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000254 }
255 // The loop index has type int or float.
256 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000257 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000258 error(symbol->getLine(),
259 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800260 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000261 }
262 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800263 if (!isConstExpr(declInit->getRight()))
264 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000265 error(declInit->getLine(),
266 "Loop index cannot be initialized with non-constant expression",
267 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800268 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000269 }
270
Zhenyao Mo550c6002014-02-26 15:40:48 -0800271 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000272}
273
Zhenyao Mo550c6002014-02-26 15:40:48 -0800274bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
275 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000276{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800277 TIntermNode *cond = node->getCondition();
278 if (cond == NULL)
279 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000280 error(node->getLine(), "Missing condition", "for");
281 return false;
282 }
283 //
284 // condition has the form:
285 // loop_index relational_operator constant_expression
286 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800287 TIntermBinary *binOp = cond->getAsBinaryNode();
288 if (binOp == NULL)
289 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000290 error(node->getLine(), "Invalid condition", "for");
291 return false;
292 }
293 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800294 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
295 if (symbol == NULL)
296 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000297 error(binOp->getLine(), "Invalid condition", "for");
298 return false;
299 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800300 if (symbol->getId() != indexSymbolId)
301 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000302 error(symbol->getLine(),
303 "Expected loop index", symbol->getSymbol().c_str());
304 return false;
305 }
306 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800307 switch (binOp->getOp())
308 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000309 case EOpEqual:
310 case EOpNotEqual:
311 case EOpLessThan:
312 case EOpGreaterThan:
313 case EOpLessThanEqual:
314 case EOpGreaterThanEqual:
315 break;
316 default:
317 error(binOp->getLine(),
318 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700319 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000320 break;
321 }
322 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800323 if (!isConstExpr(binOp->getRight()))
324 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000325 error(binOp->getLine(),
326 "Loop index cannot be compared with non-constant expression",
327 symbol->getSymbol().c_str());
328 return false;
329 }
330
331 return true;
332}
333
Zhenyao Mo550c6002014-02-26 15:40:48 -0800334bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
335 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000336{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800337 TIntermNode *expr = node->getExpression();
338 if (expr == NULL)
339 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000340 error(node->getLine(), "Missing expression", "for");
341 return false;
342 }
343
344 // for expression has one of the following forms:
345 // loop_index++
346 // loop_index--
347 // loop_index += constant_expression
348 // loop_index -= constant_expression
349 // ++loop_index
350 // --loop_index
351 // The last two forms are not specified in the spec, but I am assuming
352 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800353 TIntermUnary *unOp = expr->getAsUnaryNode();
354 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000355
356 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800357 TIntermSymbol *symbol = NULL;
358 if (unOp != NULL)
359 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000360 op = unOp->getOp();
361 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800362 }
363 else if (binOp != NULL)
364 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000365 op = binOp->getOp();
366 symbol = binOp->getLeft()->getAsSymbolNode();
367 }
368
369 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800370 if (symbol == NULL)
371 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000372 error(expr->getLine(), "Invalid expression", "for");
373 return false;
374 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800375 if (symbol->getId() != indexSymbolId)
376 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000377 error(symbol->getLine(),
378 "Expected loop index", symbol->getSymbol().c_str());
379 return false;
380 }
381
382 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800383 switch (op)
384 {
385 case EOpPostIncrement:
386 case EOpPostDecrement:
387 case EOpPreIncrement:
388 case EOpPreDecrement:
389 ASSERT((unOp != NULL) && (binOp == NULL));
390 break;
391 case EOpAddAssign:
392 case EOpSubAssign:
393 ASSERT((unOp == NULL) && (binOp != NULL));
394 break;
395 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700396 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800397 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000398 }
399
400 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800401 if (binOp != NULL)
402 {
403 if (!isConstExpr(binOp->getRight()))
404 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000405 error(binOp->getLine(),
406 "Loop index cannot be modified by non-constant expression",
407 symbol->getSymbol().c_str());
408 return false;
409 }
410 }
411
412 return true;
413}
414
Zhenyao Mo550c6002014-02-26 15:40:48 -0800415bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000416{
417 ASSERT(node->getOp() == EOpFunctionCall);
418
419 // If not within loop body, there is nothing to check.
420 if (!withinLoopBody())
421 return true;
422
423 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000424 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000425 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700426 TIntermSequence *params = node->getSequence();
427 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800428 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700429 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000430 if (symbol && isLoopIndex(symbol))
431 pIndex.push_back(i);
432 }
433 // If none of the loop indices are used as arguments,
434 // there is nothing to check.
435 if (pIndex.empty())
436 return true;
437
438 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400439 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
Olli Etuahobd674552016-10-06 13:28:42 +0100440 TSymbol *symbol = symbolTable.find(node->getFunctionSymbolInfo()->getName(),
441 GetGlobalParseContext()->getShaderVersion());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000442 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800443 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000444 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800445 i != pIndex.end(); ++i)
446 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700447 const TConstParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000448 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800449 if ((qual == EvqOut) || (qual == EvqInOut))
450 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700451 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000452 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700453 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000454 valid = false;
455 }
456 }
457
458 return valid;
459}
460
Zhenyao Mo550c6002014-02-26 15:40:48 -0800461bool ValidateLimitations::validateOperation(TIntermOperator *node,
462 TIntermNode* operand)
463{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000464 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500465 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000466 return true;
467
Zhenyao Mo550c6002014-02-26 15:40:48 -0800468 TIntermSymbol *symbol = operand->getAsSymbolNode();
469 if (symbol && isLoopIndex(symbol))
470 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000471 error(node->getLine(),
472 "Loop index cannot be statically assigned to within the body of the loop",
473 symbol->getSymbol().c_str());
474 }
475 return true;
476}
477
Zhenyao Mo550c6002014-02-26 15:40:48 -0800478bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000479{
Olli Etuahod5610572015-12-10 19:42:09 +0200480 ASSERT(node != nullptr);
481 return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000482}
483
Zhenyao Mo550c6002014-02-26 15:40:48 -0800484bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000485{
486 ASSERT(node != NULL);
487
Corentin Wallez1b896c62016-11-16 13:10:44 -0500488 ValidateConstIndexExpr validate(mLoopSymbolIds);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000489 node->traverse(&validate);
490 return validate.isValid();
491}
492
Zhenyao Mo550c6002014-02-26 15:40:48 -0800493bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000494{
495 ASSERT((node->getOp() == EOpIndexDirect) ||
496 (node->getOp() == EOpIndexIndirect));
497
498 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800499 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000500 // The index expession must be a constant-index-expression unless
501 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800502 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400503 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000504 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800505 if (!skip && !isConstIndexExpr(index))
506 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000507 error(index->getLine(), "Index expression must be constant", "[]");
508 valid = false;
509 }
510 return valid;
511}
512
Jamie Madill45bcc782016-11-07 13:58:48 -0500513} // namespace sh