blob: e96a777cee3e53071c9d15496e87726753734c0a [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"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000011
Zhenyao Mo550c6002014-02-26 15:40:48 -080012namespace
13{
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000014
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000015// Traverses a node to check if it represents a constant index expression.
16// Definition:
17// constant-index-expressions are a superset of constant-expressions.
18// Constant-index-expressions can include loop indices as defined in
19// GLSL ES 1.0 spec, Appendix A, section 4.
20// The following are constant-index-expressions:
21// - Constant expressions
22// - Loop indices as defined in section 4
23// - Expressions composed of both of the above
Zhenyao Mo550c6002014-02-26 15:40:48 -080024class ValidateConstIndexExpr : public TIntermTraverser
25{
26 public:
27 ValidateConstIndexExpr(TLoopStack& stack)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000028 : mValid(true), mLoopStack(stack) {}
29
30 // Returns true if the parsed node represents a constant index expression.
31 bool isValid() const { return mValid; }
32
Zhenyao Mo550c6002014-02-26 15:40:48 -080033 virtual void visitSymbol(TIntermSymbol *symbol)
34 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000035 // Only constants and loop indices are allowed in a
36 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080037 if (mValid)
38 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000039 mValid = (symbol->getQualifier() == EvqConst) ||
Zhenyao Mo550c6002014-02-26 15:40:48 -080040 (mLoopStack.findLoop(symbol));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000041 }
42 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000043
Zhenyao Mo550c6002014-02-26 15:40:48 -080044 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000045 bool mValid;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000046 TLoopStack& mLoopStack;
47};
Zhenyao Mo550c6002014-02-26 15:40:48 -080048
49} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000050
51ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
Zhenyao Mo550c6002014-02-26 15:40:48 -080052 TInfoSinkBase &sink)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000053 : mShaderType(shaderType),
54 mSink(sink),
55 mNumErrors(0)
56{
57}
58
Zhenyao Mo550c6002014-02-26 15:40:48 -080059bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000060{
61 // Check if loop index is modified in the loop body.
62 validateOperation(node, node->getLeft());
63
64 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -080065 switch (node->getOp())
66 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000067 case EOpIndexDirect:
68 case EOpIndexIndirect:
69 validateIndexing(node);
70 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -080071 default:
72 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000073 }
74 return true;
75}
76
Zhenyao Mo550c6002014-02-26 15:40:48 -080077bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000078{
79 // Check if loop index is modified in the loop body.
80 validateOperation(node, node->getOperand());
81
82 return true;
83}
84
Zhenyao Mo550c6002014-02-26 15:40:48 -080085bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000086{
87 switch (node->getOp()) {
88 case EOpFunctionCall:
89 validateFunctionCall(node);
90 break;
91 default:
92 break;
93 }
94 return true;
95}
96
Zhenyao Mo550c6002014-02-26 15:40:48 -080097bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000098{
99 if (!validateLoopType(node))
100 return false;
101
Zhenyao Mo550c6002014-02-26 15:40:48 -0800102 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000103 return false;
104
Zhenyao Mo550c6002014-02-26 15:40:48 -0800105 TIntermNode *body = node->getBody();
106 if (body != NULL)
107 {
108 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000109 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800110 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000111 }
112
113 // The loop is fully processed - no need to visit children.
114 return false;
115}
116
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000117void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800118 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000119{
120 mSink.prefix(EPrefixError);
121 mSink.location(loc);
122 mSink << "'" << token << "' : " << reason << "\n";
123 ++mNumErrors;
124}
125
126bool ValidateLimitations::withinLoopBody() const
127{
128 return !mLoopStack.empty();
129}
130
Zhenyao Mo550c6002014-02-26 15:40:48 -0800131bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000132{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800133 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000134}
135
Zhenyao Mo550c6002014-02-26 15:40:48 -0800136bool ValidateLimitations::validateLoopType(TIntermLoop *node)
137{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000138 TLoopType type = node->getType();
139 if (type == ELoopFor)
140 return true;
141
142 // Reject while and do-while loops.
143 error(node->getLine(),
144 "This type of loop is not allowed",
145 type == ELoopWhile ? "while" : "do");
146 return false;
147}
148
Zhenyao Mo550c6002014-02-26 15:40:48 -0800149bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000150{
151 ASSERT(node->getType() == ELoopFor);
152
153 //
154 // The for statement has the form:
155 // for ( init-declaration ; condition ; expression ) statement
156 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800157 int indexSymbolId = validateForLoopInit(node);
158 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000159 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800160 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000161 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800162 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000163 return false;
164
165 return true;
166}
167
Zhenyao Mo550c6002014-02-26 15:40:48 -0800168int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000169{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800170 TIntermNode *init = node->getInit();
171 if (init == NULL)
172 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000173 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800174 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000175 }
176
177 //
178 // init-declaration has the form:
179 // type-specifier identifier = constant-expression
180 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800181 TIntermAggregate *decl = init->getAsAggregate();
182 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
183 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000184 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800185 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000186 }
187 // To keep things simple do not allow declaration list.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800188 TIntermSequence &declSeq = decl->getSequence();
189 if (declSeq.size() != 1)
190 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000191 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800192 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000193 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800194 TIntermBinary *declInit = declSeq[0]->getAsBinaryNode();
195 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
196 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000197 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800198 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000199 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800200 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
201 if (symbol == NULL)
202 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000203 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800204 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000205 }
206 // The loop index has type int or float.
207 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000208 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000209 error(symbol->getLine(),
210 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800211 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000212 }
213 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800214 if (!isConstExpr(declInit->getRight()))
215 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000216 error(declInit->getLine(),
217 "Loop index cannot be initialized with non-constant expression",
218 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800219 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000220 }
221
Zhenyao Mo550c6002014-02-26 15:40:48 -0800222 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000223}
224
Zhenyao Mo550c6002014-02-26 15:40:48 -0800225bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
226 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000227{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800228 TIntermNode *cond = node->getCondition();
229 if (cond == NULL)
230 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000231 error(node->getLine(), "Missing condition", "for");
232 return false;
233 }
234 //
235 // condition has the form:
236 // loop_index relational_operator constant_expression
237 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800238 TIntermBinary *binOp = cond->getAsBinaryNode();
239 if (binOp == NULL)
240 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000241 error(node->getLine(), "Invalid condition", "for");
242 return false;
243 }
244 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800245 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
246 if (symbol == NULL)
247 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000248 error(binOp->getLine(), "Invalid condition", "for");
249 return false;
250 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800251 if (symbol->getId() != indexSymbolId)
252 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000253 error(symbol->getLine(),
254 "Expected loop index", symbol->getSymbol().c_str());
255 return false;
256 }
257 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800258 switch (binOp->getOp())
259 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000260 case EOpEqual:
261 case EOpNotEqual:
262 case EOpLessThan:
263 case EOpGreaterThan:
264 case EOpLessThanEqual:
265 case EOpGreaterThanEqual:
266 break;
267 default:
268 error(binOp->getLine(),
269 "Invalid relational operator",
270 getOperatorString(binOp->getOp()));
271 break;
272 }
273 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800274 if (!isConstExpr(binOp->getRight()))
275 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000276 error(binOp->getLine(),
277 "Loop index cannot be compared with non-constant expression",
278 symbol->getSymbol().c_str());
279 return false;
280 }
281
282 return true;
283}
284
Zhenyao Mo550c6002014-02-26 15:40:48 -0800285bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
286 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000287{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800288 TIntermNode *expr = node->getExpression();
289 if (expr == NULL)
290 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000291 error(node->getLine(), "Missing expression", "for");
292 return false;
293 }
294
295 // for expression has one of the following forms:
296 // loop_index++
297 // loop_index--
298 // loop_index += constant_expression
299 // loop_index -= constant_expression
300 // ++loop_index
301 // --loop_index
302 // The last two forms are not specified in the spec, but I am assuming
303 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800304 TIntermUnary *unOp = expr->getAsUnaryNode();
305 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000306
307 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800308 TIntermSymbol *symbol = NULL;
309 if (unOp != NULL)
310 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000311 op = unOp->getOp();
312 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800313 }
314 else if (binOp != NULL)
315 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000316 op = binOp->getOp();
317 symbol = binOp->getLeft()->getAsSymbolNode();
318 }
319
320 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800321 if (symbol == NULL)
322 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000323 error(expr->getLine(), "Invalid expression", "for");
324 return false;
325 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800326 if (symbol->getId() != indexSymbolId)
327 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000328 error(symbol->getLine(),
329 "Expected loop index", symbol->getSymbol().c_str());
330 return false;
331 }
332
333 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800334 switch (op)
335 {
336 case EOpPostIncrement:
337 case EOpPostDecrement:
338 case EOpPreIncrement:
339 case EOpPreDecrement:
340 ASSERT((unOp != NULL) && (binOp == NULL));
341 break;
342 case EOpAddAssign:
343 case EOpSubAssign:
344 ASSERT((unOp == NULL) && (binOp != NULL));
345 break;
346 default:
347 error(expr->getLine(), "Invalid operator", getOperatorString(op));
348 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000349 }
350
351 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800352 if (binOp != NULL)
353 {
354 if (!isConstExpr(binOp->getRight()))
355 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000356 error(binOp->getLine(),
357 "Loop index cannot be modified by non-constant expression",
358 symbol->getSymbol().c_str());
359 return false;
360 }
361 }
362
363 return true;
364}
365
Zhenyao Mo550c6002014-02-26 15:40:48 -0800366bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000367{
368 ASSERT(node->getOp() == EOpFunctionCall);
369
370 // If not within loop body, there is nothing to check.
371 if (!withinLoopBody())
372 return true;
373
374 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000375 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000376 ParamIndex pIndex;
377 TIntermSequence& params = node->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800378 for (TIntermSequence::size_type i = 0; i < params.size(); ++i)
379 {
380 TIntermSymbol *symbol = params[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000381 if (symbol && isLoopIndex(symbol))
382 pIndex.push_back(i);
383 }
384 // If none of the loop indices are used as arguments,
385 // there is nothing to check.
386 if (pIndex.empty())
387 return true;
388
389 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400390 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
391 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000392 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800393 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000394 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800395 i != pIndex.end(); ++i)
396 {
397 const TParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000398 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800399 if ((qual == EvqOut) || (qual == EvqInOut))
400 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000401 error(params[*i]->getLine(),
402 "Loop index cannot be used as argument to a function out or inout parameter",
403 params[*i]->getAsSymbolNode()->getSymbol().c_str());
404 valid = false;
405 }
406 }
407
408 return valid;
409}
410
Zhenyao Mo550c6002014-02-26 15:40:48 -0800411bool ValidateLimitations::validateOperation(TIntermOperator *node,
412 TIntermNode* operand)
413{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000414 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500415 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000416 return true;
417
Zhenyao Mo550c6002014-02-26 15:40:48 -0800418 TIntermSymbol *symbol = operand->getAsSymbolNode();
419 if (symbol && isLoopIndex(symbol))
420 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000421 error(node->getLine(),
422 "Loop index cannot be statically assigned to within the body of the loop",
423 symbol->getSymbol().c_str());
424 }
425 return true;
426}
427
Zhenyao Mo550c6002014-02-26 15:40:48 -0800428bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000429{
430 ASSERT(node != NULL);
431 return node->getAsConstantUnion() != NULL;
432}
433
Zhenyao Mo550c6002014-02-26 15:40:48 -0800434bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000435{
436 ASSERT(node != NULL);
437
438 ValidateConstIndexExpr validate(mLoopStack);
439 node->traverse(&validate);
440 return validate.isValid();
441}
442
Zhenyao Mo550c6002014-02-26 15:40:48 -0800443bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000444{
445 ASSERT((node->getOp() == EOpIndexDirect) ||
446 (node->getOp() == EOpIndexIndirect));
447
448 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800449 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000450 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000451 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000452 error(index->getLine(),
453 "Index expression must have integral type",
454 index->getCompleteString().c_str());
455 valid = false;
456 }
457 // The index expession must be a constant-index-expression unless
458 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800459 TIntermTyped *operand = node->getLeft();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000460 bool skip = (mShaderType == SH_VERTEX_SHADER) &&
461 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800462 if (!skip && !isConstIndexExpr(index))
463 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000464 error(index->getLine(), "Index expression must be constant", "[]");
465 valid = false;
466 }
467 return valid;
468}
469