blob: c1a7b7524f1dc4bc5b26fe26569ed605489a2fa0 [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 "-";
97 case EOpVectorLogicalNot: return "not";
98 case EOpLogicalNot: return "!";
99 case EOpPostIncrement: return "++";
100 case EOpPostDecrement: return "--";
101 case EOpPreIncrement: return "++";
102 case EOpPreDecrement: return "--";
103
104 case EOpRadians: return "radians";
105 case EOpDegrees: return "degrees";
106 case EOpSin: return "sin";
107 case EOpCos: return "cos";
108 case EOpTan: return "tan";
109 case EOpAsin: return "asin";
110 case EOpAcos: return "acos";
111 case EOpAtan: return "atan";
112 case EOpExp: return "exp";
113 case EOpLog: return "log";
114 case EOpExp2: return "exp2";
115 case EOpLog2: return "log2";
116 case EOpSqrt: return "sqrt";
117 case EOpInverseSqrt: return "inversesqrt";
118 case EOpAbs: return "abs";
119 case EOpSign: return "sign";
120 case EOpFloor: return "floor";
121 case EOpCeil: return "ceil";
122 case EOpFract: return "fract";
123 case EOpLength: return "length";
124 case EOpNormalize: return "normalize";
125 case EOpDFdx: return "dFdx";
126 case EOpDFdy: return "dFdy";
127 case EOpFwidth: return "fwidth";
128 case EOpAny: return "any";
129 case EOpAll: return "all";
130
131 default: break;
132 }
133 return "";
134}
135
Zhenyao Mo550c6002014-02-26 15:40:48 -0800136} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000137
Jamie Madill183bde52014-07-02 15:31:19 -0400138ValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800139 TInfoSinkBase &sink)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000140 : mShaderType(shaderType),
141 mSink(sink),
142 mNumErrors(0)
143{
144}
145
Zhenyao Mo550c6002014-02-26 15:40:48 -0800146bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000147{
148 // Check if loop index is modified in the loop body.
149 validateOperation(node, node->getLeft());
150
151 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800152 switch (node->getOp())
153 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000154 case EOpIndexDirect:
155 case EOpIndexIndirect:
156 validateIndexing(node);
157 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800158 default:
159 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000160 }
161 return true;
162}
163
Zhenyao Mo550c6002014-02-26 15:40:48 -0800164bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000165{
166 // Check if loop index is modified in the loop body.
167 validateOperation(node, node->getOperand());
168
169 return true;
170}
171
Zhenyao Mo550c6002014-02-26 15:40:48 -0800172bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000173{
174 switch (node->getOp()) {
175 case EOpFunctionCall:
176 validateFunctionCall(node);
177 break;
178 default:
179 break;
180 }
181 return true;
182}
183
Zhenyao Mo550c6002014-02-26 15:40:48 -0800184bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000185{
186 if (!validateLoopType(node))
187 return false;
188
Zhenyao Mo550c6002014-02-26 15:40:48 -0800189 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000190 return false;
191
Zhenyao Mo550c6002014-02-26 15:40:48 -0800192 TIntermNode *body = node->getBody();
193 if (body != NULL)
194 {
195 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000196 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800197 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000198 }
199
200 // The loop is fully processed - no need to visit children.
201 return false;
202}
203
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000204void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800205 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000206{
207 mSink.prefix(EPrefixError);
208 mSink.location(loc);
209 mSink << "'" << token << "' : " << reason << "\n";
210 ++mNumErrors;
211}
212
213bool ValidateLimitations::withinLoopBody() const
214{
215 return !mLoopStack.empty();
216}
217
Zhenyao Mo550c6002014-02-26 15:40:48 -0800218bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000219{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800220 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000221}
222
Zhenyao Mo550c6002014-02-26 15:40:48 -0800223bool ValidateLimitations::validateLoopType(TIntermLoop *node)
224{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000225 TLoopType type = node->getType();
226 if (type == ELoopFor)
227 return true;
228
229 // Reject while and do-while loops.
230 error(node->getLine(),
231 "This type of loop is not allowed",
232 type == ELoopWhile ? "while" : "do");
233 return false;
234}
235
Zhenyao Mo550c6002014-02-26 15:40:48 -0800236bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000237{
238 ASSERT(node->getType() == ELoopFor);
239
240 //
241 // The for statement has the form:
242 // for ( init-declaration ; condition ; expression ) statement
243 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800244 int indexSymbolId = validateForLoopInit(node);
245 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000246 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800247 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000248 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800249 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000250 return false;
251
252 return true;
253}
254
Zhenyao Mo550c6002014-02-26 15:40:48 -0800255int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000256{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257 TIntermNode *init = node->getInit();
258 if (init == NULL)
259 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000260 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800261 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000262 }
263
264 //
265 // init-declaration has the form:
266 // type-specifier identifier = constant-expression
267 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800268 TIntermAggregate *decl = init->getAsAggregate();
269 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
270 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000271 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800272 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000273 }
274 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700275 TIntermSequence *declSeq = decl->getSequence();
276 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800277 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000278 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800279 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000280 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700281 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800282 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
283 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000284 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800285 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000286 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800287 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
288 if (symbol == NULL)
289 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000290 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800291 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000292 }
293 // The loop index has type int or float.
294 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000295 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000296 error(symbol->getLine(),
297 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800298 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000299 }
300 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800301 if (!isConstExpr(declInit->getRight()))
302 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000303 error(declInit->getLine(),
304 "Loop index cannot be initialized with non-constant expression",
305 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800306 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000307 }
308
Zhenyao Mo550c6002014-02-26 15:40:48 -0800309 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000310}
311
Zhenyao Mo550c6002014-02-26 15:40:48 -0800312bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
313 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000314{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800315 TIntermNode *cond = node->getCondition();
316 if (cond == NULL)
317 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000318 error(node->getLine(), "Missing condition", "for");
319 return false;
320 }
321 //
322 // condition has the form:
323 // loop_index relational_operator constant_expression
324 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800325 TIntermBinary *binOp = cond->getAsBinaryNode();
326 if (binOp == NULL)
327 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000328 error(node->getLine(), "Invalid condition", "for");
329 return false;
330 }
331 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800332 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
333 if (symbol == NULL)
334 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000335 error(binOp->getLine(), "Invalid condition", "for");
336 return false;
337 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800338 if (symbol->getId() != indexSymbolId)
339 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000340 error(symbol->getLine(),
341 "Expected loop index", symbol->getSymbol().c_str());
342 return false;
343 }
344 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800345 switch (binOp->getOp())
346 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000347 case EOpEqual:
348 case EOpNotEqual:
349 case EOpLessThan:
350 case EOpGreaterThan:
351 case EOpLessThanEqual:
352 case EOpGreaterThanEqual:
353 break;
354 default:
355 error(binOp->getLine(),
356 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700357 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000358 break;
359 }
360 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800361 if (!isConstExpr(binOp->getRight()))
362 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000363 error(binOp->getLine(),
364 "Loop index cannot be compared with non-constant expression",
365 symbol->getSymbol().c_str());
366 return false;
367 }
368
369 return true;
370}
371
Zhenyao Mo550c6002014-02-26 15:40:48 -0800372bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
373 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000374{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800375 TIntermNode *expr = node->getExpression();
376 if (expr == NULL)
377 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000378 error(node->getLine(), "Missing expression", "for");
379 return false;
380 }
381
382 // for expression has one of the following forms:
383 // loop_index++
384 // loop_index--
385 // loop_index += constant_expression
386 // loop_index -= constant_expression
387 // ++loop_index
388 // --loop_index
389 // The last two forms are not specified in the spec, but I am assuming
390 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800391 TIntermUnary *unOp = expr->getAsUnaryNode();
392 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000393
394 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800395 TIntermSymbol *symbol = NULL;
396 if (unOp != NULL)
397 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000398 op = unOp->getOp();
399 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800400 }
401 else if (binOp != NULL)
402 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000403 op = binOp->getOp();
404 symbol = binOp->getLeft()->getAsSymbolNode();
405 }
406
407 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800408 if (symbol == NULL)
409 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000410 error(expr->getLine(), "Invalid expression", "for");
411 return false;
412 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800413 if (symbol->getId() != indexSymbolId)
414 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000415 error(symbol->getLine(),
416 "Expected loop index", symbol->getSymbol().c_str());
417 return false;
418 }
419
420 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800421 switch (op)
422 {
423 case EOpPostIncrement:
424 case EOpPostDecrement:
425 case EOpPreIncrement:
426 case EOpPreDecrement:
427 ASSERT((unOp != NULL) && (binOp == NULL));
428 break;
429 case EOpAddAssign:
430 case EOpSubAssign:
431 ASSERT((unOp == NULL) && (binOp != NULL));
432 break;
433 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700434 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800435 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000436 }
437
438 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800439 if (binOp != NULL)
440 {
441 if (!isConstExpr(binOp->getRight()))
442 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000443 error(binOp->getLine(),
444 "Loop index cannot be modified by non-constant expression",
445 symbol->getSymbol().c_str());
446 return false;
447 }
448 }
449
450 return true;
451}
452
Zhenyao Mo550c6002014-02-26 15:40:48 -0800453bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000454{
455 ASSERT(node->getOp() == EOpFunctionCall);
456
457 // If not within loop body, there is nothing to check.
458 if (!withinLoopBody())
459 return true;
460
461 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000462 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000463 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700464 TIntermSequence *params = node->getSequence();
465 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800466 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700467 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000468 if (symbol && isLoopIndex(symbol))
469 pIndex.push_back(i);
470 }
471 // If none of the loop indices are used as arguments,
472 // there is nothing to check.
473 if (pIndex.empty())
474 return true;
475
476 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400477 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
478 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000479 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800480 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000481 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800482 i != pIndex.end(); ++i)
483 {
484 const TParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000485 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800486 if ((qual == EvqOut) || (qual == EvqInOut))
487 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700488 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000489 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700490 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000491 valid = false;
492 }
493 }
494
495 return valid;
496}
497
Zhenyao Mo550c6002014-02-26 15:40:48 -0800498bool ValidateLimitations::validateOperation(TIntermOperator *node,
499 TIntermNode* operand)
500{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000501 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500502 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000503 return true;
504
Zhenyao Mo550c6002014-02-26 15:40:48 -0800505 TIntermSymbol *symbol = operand->getAsSymbolNode();
506 if (symbol && isLoopIndex(symbol))
507 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000508 error(node->getLine(),
509 "Loop index cannot be statically assigned to within the body of the loop",
510 symbol->getSymbol().c_str());
511 }
512 return true;
513}
514
Zhenyao Mo550c6002014-02-26 15:40:48 -0800515bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000516{
517 ASSERT(node != NULL);
518 return node->getAsConstantUnion() != NULL;
519}
520
Zhenyao Mo550c6002014-02-26 15:40:48 -0800521bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000522{
523 ASSERT(node != NULL);
524
525 ValidateConstIndexExpr validate(mLoopStack);
526 node->traverse(&validate);
527 return validate.isValid();
528}
529
Zhenyao Mo550c6002014-02-26 15:40:48 -0800530bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000531{
532 ASSERT((node->getOp() == EOpIndexDirect) ||
533 (node->getOp() == EOpIndexIndirect));
534
535 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800536 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000537 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000538 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000539 error(index->getLine(),
540 "Index expression must have integral type",
541 index->getCompleteString().c_str());
542 valid = false;
543 }
544 // The index expession must be a constant-index-expression unless
545 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800546 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400547 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000548 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800549 if (!skip && !isConstIndexExpr(index))
550 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000551 error(index->getLine(), "Index expression must be constant", "[]");
552 valid = false;
553 }
554 return valid;
555}
556