blob: 12367066e8ef90c12f4c1e597535c965dd0e6f0b [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
50} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000051
Jamie Madill183bde52014-07-02 15:31:19 -040052ValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
Zhenyao Mo550c6002014-02-26 15:40:48 -080053 TInfoSinkBase &sink)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000054 : mShaderType(shaderType),
55 mSink(sink),
56 mNumErrors(0)
57{
58}
59
Zhenyao Mo550c6002014-02-26 15:40:48 -080060bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000061{
62 // Check if loop index is modified in the loop body.
63 validateOperation(node, node->getLeft());
64
65 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -080066 switch (node->getOp())
67 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000068 case EOpIndexDirect:
69 case EOpIndexIndirect:
70 validateIndexing(node);
71 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -080072 default:
73 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000074 }
75 return true;
76}
77
Zhenyao Mo550c6002014-02-26 15:40:48 -080078bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000079{
80 // Check if loop index is modified in the loop body.
81 validateOperation(node, node->getOperand());
82
83 return true;
84}
85
Zhenyao Mo550c6002014-02-26 15:40:48 -080086bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000087{
88 switch (node->getOp()) {
89 case EOpFunctionCall:
90 validateFunctionCall(node);
91 break;
92 default:
93 break;
94 }
95 return true;
96}
97
Zhenyao Mo550c6002014-02-26 15:40:48 -080098bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000099{
100 if (!validateLoopType(node))
101 return false;
102
Zhenyao Mo550c6002014-02-26 15:40:48 -0800103 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000104 return false;
105
Zhenyao Mo550c6002014-02-26 15:40:48 -0800106 TIntermNode *body = node->getBody();
107 if (body != NULL)
108 {
109 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000110 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800111 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000112 }
113
114 // The loop is fully processed - no need to visit children.
115 return false;
116}
117
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000118void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800119 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000120{
121 mSink.prefix(EPrefixError);
122 mSink.location(loc);
123 mSink << "'" << token << "' : " << reason << "\n";
124 ++mNumErrors;
125}
126
127bool ValidateLimitations::withinLoopBody() const
128{
129 return !mLoopStack.empty();
130}
131
Zhenyao Mo550c6002014-02-26 15:40:48 -0800132bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000133{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800134 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000135}
136
Zhenyao Mo550c6002014-02-26 15:40:48 -0800137bool ValidateLimitations::validateLoopType(TIntermLoop *node)
138{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000139 TLoopType type = node->getType();
140 if (type == ELoopFor)
141 return true;
142
143 // Reject while and do-while loops.
144 error(node->getLine(),
145 "This type of loop is not allowed",
146 type == ELoopWhile ? "while" : "do");
147 return false;
148}
149
Zhenyao Mo550c6002014-02-26 15:40:48 -0800150bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000151{
152 ASSERT(node->getType() == ELoopFor);
153
154 //
155 // The for statement has the form:
156 // for ( init-declaration ; condition ; expression ) statement
157 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800158 int indexSymbolId = validateForLoopInit(node);
159 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000160 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800161 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000162 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800163 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000164 return false;
165
166 return true;
167}
168
Zhenyao Mo550c6002014-02-26 15:40:48 -0800169int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000170{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800171 TIntermNode *init = node->getInit();
172 if (init == NULL)
173 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000174 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800175 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000176 }
177
178 //
179 // init-declaration has the form:
180 // type-specifier identifier = constant-expression
181 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800182 TIntermAggregate *decl = init->getAsAggregate();
183 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
184 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000185 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800186 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000187 }
188 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700189 TIntermSequence *declSeq = decl->getSequence();
190 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800191 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000192 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800193 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000194 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700195 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800196 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
197 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000198 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800199 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000200 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800201 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
202 if (symbol == NULL)
203 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000204 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800205 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000206 }
207 // The loop index has type int or float.
208 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000209 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000210 error(symbol->getLine(),
211 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800212 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000213 }
214 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800215 if (!isConstExpr(declInit->getRight()))
216 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000217 error(declInit->getLine(),
218 "Loop index cannot be initialized with non-constant expression",
219 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800220 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000221 }
222
Zhenyao Mo550c6002014-02-26 15:40:48 -0800223 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000224}
225
Zhenyao Mo550c6002014-02-26 15:40:48 -0800226bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
227 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000228{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800229 TIntermNode *cond = node->getCondition();
230 if (cond == NULL)
231 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000232 error(node->getLine(), "Missing condition", "for");
233 return false;
234 }
235 //
236 // condition has the form:
237 // loop_index relational_operator constant_expression
238 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800239 TIntermBinary *binOp = cond->getAsBinaryNode();
240 if (binOp == NULL)
241 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000242 error(node->getLine(), "Invalid condition", "for");
243 return false;
244 }
245 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800246 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
247 if (symbol == NULL)
248 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000249 error(binOp->getLine(), "Invalid condition", "for");
250 return false;
251 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800252 if (symbol->getId() != indexSymbolId)
253 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000254 error(symbol->getLine(),
255 "Expected loop index", symbol->getSymbol().c_str());
256 return false;
257 }
258 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800259 switch (binOp->getOp())
260 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000261 case EOpEqual:
262 case EOpNotEqual:
263 case EOpLessThan:
264 case EOpGreaterThan:
265 case EOpLessThanEqual:
266 case EOpGreaterThanEqual:
267 break;
268 default:
269 error(binOp->getLine(),
270 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700271 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000272 break;
273 }
274 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800275 if (!isConstExpr(binOp->getRight()))
276 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000277 error(binOp->getLine(),
278 "Loop index cannot be compared with non-constant expression",
279 symbol->getSymbol().c_str());
280 return false;
281 }
282
283 return true;
284}
285
Zhenyao Mo550c6002014-02-26 15:40:48 -0800286bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
287 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000288{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800289 TIntermNode *expr = node->getExpression();
290 if (expr == NULL)
291 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000292 error(node->getLine(), "Missing expression", "for");
293 return false;
294 }
295
296 // for expression has one of the following forms:
297 // loop_index++
298 // loop_index--
299 // loop_index += constant_expression
300 // loop_index -= constant_expression
301 // ++loop_index
302 // --loop_index
303 // The last two forms are not specified in the spec, but I am assuming
304 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800305 TIntermUnary *unOp = expr->getAsUnaryNode();
306 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000307
308 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800309 TIntermSymbol *symbol = NULL;
310 if (unOp != NULL)
311 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000312 op = unOp->getOp();
313 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800314 }
315 else if (binOp != NULL)
316 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000317 op = binOp->getOp();
318 symbol = binOp->getLeft()->getAsSymbolNode();
319 }
320
321 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800322 if (symbol == NULL)
323 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000324 error(expr->getLine(), "Invalid expression", "for");
325 return false;
326 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800327 if (symbol->getId() != indexSymbolId)
328 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000329 error(symbol->getLine(),
330 "Expected loop index", symbol->getSymbol().c_str());
331 return false;
332 }
333
334 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800335 switch (op)
336 {
337 case EOpPostIncrement:
338 case EOpPostDecrement:
339 case EOpPreIncrement:
340 case EOpPreDecrement:
341 ASSERT((unOp != NULL) && (binOp == NULL));
342 break;
343 case EOpAddAssign:
344 case EOpSubAssign:
345 ASSERT((unOp == NULL) && (binOp != NULL));
346 break;
347 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700348 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800349 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000350 }
351
352 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800353 if (binOp != NULL)
354 {
355 if (!isConstExpr(binOp->getRight()))
356 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000357 error(binOp->getLine(),
358 "Loop index cannot be modified by non-constant expression",
359 symbol->getSymbol().c_str());
360 return false;
361 }
362 }
363
364 return true;
365}
366
Zhenyao Mo550c6002014-02-26 15:40:48 -0800367bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000368{
369 ASSERT(node->getOp() == EOpFunctionCall);
370
371 // If not within loop body, there is nothing to check.
372 if (!withinLoopBody())
373 return true;
374
375 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000376 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000377 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700378 TIntermSequence *params = node->getSequence();
379 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800380 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700381 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000382 if (symbol && isLoopIndex(symbol))
383 pIndex.push_back(i);
384 }
385 // If none of the loop indices are used as arguments,
386 // there is nothing to check.
387 if (pIndex.empty())
388 return true;
389
390 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400391 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
Jamie Madill749fe342015-05-13 21:07:55 +0000392 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000393 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800394 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000395 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800396 i != pIndex.end(); ++i)
397 {
398 const TParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000399 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800400 if ((qual == EvqOut) || (qual == EvqInOut))
401 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700402 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000403 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700404 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000405 valid = false;
406 }
407 }
408
409 return valid;
410}
411
Zhenyao Mo550c6002014-02-26 15:40:48 -0800412bool ValidateLimitations::validateOperation(TIntermOperator *node,
413 TIntermNode* operand)
414{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000415 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500416 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000417 return true;
418
Zhenyao Mo550c6002014-02-26 15:40:48 -0800419 TIntermSymbol *symbol = operand->getAsSymbolNode();
420 if (symbol && isLoopIndex(symbol))
421 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000422 error(node->getLine(),
423 "Loop index cannot be statically assigned to within the body of the loop",
424 symbol->getSymbol().c_str());
425 }
426 return true;
427}
428
Zhenyao Mo550c6002014-02-26 15:40:48 -0800429bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000430{
431 ASSERT(node != NULL);
432 return node->getAsConstantUnion() != NULL;
433}
434
Zhenyao Mo550c6002014-02-26 15:40:48 -0800435bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000436{
437 ASSERT(node != NULL);
438
439 ValidateConstIndexExpr validate(mLoopStack);
440 node->traverse(&validate);
441 return validate.isValid();
442}
443
Zhenyao Mo550c6002014-02-26 15:40:48 -0800444bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000445{
446 ASSERT((node->getOp() == EOpIndexDirect) ||
447 (node->getOp() == EOpIndexIndirect));
448
449 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800450 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000451 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000452 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000453 error(index->getLine(),
454 "Index expression must have integral type",
455 index->getCompleteString().c_str());
456 valid = false;
457 }
458 // The index expession must be a constant-index-expression unless
459 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800460 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400461 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000462 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800463 if (!skip && !isConstIndexExpr(index))
464 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000465 error(index->getLine(), "Index expression must be constant", "[]");
466 valid = false;
467 }
468 return valid;
469}
470