blob: c4dad54be9916ade5dace52ea85560adfa1f75eb [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)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000029 : mValid(true), mLoopStack(stack) {}
30
31 // Returns true if the parsed node represents a constant index expression.
32 bool isValid() const { return mValid; }
33
Zhenyao Mo550c6002014-02-26 15:40:48 -080034 virtual void visitSymbol(TIntermSymbol *symbol)
35 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000036 // Only constants and loop indices are allowed in a
37 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080038 if (mValid)
39 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000040 mValid = (symbol->getQualifier() == EvqConst) ||
Zhenyao Mo550c6002014-02-26 15:40:48 -080041 (mLoopStack.findLoop(symbol));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000042 }
43 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000044
Zhenyao Mo550c6002014-02-26 15:40:48 -080045 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000046 bool mValid;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000047 TLoopStack& mLoopStack;
48};
Zhenyao Mo550c6002014-02-26 15:40:48 -080049
Zhenyao Moe40d1e92014-07-16 17:40:36 -070050const char *GetOperatorString(TOperator op)
51{
52 switch (op)
53 {
54 case EOpInitialize: return "=";
55 case EOpAssign: return "=";
56 case EOpAddAssign: return "+=";
57 case EOpSubAssign: return "-=";
58 case EOpDivAssign: return "/=";
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +000059 case EOpModAssign: return "%=";
Zhenyao Moe40d1e92014-07-16 17:40:36 -070060
61 // Fall-through.
62 case EOpMulAssign:
63 case EOpVectorTimesMatrixAssign:
64 case EOpVectorTimesScalarAssign:
65 case EOpMatrixTimesScalarAssign:
66 case EOpMatrixTimesMatrixAssign: return "*=";
67
68 // Fall-through.
69 case EOpIndexDirect:
70 case EOpIndexIndirect: return "[]";
71
72 case EOpIndexDirectStruct:
73 case EOpIndexDirectInterfaceBlock: return ".";
74 case EOpVectorSwizzle: return ".";
75 case EOpAdd: return "+";
76 case EOpSub: return "-";
77 case EOpMul: return "*";
78 case EOpDiv: return "/";
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +000079 case EOpMod: return "%";
Zhenyao Moe40d1e92014-07-16 17:40:36 -070080 case EOpEqual: return "==";
81 case EOpNotEqual: return "!=";
82 case EOpLessThan: return "<";
83 case EOpGreaterThan: return ">";
84 case EOpLessThanEqual: return "<=";
85 case EOpGreaterThanEqual: return ">=";
86
87 // Fall-through.
88 case EOpVectorTimesScalar:
89 case EOpVectorTimesMatrix:
90 case EOpMatrixTimesVector:
91 case EOpMatrixTimesScalar:
92 case EOpMatrixTimesMatrix: return "*";
93
94 case EOpLogicalOr: return "||";
95 case EOpLogicalXor: return "^^";
96 case EOpLogicalAnd: return "&&";
97 case EOpNegative: return "-";
Zhenyao Mode1e00e2014-10-09 16:55:32 -070098 case EOpPositive: return "+";
Zhenyao Moe40d1e92014-07-16 17:40:36 -070099 case EOpVectorLogicalNot: return "not";
100 case EOpLogicalNot: return "!";
101 case EOpPostIncrement: return "++";
102 case EOpPostDecrement: return "--";
103 case EOpPreIncrement: return "++";
104 case EOpPreDecrement: return "--";
105
106 case EOpRadians: return "radians";
107 case EOpDegrees: return "degrees";
108 case EOpSin: return "sin";
109 case EOpCos: return "cos";
110 case EOpTan: return "tan";
111 case EOpAsin: return "asin";
112 case EOpAcos: return "acos";
113 case EOpAtan: return "atan";
114 case EOpExp: return "exp";
115 case EOpLog: return "log";
116 case EOpExp2: return "exp2";
117 case EOpLog2: return "log2";
118 case EOpSqrt: return "sqrt";
119 case EOpInverseSqrt: return "inversesqrt";
120 case EOpAbs: return "abs";
121 case EOpSign: return "sign";
122 case EOpFloor: return "floor";
123 case EOpCeil: return "ceil";
124 case EOpFract: return "fract";
125 case EOpLength: return "length";
126 case EOpNormalize: return "normalize";
127 case EOpDFdx: return "dFdx";
128 case EOpDFdy: return "dFdy";
129 case EOpFwidth: return "fwidth";
130 case EOpAny: return "any";
131 case EOpAll: return "all";
132
133 default: break;
134 }
135 return "";
136}
137
Zhenyao Mo550c6002014-02-26 15:40:48 -0800138} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000139
Jamie Madill183bde52014-07-02 15:31:19 -0400140ValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800141 TInfoSinkBase &sink)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000142 : mShaderType(shaderType),
143 mSink(sink),
144 mNumErrors(0)
145{
146}
147
Zhenyao Mo550c6002014-02-26 15:40:48 -0800148bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000149{
150 // Check if loop index is modified in the loop body.
151 validateOperation(node, node->getLeft());
152
153 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800154 switch (node->getOp())
155 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000156 case EOpIndexDirect:
157 case EOpIndexIndirect:
158 validateIndexing(node);
159 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800160 default:
161 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000162 }
163 return true;
164}
165
Zhenyao Mo550c6002014-02-26 15:40:48 -0800166bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000167{
168 // Check if loop index is modified in the loop body.
169 validateOperation(node, node->getOperand());
170
171 return true;
172}
173
Zhenyao Mo550c6002014-02-26 15:40:48 -0800174bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000175{
176 switch (node->getOp()) {
177 case EOpFunctionCall:
178 validateFunctionCall(node);
179 break;
180 default:
181 break;
182 }
183 return true;
184}
185
Zhenyao Mo550c6002014-02-26 15:40:48 -0800186bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000187{
188 if (!validateLoopType(node))
189 return false;
190
Zhenyao Mo550c6002014-02-26 15:40:48 -0800191 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000192 return false;
193
Zhenyao Mo550c6002014-02-26 15:40:48 -0800194 TIntermNode *body = node->getBody();
195 if (body != NULL)
196 {
197 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000198 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800199 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000200 }
201
202 // The loop is fully processed - no need to visit children.
203 return false;
204}
205
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000206void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800207 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000208{
209 mSink.prefix(EPrefixError);
210 mSink.location(loc);
211 mSink << "'" << token << "' : " << reason << "\n";
212 ++mNumErrors;
213}
214
215bool ValidateLimitations::withinLoopBody() const
216{
217 return !mLoopStack.empty();
218}
219
Zhenyao Mo550c6002014-02-26 15:40:48 -0800220bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000221{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800222 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000223}
224
Zhenyao Mo550c6002014-02-26 15:40:48 -0800225bool ValidateLimitations::validateLoopType(TIntermLoop *node)
226{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000227 TLoopType type = node->getType();
228 if (type == ELoopFor)
229 return true;
230
231 // Reject while and do-while loops.
232 error(node->getLine(),
233 "This type of loop is not allowed",
234 type == ELoopWhile ? "while" : "do");
235 return false;
236}
237
Zhenyao Mo550c6002014-02-26 15:40:48 -0800238bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000239{
240 ASSERT(node->getType() == ELoopFor);
241
242 //
243 // The for statement has the form:
244 // for ( init-declaration ; condition ; expression ) statement
245 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800246 int indexSymbolId = validateForLoopInit(node);
247 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000248 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800249 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000250 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800251 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000252 return false;
253
254 return true;
255}
256
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000258{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800259 TIntermNode *init = node->getInit();
260 if (init == NULL)
261 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000262 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800263 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000264 }
265
266 //
267 // init-declaration has the form:
268 // type-specifier identifier = constant-expression
269 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800270 TIntermAggregate *decl = init->getAsAggregate();
271 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
272 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000273 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800274 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000275 }
276 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700277 TIntermSequence *declSeq = decl->getSequence();
278 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800279 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000280 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800281 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000282 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700283 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800284 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
285 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000286 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800287 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000288 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800289 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
290 if (symbol == NULL)
291 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000292 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800293 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000294 }
295 // The loop index has type int or float.
296 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000297 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000298 error(symbol->getLine(),
299 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800300 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000301 }
302 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800303 if (!isConstExpr(declInit->getRight()))
304 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000305 error(declInit->getLine(),
306 "Loop index cannot be initialized with non-constant expression",
307 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800308 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000309 }
310
Zhenyao Mo550c6002014-02-26 15:40:48 -0800311 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000312}
313
Zhenyao Mo550c6002014-02-26 15:40:48 -0800314bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
315 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000316{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800317 TIntermNode *cond = node->getCondition();
318 if (cond == NULL)
319 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000320 error(node->getLine(), "Missing condition", "for");
321 return false;
322 }
323 //
324 // condition has the form:
325 // loop_index relational_operator constant_expression
326 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800327 TIntermBinary *binOp = cond->getAsBinaryNode();
328 if (binOp == NULL)
329 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000330 error(node->getLine(), "Invalid condition", "for");
331 return false;
332 }
333 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800334 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
335 if (symbol == NULL)
336 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000337 error(binOp->getLine(), "Invalid condition", "for");
338 return false;
339 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800340 if (symbol->getId() != indexSymbolId)
341 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000342 error(symbol->getLine(),
343 "Expected loop index", symbol->getSymbol().c_str());
344 return false;
345 }
346 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800347 switch (binOp->getOp())
348 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000349 case EOpEqual:
350 case EOpNotEqual:
351 case EOpLessThan:
352 case EOpGreaterThan:
353 case EOpLessThanEqual:
354 case EOpGreaterThanEqual:
355 break;
356 default:
357 error(binOp->getLine(),
358 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700359 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000360 break;
361 }
362 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800363 if (!isConstExpr(binOp->getRight()))
364 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000365 error(binOp->getLine(),
366 "Loop index cannot be compared with non-constant expression",
367 symbol->getSymbol().c_str());
368 return false;
369 }
370
371 return true;
372}
373
Zhenyao Mo550c6002014-02-26 15:40:48 -0800374bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
375 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000376{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800377 TIntermNode *expr = node->getExpression();
378 if (expr == NULL)
379 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000380 error(node->getLine(), "Missing expression", "for");
381 return false;
382 }
383
384 // for expression has one of the following forms:
385 // loop_index++
386 // loop_index--
387 // loop_index += constant_expression
388 // loop_index -= constant_expression
389 // ++loop_index
390 // --loop_index
391 // The last two forms are not specified in the spec, but I am assuming
392 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800393 TIntermUnary *unOp = expr->getAsUnaryNode();
394 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000395
396 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800397 TIntermSymbol *symbol = NULL;
398 if (unOp != NULL)
399 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000400 op = unOp->getOp();
401 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800402 }
403 else if (binOp != NULL)
404 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000405 op = binOp->getOp();
406 symbol = binOp->getLeft()->getAsSymbolNode();
407 }
408
409 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800410 if (symbol == NULL)
411 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000412 error(expr->getLine(), "Invalid expression", "for");
413 return false;
414 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800415 if (symbol->getId() != indexSymbolId)
416 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000417 error(symbol->getLine(),
418 "Expected loop index", symbol->getSymbol().c_str());
419 return false;
420 }
421
422 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800423 switch (op)
424 {
425 case EOpPostIncrement:
426 case EOpPostDecrement:
427 case EOpPreIncrement:
428 case EOpPreDecrement:
429 ASSERT((unOp != NULL) && (binOp == NULL));
430 break;
431 case EOpAddAssign:
432 case EOpSubAssign:
433 ASSERT((unOp == NULL) && (binOp != NULL));
434 break;
435 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700436 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800437 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000438 }
439
440 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800441 if (binOp != NULL)
442 {
443 if (!isConstExpr(binOp->getRight()))
444 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000445 error(binOp->getLine(),
446 "Loop index cannot be modified by non-constant expression",
447 symbol->getSymbol().c_str());
448 return false;
449 }
450 }
451
452 return true;
453}
454
Zhenyao Mo550c6002014-02-26 15:40:48 -0800455bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000456{
457 ASSERT(node->getOp() == EOpFunctionCall);
458
459 // If not within loop body, there is nothing to check.
460 if (!withinLoopBody())
461 return true;
462
463 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000464 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000465 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700466 TIntermSequence *params = node->getSequence();
467 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800468 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700469 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000470 if (symbol && isLoopIndex(symbol))
471 pIndex.push_back(i);
472 }
473 // If none of the loop indices are used as arguments,
474 // there is nothing to check.
475 if (pIndex.empty())
476 return true;
477
478 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400479 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
480 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000481 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800482 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000483 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800484 i != pIndex.end(); ++i)
485 {
486 const TParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000487 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800488 if ((qual == EvqOut) || (qual == EvqInOut))
489 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700490 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000491 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700492 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000493 valid = false;
494 }
495 }
496
497 return valid;
498}
499
Zhenyao Mo550c6002014-02-26 15:40:48 -0800500bool ValidateLimitations::validateOperation(TIntermOperator *node,
501 TIntermNode* operand)
502{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000503 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500504 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000505 return true;
506
Zhenyao Mo550c6002014-02-26 15:40:48 -0800507 TIntermSymbol *symbol = operand->getAsSymbolNode();
508 if (symbol && isLoopIndex(symbol))
509 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000510 error(node->getLine(),
511 "Loop index cannot be statically assigned to within the body of the loop",
512 symbol->getSymbol().c_str());
513 }
514 return true;
515}
516
Zhenyao Mo550c6002014-02-26 15:40:48 -0800517bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000518{
519 ASSERT(node != NULL);
520 return node->getAsConstantUnion() != NULL;
521}
522
Zhenyao Mo550c6002014-02-26 15:40:48 -0800523bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000524{
525 ASSERT(node != NULL);
526
527 ValidateConstIndexExpr validate(mLoopStack);
528 node->traverse(&validate);
529 return validate.isValid();
530}
531
Zhenyao Mo550c6002014-02-26 15:40:48 -0800532bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000533{
534 ASSERT((node->getOp() == EOpIndexDirect) ||
535 (node->getOp() == EOpIndexIndirect));
536
537 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800538 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000539 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000540 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000541 error(index->getLine(),
542 "Index expression must have integral type",
543 index->getCompleteString().c_str());
544 valid = false;
545 }
546 // The index expession must be a constant-index-expression unless
547 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800548 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400549 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000550 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800551 if (!skip && !isConstIndexExpr(index))
552 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000553 error(index->getLine(), "Index expression must be constant", "[]");
554 valid = false;
555 }
556 return valid;
557}
558