blob: 896e1cd7a01a72734461f5de46c6a3f48ce1c742 [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 "/=";
59
60 // Fall-through.
61 case EOpMulAssign:
62 case EOpVectorTimesMatrixAssign:
63 case EOpVectorTimesScalarAssign:
64 case EOpMatrixTimesScalarAssign:
65 case EOpMatrixTimesMatrixAssign: return "*=";
66
67 // Fall-through.
68 case EOpIndexDirect:
69 case EOpIndexIndirect: return "[]";
70
71 case EOpIndexDirectStruct:
72 case EOpIndexDirectInterfaceBlock: return ".";
73 case EOpVectorSwizzle: return ".";
74 case EOpAdd: return "+";
75 case EOpSub: return "-";
76 case EOpMul: return "*";
77 case EOpDiv: return "/";
78 case EOpMod: UNIMPLEMENTED(); break;
79 case EOpEqual: return "==";
80 case EOpNotEqual: return "!=";
81 case EOpLessThan: return "<";
82 case EOpGreaterThan: return ">";
83 case EOpLessThanEqual: return "<=";
84 case EOpGreaterThanEqual: return ">=";
85
86 // Fall-through.
87 case EOpVectorTimesScalar:
88 case EOpVectorTimesMatrix:
89 case EOpMatrixTimesVector:
90 case EOpMatrixTimesScalar:
91 case EOpMatrixTimesMatrix: return "*";
92
93 case EOpLogicalOr: return "||";
94 case EOpLogicalXor: return "^^";
95 case EOpLogicalAnd: return "&&";
96 case EOpNegative: return "-";
Zhenyao Mode1e00e2014-10-09 16:55:32 -070097 case EOpPositive: return "+";
Zhenyao Moe40d1e92014-07-16 17:40:36 -070098 case EOpVectorLogicalNot: return "not";
99 case EOpLogicalNot: return "!";
100 case EOpPostIncrement: return "++";
101 case EOpPostDecrement: return "--";
102 case EOpPreIncrement: return "++";
103 case EOpPreDecrement: return "--";
104
105 case EOpRadians: return "radians";
106 case EOpDegrees: return "degrees";
107 case EOpSin: return "sin";
108 case EOpCos: return "cos";
109 case EOpTan: return "tan";
110 case EOpAsin: return "asin";
111 case EOpAcos: return "acos";
112 case EOpAtan: return "atan";
113 case EOpExp: return "exp";
114 case EOpLog: return "log";
115 case EOpExp2: return "exp2";
116 case EOpLog2: return "log2";
117 case EOpSqrt: return "sqrt";
118 case EOpInverseSqrt: return "inversesqrt";
119 case EOpAbs: return "abs";
120 case EOpSign: return "sign";
121 case EOpFloor: return "floor";
122 case EOpCeil: return "ceil";
123 case EOpFract: return "fract";
124 case EOpLength: return "length";
125 case EOpNormalize: return "normalize";
126 case EOpDFdx: return "dFdx";
127 case EOpDFdy: return "dFdy";
128 case EOpFwidth: return "fwidth";
129 case EOpAny: return "any";
130 case EOpAll: return "all";
131
132 default: break;
133 }
134 return "";
135}
136
Zhenyao Mo550c6002014-02-26 15:40:48 -0800137} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000138
Jamie Madill183bde52014-07-02 15:31:19 -0400139ValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800140 TInfoSinkBase &sink)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000141 : mShaderType(shaderType),
142 mSink(sink),
143 mNumErrors(0)
144{
145}
146
Zhenyao Mo550c6002014-02-26 15:40:48 -0800147bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000148{
149 // Check if loop index is modified in the loop body.
150 validateOperation(node, node->getLeft());
151
152 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800153 switch (node->getOp())
154 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000155 case EOpIndexDirect:
156 case EOpIndexIndirect:
157 validateIndexing(node);
158 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800159 default:
160 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000161 }
162 return true;
163}
164
Zhenyao Mo550c6002014-02-26 15:40:48 -0800165bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000166{
167 // Check if loop index is modified in the loop body.
168 validateOperation(node, node->getOperand());
169
170 return true;
171}
172
Zhenyao Mo550c6002014-02-26 15:40:48 -0800173bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000174{
175 switch (node->getOp()) {
176 case EOpFunctionCall:
177 validateFunctionCall(node);
178 break;
179 default:
180 break;
181 }
182 return true;
183}
184
Zhenyao Mo550c6002014-02-26 15:40:48 -0800185bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000186{
187 if (!validateLoopType(node))
188 return false;
189
Zhenyao Mo550c6002014-02-26 15:40:48 -0800190 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000191 return false;
192
Zhenyao Mo550c6002014-02-26 15:40:48 -0800193 TIntermNode *body = node->getBody();
194 if (body != NULL)
195 {
196 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000197 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800198 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000199 }
200
201 // The loop is fully processed - no need to visit children.
202 return false;
203}
204
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000205void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800206 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000207{
208 mSink.prefix(EPrefixError);
209 mSink.location(loc);
210 mSink << "'" << token << "' : " << reason << "\n";
211 ++mNumErrors;
212}
213
214bool ValidateLimitations::withinLoopBody() const
215{
216 return !mLoopStack.empty();
217}
218
Zhenyao Mo550c6002014-02-26 15:40:48 -0800219bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000220{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800221 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000222}
223
Zhenyao Mo550c6002014-02-26 15:40:48 -0800224bool ValidateLimitations::validateLoopType(TIntermLoop *node)
225{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000226 TLoopType type = node->getType();
227 if (type == ELoopFor)
228 return true;
229
230 // Reject while and do-while loops.
231 error(node->getLine(),
232 "This type of loop is not allowed",
233 type == ELoopWhile ? "while" : "do");
234 return false;
235}
236
Zhenyao Mo550c6002014-02-26 15:40:48 -0800237bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000238{
239 ASSERT(node->getType() == ELoopFor);
240
241 //
242 // The for statement has the form:
243 // for ( init-declaration ; condition ; expression ) statement
244 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800245 int indexSymbolId = validateForLoopInit(node);
246 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000247 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800248 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000249 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800250 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000251 return false;
252
253 return true;
254}
255
Zhenyao Mo550c6002014-02-26 15:40:48 -0800256int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000257{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800258 TIntermNode *init = node->getInit();
259 if (init == NULL)
260 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000261 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800262 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000263 }
264
265 //
266 // init-declaration has the form:
267 // type-specifier identifier = constant-expression
268 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800269 TIntermAggregate *decl = init->getAsAggregate();
270 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
271 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000272 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800273 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000274 }
275 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700276 TIntermSequence *declSeq = decl->getSequence();
277 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800278 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000279 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800280 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000281 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700282 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800283 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
284 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000285 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800286 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000287 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800288 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
289 if (symbol == NULL)
290 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000291 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800292 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000293 }
294 // The loop index has type int or float.
295 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000296 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000297 error(symbol->getLine(),
298 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800299 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000300 }
301 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800302 if (!isConstExpr(declInit->getRight()))
303 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000304 error(declInit->getLine(),
305 "Loop index cannot be initialized with non-constant expression",
306 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800307 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000308 }
309
Zhenyao Mo550c6002014-02-26 15:40:48 -0800310 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000311}
312
Zhenyao Mo550c6002014-02-26 15:40:48 -0800313bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
314 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000315{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800316 TIntermNode *cond = node->getCondition();
317 if (cond == NULL)
318 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000319 error(node->getLine(), "Missing condition", "for");
320 return false;
321 }
322 //
323 // condition has the form:
324 // loop_index relational_operator constant_expression
325 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800326 TIntermBinary *binOp = cond->getAsBinaryNode();
327 if (binOp == NULL)
328 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000329 error(node->getLine(), "Invalid condition", "for");
330 return false;
331 }
332 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800333 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
334 if (symbol == NULL)
335 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000336 error(binOp->getLine(), "Invalid condition", "for");
337 return false;
338 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800339 if (symbol->getId() != indexSymbolId)
340 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000341 error(symbol->getLine(),
342 "Expected loop index", symbol->getSymbol().c_str());
343 return false;
344 }
345 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800346 switch (binOp->getOp())
347 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000348 case EOpEqual:
349 case EOpNotEqual:
350 case EOpLessThan:
351 case EOpGreaterThan:
352 case EOpLessThanEqual:
353 case EOpGreaterThanEqual:
354 break;
355 default:
356 error(binOp->getLine(),
357 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700358 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000359 break;
360 }
361 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800362 if (!isConstExpr(binOp->getRight()))
363 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000364 error(binOp->getLine(),
365 "Loop index cannot be compared with non-constant expression",
366 symbol->getSymbol().c_str());
367 return false;
368 }
369
370 return true;
371}
372
Zhenyao Mo550c6002014-02-26 15:40:48 -0800373bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
374 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000375{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800376 TIntermNode *expr = node->getExpression();
377 if (expr == NULL)
378 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000379 error(node->getLine(), "Missing expression", "for");
380 return false;
381 }
382
383 // for expression has one of the following forms:
384 // loop_index++
385 // loop_index--
386 // loop_index += constant_expression
387 // loop_index -= constant_expression
388 // ++loop_index
389 // --loop_index
390 // The last two forms are not specified in the spec, but I am assuming
391 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800392 TIntermUnary *unOp = expr->getAsUnaryNode();
393 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000394
395 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800396 TIntermSymbol *symbol = NULL;
397 if (unOp != NULL)
398 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000399 op = unOp->getOp();
400 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800401 }
402 else if (binOp != NULL)
403 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000404 op = binOp->getOp();
405 symbol = binOp->getLeft()->getAsSymbolNode();
406 }
407
408 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800409 if (symbol == NULL)
410 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000411 error(expr->getLine(), "Invalid expression", "for");
412 return false;
413 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800414 if (symbol->getId() != indexSymbolId)
415 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000416 error(symbol->getLine(),
417 "Expected loop index", symbol->getSymbol().c_str());
418 return false;
419 }
420
421 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800422 switch (op)
423 {
424 case EOpPostIncrement:
425 case EOpPostDecrement:
426 case EOpPreIncrement:
427 case EOpPreDecrement:
428 ASSERT((unOp != NULL) && (binOp == NULL));
429 break;
430 case EOpAddAssign:
431 case EOpSubAssign:
432 ASSERT((unOp == NULL) && (binOp != NULL));
433 break;
434 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700435 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800436 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000437 }
438
439 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800440 if (binOp != NULL)
441 {
442 if (!isConstExpr(binOp->getRight()))
443 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000444 error(binOp->getLine(),
445 "Loop index cannot be modified by non-constant expression",
446 symbol->getSymbol().c_str());
447 return false;
448 }
449 }
450
451 return true;
452}
453
Zhenyao Mo550c6002014-02-26 15:40:48 -0800454bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000455{
456 ASSERT(node->getOp() == EOpFunctionCall);
457
458 // If not within loop body, there is nothing to check.
459 if (!withinLoopBody())
460 return true;
461
462 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000463 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000464 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700465 TIntermSequence *params = node->getSequence();
466 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800467 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700468 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000469 if (symbol && isLoopIndex(symbol))
470 pIndex.push_back(i);
471 }
472 // If none of the loop indices are used as arguments,
473 // there is nothing to check.
474 if (pIndex.empty())
475 return true;
476
477 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400478 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
479 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000480 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800481 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000482 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800483 i != pIndex.end(); ++i)
484 {
485 const TParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000486 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800487 if ((qual == EvqOut) || (qual == EvqInOut))
488 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700489 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000490 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700491 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000492 valid = false;
493 }
494 }
495
496 return valid;
497}
498
Zhenyao Mo550c6002014-02-26 15:40:48 -0800499bool ValidateLimitations::validateOperation(TIntermOperator *node,
500 TIntermNode* operand)
501{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000502 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500503 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000504 return true;
505
Zhenyao Mo550c6002014-02-26 15:40:48 -0800506 TIntermSymbol *symbol = operand->getAsSymbolNode();
507 if (symbol && isLoopIndex(symbol))
508 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000509 error(node->getLine(),
510 "Loop index cannot be statically assigned to within the body of the loop",
511 symbol->getSymbol().c_str());
512 }
513 return true;
514}
515
Zhenyao Mo550c6002014-02-26 15:40:48 -0800516bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000517{
518 ASSERT(node != NULL);
519 return node->getAsConstantUnion() != NULL;
520}
521
Zhenyao Mo550c6002014-02-26 15:40:48 -0800522bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000523{
524 ASSERT(node != NULL);
525
526 ValidateConstIndexExpr validate(mLoopStack);
527 node->traverse(&validate);
528 return validate.isValid();
529}
530
Zhenyao Mo550c6002014-02-26 15:40:48 -0800531bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000532{
533 ASSERT((node->getOp() == EOpIndexDirect) ||
534 (node->getOp() == EOpIndexIndirect));
535
536 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800537 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000538 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000539 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000540 error(index->getLine(),
541 "Index expression must have integral type",
542 index->getCompleteString().c_str());
543 valid = false;
544 }
545 // The index expession must be a constant-index-expression unless
546 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800547 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400548 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000549 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800550 if (!skip && !isConstIndexExpr(index))
551 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000552 error(index->getLine(), "Index expression must be constant", "[]");
553 valid = false;
554 }
555 return valid;
556}
557