blob: 918f125798e0774c212edc16e3c4f8cf19ea41da [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
Zhenyao Mo550c6002014-02-26 15:40:48 -080013namespace
14{
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000015
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000016// Traverses a node to check if it represents a constant index expression.
17// Definition:
18// constant-index-expressions are a superset of constant-expressions.
19// Constant-index-expressions can include loop indices as defined in
20// GLSL ES 1.0 spec, Appendix A, section 4.
21// The following are constant-index-expressions:
22// - Constant expressions
23// - Loop indices as defined in section 4
24// - Expressions composed of both of the above
Zhenyao Mo550c6002014-02-26 15:40:48 -080025class ValidateConstIndexExpr : public TIntermTraverser
26{
27 public:
28 ValidateConstIndexExpr(TLoopStack& stack)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030029 : TIntermTraverser(true, false, false),
30 mValid(true),
31 mLoopStack(stack)
32 {
33 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000034
35 // Returns true if the parsed node represents a constant index expression.
36 bool isValid() const { return mValid; }
37
Corentin Walleze5a1f272015-08-21 02:58:25 +020038 void visitSymbol(TIntermSymbol *symbol) override
Zhenyao Mo550c6002014-02-26 15:40:48 -080039 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000040 // Only constants and loop indices are allowed in a
41 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080042 if (mValid)
43 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000044 mValid = (symbol->getQualifier() == EvqConst) ||
Zhenyao Mo550c6002014-02-26 15:40:48 -080045 (mLoopStack.findLoop(symbol));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000046 }
47 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000048
Zhenyao Mo550c6002014-02-26 15:40:48 -080049 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000050 bool mValid;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000051 TLoopStack& mLoopStack;
52};
Zhenyao Mo550c6002014-02-26 15:40:48 -080053
54} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000055
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020056ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030057 : TIntermTraverser(true, false, false),
58 mShaderType(shaderType),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000059 mSink(sink),
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020060 mNumErrors(0),
61 mValidateIndexing(true),
62 mValidateInnerLoops(true)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000063{
64}
65
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020066// static
67bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
68{
69 // The shader type doesn't matter in this case.
70 ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
71 validate.mValidateIndexing = false;
72 validate.mValidateInnerLoops = false;
73 if (!validate.validateLoopType(loop))
74 return false;
75 if (!validate.validateForLoopHeader(loop))
76 return false;
77 TIntermNode *body = loop->getBody();
78 if (body != nullptr)
79 {
80 validate.mLoopStack.push(loop);
81 body->traverse(&validate);
82 validate.mLoopStack.pop();
83 }
84 return (validate.mNumErrors == 0);
85}
86
Zhenyao Mo550c6002014-02-26 15:40:48 -080087bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000088{
89 // Check if loop index is modified in the loop body.
90 validateOperation(node, node->getLeft());
91
92 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -080093 switch (node->getOp())
94 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000095 case EOpIndexDirect:
96 case EOpIndexIndirect:
Olli Etuaho8a76dcc2015-12-10 20:25:12 +020097 if (mValidateIndexing)
98 validateIndexing(node);
99 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800100 default:
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200101 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000102 }
103 return true;
104}
105
Zhenyao Mo550c6002014-02-26 15:40:48 -0800106bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000107{
108 // Check if loop index is modified in the loop body.
109 validateOperation(node, node->getOperand());
110
111 return true;
112}
113
Zhenyao Mo550c6002014-02-26 15:40:48 -0800114bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000115{
116 switch (node->getOp()) {
117 case EOpFunctionCall:
118 validateFunctionCall(node);
119 break;
120 default:
121 break;
122 }
123 return true;
124}
125
Zhenyao Mo550c6002014-02-26 15:40:48 -0800126bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000127{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200128 if (!mValidateInnerLoops)
129 return true;
130
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000131 if (!validateLoopType(node))
132 return false;
133
Zhenyao Mo550c6002014-02-26 15:40:48 -0800134 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000135 return false;
136
Zhenyao Mo550c6002014-02-26 15:40:48 -0800137 TIntermNode *body = node->getBody();
138 if (body != NULL)
139 {
140 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000141 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800142 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000143 }
144
145 // The loop is fully processed - no need to visit children.
146 return false;
147}
148
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000149void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800150 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000151{
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200152 if (mSink)
153 {
154 mSink->prefix(EPrefixError);
155 mSink->location(loc);
156 (*mSink) << "'" << token << "' : " << reason << "\n";
157 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000158 ++mNumErrors;
159}
160
161bool ValidateLimitations::withinLoopBody() const
162{
163 return !mLoopStack.empty();
164}
165
Zhenyao Mo550c6002014-02-26 15:40:48 -0800166bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000167{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800168 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000169}
170
Zhenyao Mo550c6002014-02-26 15:40:48 -0800171bool ValidateLimitations::validateLoopType(TIntermLoop *node)
172{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000173 TLoopType type = node->getType();
174 if (type == ELoopFor)
175 return true;
176
177 // Reject while and do-while loops.
178 error(node->getLine(),
179 "This type of loop is not allowed",
180 type == ELoopWhile ? "while" : "do");
181 return false;
182}
183
Zhenyao Mo550c6002014-02-26 15:40:48 -0800184bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000185{
186 ASSERT(node->getType() == ELoopFor);
187
188 //
189 // The for statement has the form:
190 // for ( init-declaration ; condition ; expression ) statement
191 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800192 int indexSymbolId = validateForLoopInit(node);
193 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000194 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800195 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000196 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800197 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000198 return false;
199
200 return true;
201}
202
Zhenyao Mo550c6002014-02-26 15:40:48 -0800203int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000204{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800205 TIntermNode *init = node->getInit();
206 if (init == NULL)
207 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000208 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800209 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000210 }
211
212 //
213 // init-declaration has the form:
214 // type-specifier identifier = constant-expression
215 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800216 TIntermAggregate *decl = init->getAsAggregate();
217 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
218 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000219 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800220 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000221 }
222 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700223 TIntermSequence *declSeq = decl->getSequence();
224 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800225 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000226 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800227 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000228 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700229 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800230 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
231 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000232 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800233 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000234 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800235 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
236 if (symbol == NULL)
237 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000238 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800239 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000240 }
241 // The loop index has type int or float.
242 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000243 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000244 error(symbol->getLine(),
245 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800246 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000247 }
248 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800249 if (!isConstExpr(declInit->getRight()))
250 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000251 error(declInit->getLine(),
252 "Loop index cannot be initialized with non-constant expression",
253 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800254 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000255 }
256
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000258}
259
Zhenyao Mo550c6002014-02-26 15:40:48 -0800260bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
261 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000262{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800263 TIntermNode *cond = node->getCondition();
264 if (cond == NULL)
265 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000266 error(node->getLine(), "Missing condition", "for");
267 return false;
268 }
269 //
270 // condition has the form:
271 // loop_index relational_operator constant_expression
272 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800273 TIntermBinary *binOp = cond->getAsBinaryNode();
274 if (binOp == NULL)
275 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000276 error(node->getLine(), "Invalid condition", "for");
277 return false;
278 }
279 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800280 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
281 if (symbol == NULL)
282 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000283 error(binOp->getLine(), "Invalid condition", "for");
284 return false;
285 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800286 if (symbol->getId() != indexSymbolId)
287 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000288 error(symbol->getLine(),
289 "Expected loop index", symbol->getSymbol().c_str());
290 return false;
291 }
292 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800293 switch (binOp->getOp())
294 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000295 case EOpEqual:
296 case EOpNotEqual:
297 case EOpLessThan:
298 case EOpGreaterThan:
299 case EOpLessThanEqual:
300 case EOpGreaterThanEqual:
301 break;
302 default:
303 error(binOp->getLine(),
304 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700305 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000306 break;
307 }
308 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800309 if (!isConstExpr(binOp->getRight()))
310 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000311 error(binOp->getLine(),
312 "Loop index cannot be compared with non-constant expression",
313 symbol->getSymbol().c_str());
314 return false;
315 }
316
317 return true;
318}
319
Zhenyao Mo550c6002014-02-26 15:40:48 -0800320bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
321 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000322{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800323 TIntermNode *expr = node->getExpression();
324 if (expr == NULL)
325 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000326 error(node->getLine(), "Missing expression", "for");
327 return false;
328 }
329
330 // for expression has one of the following forms:
331 // loop_index++
332 // loop_index--
333 // loop_index += constant_expression
334 // loop_index -= constant_expression
335 // ++loop_index
336 // --loop_index
337 // The last two forms are not specified in the spec, but I am assuming
338 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800339 TIntermUnary *unOp = expr->getAsUnaryNode();
340 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000341
342 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800343 TIntermSymbol *symbol = NULL;
344 if (unOp != NULL)
345 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000346 op = unOp->getOp();
347 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800348 }
349 else if (binOp != NULL)
350 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000351 op = binOp->getOp();
352 symbol = binOp->getLeft()->getAsSymbolNode();
353 }
354
355 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800356 if (symbol == NULL)
357 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000358 error(expr->getLine(), "Invalid expression", "for");
359 return false;
360 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800361 if (symbol->getId() != indexSymbolId)
362 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000363 error(symbol->getLine(),
364 "Expected loop index", symbol->getSymbol().c_str());
365 return false;
366 }
367
368 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800369 switch (op)
370 {
371 case EOpPostIncrement:
372 case EOpPostDecrement:
373 case EOpPreIncrement:
374 case EOpPreDecrement:
375 ASSERT((unOp != NULL) && (binOp == NULL));
376 break;
377 case EOpAddAssign:
378 case EOpSubAssign:
379 ASSERT((unOp == NULL) && (binOp != NULL));
380 break;
381 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700382 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800383 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000384 }
385
386 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800387 if (binOp != NULL)
388 {
389 if (!isConstExpr(binOp->getRight()))
390 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000391 error(binOp->getLine(),
392 "Loop index cannot be modified by non-constant expression",
393 symbol->getSymbol().c_str());
394 return false;
395 }
396 }
397
398 return true;
399}
400
Zhenyao Mo550c6002014-02-26 15:40:48 -0800401bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000402{
403 ASSERT(node->getOp() == EOpFunctionCall);
404
405 // If not within loop body, there is nothing to check.
406 if (!withinLoopBody())
407 return true;
408
409 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000410 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000411 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700412 TIntermSequence *params = node->getSequence();
413 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800414 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700415 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000416 if (symbol && isLoopIndex(symbol))
417 pIndex.push_back(i);
418 }
419 // If none of the loop indices are used as arguments,
420 // there is nothing to check.
421 if (pIndex.empty())
422 return true;
423
424 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400425 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400426 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->getShaderVersion());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000427 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800428 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000429 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800430 i != pIndex.end(); ++i)
431 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700432 const TConstParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000433 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800434 if ((qual == EvqOut) || (qual == EvqInOut))
435 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700436 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000437 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700438 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000439 valid = false;
440 }
441 }
442
443 return valid;
444}
445
Zhenyao Mo550c6002014-02-26 15:40:48 -0800446bool ValidateLimitations::validateOperation(TIntermOperator *node,
447 TIntermNode* operand)
448{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000449 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500450 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000451 return true;
452
Zhenyao Mo550c6002014-02-26 15:40:48 -0800453 TIntermSymbol *symbol = operand->getAsSymbolNode();
454 if (symbol && isLoopIndex(symbol))
455 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000456 error(node->getLine(),
457 "Loop index cannot be statically assigned to within the body of the loop",
458 symbol->getSymbol().c_str());
459 }
460 return true;
461}
462
Zhenyao Mo550c6002014-02-26 15:40:48 -0800463bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000464{
Olli Etuahod5610572015-12-10 19:42:09 +0200465 ASSERT(node != nullptr);
466 return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000467}
468
Zhenyao Mo550c6002014-02-26 15:40:48 -0800469bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000470{
471 ASSERT(node != NULL);
472
473 ValidateConstIndexExpr validate(mLoopStack);
474 node->traverse(&validate);
475 return validate.isValid();
476}
477
Zhenyao Mo550c6002014-02-26 15:40:48 -0800478bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000479{
480 ASSERT((node->getOp() == EOpIndexDirect) ||
481 (node->getOp() == EOpIndexIndirect));
482
483 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800484 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000485 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000486 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000487 error(index->getLine(),
488 "Index expression must have integral type",
489 index->getCompleteString().c_str());
490 valid = false;
491 }
492 // The index expession must be a constant-index-expression unless
493 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800494 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400495 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000496 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800497 if (!skip && !isConstIndexExpr(index))
498 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000499 error(index->getLine(), "Index expression must be constant", "[]");
500 valid = false;
501 }
502 return valid;
503}
504