blob: ed60c3755ec48c7279765232db7413445d4c7db8 [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)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030029 : TIntermTraverser(true, false, false),
30 mValid(true),
31 mLoopStack(stack)
32 {
33 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000034
35 // Returns true if the parsed node represents a constant index expression.
36 bool isValid() const { return mValid; }
37
Corentin Walleze5a1f272015-08-21 02:58:25 +020038 void visitSymbol(TIntermSymbol *symbol) override
Zhenyao Mo550c6002014-02-26 15:40:48 -080039 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000040 // Only constants and loop indices are allowed in a
41 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080042 if (mValid)
43 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000044 mValid = (symbol->getQualifier() == EvqConst) ||
Zhenyao Mo550c6002014-02-26 15:40:48 -080045 (mLoopStack.findLoop(symbol));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000046 }
47 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000048
Zhenyao Mo550c6002014-02-26 15:40:48 -080049 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000050 bool mValid;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000051 TLoopStack& mLoopStack;
52};
Zhenyao Mo550c6002014-02-26 15:40:48 -080053
54} // namespace anonymous
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000055
Jamie Madill183bde52014-07-02 15:31:19 -040056ValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
Zhenyao Mo550c6002014-02-26 15:40:48 -080057 TInfoSinkBase &sink)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030058 : TIntermTraverser(true, false, false),
59 mShaderType(shaderType),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000060 mSink(sink),
61 mNumErrors(0)
62{
63}
64
Zhenyao Mo550c6002014-02-26 15:40:48 -080065bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000066{
67 // Check if loop index is modified in the loop body.
68 validateOperation(node, node->getLeft());
69
70 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -080071 switch (node->getOp())
72 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000073 case EOpIndexDirect:
74 case EOpIndexIndirect:
75 validateIndexing(node);
76 break;
Zhenyao Mo550c6002014-02-26 15:40:48 -080077 default:
78 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000079 }
80 return true;
81}
82
Zhenyao Mo550c6002014-02-26 15:40:48 -080083bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000084{
85 // Check if loop index is modified in the loop body.
86 validateOperation(node, node->getOperand());
87
88 return true;
89}
90
Zhenyao Mo550c6002014-02-26 15:40:48 -080091bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000092{
93 switch (node->getOp()) {
94 case EOpFunctionCall:
95 validateFunctionCall(node);
96 break;
97 default:
98 break;
99 }
100 return true;
101}
102
Zhenyao Mo550c6002014-02-26 15:40:48 -0800103bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000104{
105 if (!validateLoopType(node))
106 return false;
107
Zhenyao Mo550c6002014-02-26 15:40:48 -0800108 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000109 return false;
110
Zhenyao Mo550c6002014-02-26 15:40:48 -0800111 TIntermNode *body = node->getBody();
112 if (body != NULL)
113 {
114 mLoopStack.push(node);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000115 body->traverse(this);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800116 mLoopStack.pop();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000117 }
118
119 // The loop is fully processed - no need to visit children.
120 return false;
121}
122
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000123void ValidateLimitations::error(TSourceLoc loc,
Zhenyao Mo550c6002014-02-26 15:40:48 -0800124 const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000125{
126 mSink.prefix(EPrefixError);
127 mSink.location(loc);
128 mSink << "'" << token << "' : " << reason << "\n";
129 ++mNumErrors;
130}
131
132bool ValidateLimitations::withinLoopBody() const
133{
134 return !mLoopStack.empty();
135}
136
Zhenyao Mo550c6002014-02-26 15:40:48 -0800137bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000138{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800139 return mLoopStack.findLoop(symbol) != NULL;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000140}
141
Zhenyao Mo550c6002014-02-26 15:40:48 -0800142bool ValidateLimitations::validateLoopType(TIntermLoop *node)
143{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000144 TLoopType type = node->getType();
145 if (type == ELoopFor)
146 return true;
147
148 // Reject while and do-while loops.
149 error(node->getLine(),
150 "This type of loop is not allowed",
151 type == ELoopWhile ? "while" : "do");
152 return false;
153}
154
Zhenyao Mo550c6002014-02-26 15:40:48 -0800155bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000156{
157 ASSERT(node->getType() == ELoopFor);
158
159 //
160 // The for statement has the form:
161 // for ( init-declaration ; condition ; expression ) statement
162 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800163 int indexSymbolId = validateForLoopInit(node);
164 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000165 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800166 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000167 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800168 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000169 return false;
170
171 return true;
172}
173
Zhenyao Mo550c6002014-02-26 15:40:48 -0800174int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000175{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800176 TIntermNode *init = node->getInit();
177 if (init == NULL)
178 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000179 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800180 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000181 }
182
183 //
184 // init-declaration has the form:
185 // type-specifier identifier = constant-expression
186 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800187 TIntermAggregate *decl = init->getAsAggregate();
188 if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
189 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000190 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800191 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000192 }
193 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700194 TIntermSequence *declSeq = decl->getSequence();
195 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800196 {
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 Moe40d1e92014-07-16 17:40:36 -0700200 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800201 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
202 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000203 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800204 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000205 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800206 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
207 if (symbol == NULL)
208 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000209 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800210 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000211 }
212 // The loop index has type int or float.
213 TBasicType type = symbol->getBasicType();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000214 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000215 error(symbol->getLine(),
216 "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800217 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000218 }
219 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800220 if (!isConstExpr(declInit->getRight()))
221 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000222 error(declInit->getLine(),
223 "Loop index cannot be initialized with non-constant expression",
224 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800225 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000226 }
227
Zhenyao Mo550c6002014-02-26 15:40:48 -0800228 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000229}
230
Zhenyao Mo550c6002014-02-26 15:40:48 -0800231bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
232 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000233{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800234 TIntermNode *cond = node->getCondition();
235 if (cond == NULL)
236 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000237 error(node->getLine(), "Missing condition", "for");
238 return false;
239 }
240 //
241 // condition has the form:
242 // loop_index relational_operator constant_expression
243 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800244 TIntermBinary *binOp = cond->getAsBinaryNode();
245 if (binOp == NULL)
246 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000247 error(node->getLine(), "Invalid condition", "for");
248 return false;
249 }
250 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800251 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
252 if (symbol == NULL)
253 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000254 error(binOp->getLine(), "Invalid condition", "for");
255 return false;
256 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257 if (symbol->getId() != indexSymbolId)
258 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000259 error(symbol->getLine(),
260 "Expected loop index", symbol->getSymbol().c_str());
261 return false;
262 }
263 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800264 switch (binOp->getOp())
265 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000266 case EOpEqual:
267 case EOpNotEqual:
268 case EOpLessThan:
269 case EOpGreaterThan:
270 case EOpLessThanEqual:
271 case EOpGreaterThanEqual:
272 break;
273 default:
274 error(binOp->getLine(),
275 "Invalid relational operator",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700276 GetOperatorString(binOp->getOp()));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000277 break;
278 }
279 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800280 if (!isConstExpr(binOp->getRight()))
281 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000282 error(binOp->getLine(),
283 "Loop index cannot be compared with non-constant expression",
284 symbol->getSymbol().c_str());
285 return false;
286 }
287
288 return true;
289}
290
Zhenyao Mo550c6002014-02-26 15:40:48 -0800291bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
292 int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000293{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800294 TIntermNode *expr = node->getExpression();
295 if (expr == NULL)
296 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000297 error(node->getLine(), "Missing expression", "for");
298 return false;
299 }
300
301 // for expression has one of the following forms:
302 // loop_index++
303 // loop_index--
304 // loop_index += constant_expression
305 // loop_index -= constant_expression
306 // ++loop_index
307 // --loop_index
308 // The last two forms are not specified in the spec, but I am assuming
309 // its an oversight.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800310 TIntermUnary *unOp = expr->getAsUnaryNode();
311 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000312
313 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800314 TIntermSymbol *symbol = NULL;
315 if (unOp != NULL)
316 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000317 op = unOp->getOp();
318 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800319 }
320 else if (binOp != NULL)
321 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000322 op = binOp->getOp();
323 symbol = binOp->getLeft()->getAsSymbolNode();
324 }
325
326 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800327 if (symbol == NULL)
328 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000329 error(expr->getLine(), "Invalid expression", "for");
330 return false;
331 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800332 if (symbol->getId() != indexSymbolId)
333 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000334 error(symbol->getLine(),
335 "Expected loop index", symbol->getSymbol().c_str());
336 return false;
337 }
338
339 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800340 switch (op)
341 {
342 case EOpPostIncrement:
343 case EOpPostDecrement:
344 case EOpPreIncrement:
345 case EOpPreDecrement:
346 ASSERT((unOp != NULL) && (binOp == NULL));
347 break;
348 case EOpAddAssign:
349 case EOpSubAssign:
350 ASSERT((unOp == NULL) && (binOp != NULL));
351 break;
352 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700353 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800354 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000355 }
356
357 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800358 if (binOp != NULL)
359 {
360 if (!isConstExpr(binOp->getRight()))
361 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000362 error(binOp->getLine(),
363 "Loop index cannot be modified by non-constant expression",
364 symbol->getSymbol().c_str());
365 return false;
366 }
367 }
368
369 return true;
370}
371
Zhenyao Mo550c6002014-02-26 15:40:48 -0800372bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000373{
374 ASSERT(node->getOp() == EOpFunctionCall);
375
376 // If not within loop body, there is nothing to check.
377 if (!withinLoopBody())
378 return true;
379
380 // List of param indices for which loop indices are used as argument.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000381 typedef std::vector<size_t> ParamIndex;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000382 ParamIndex pIndex;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700383 TIntermSequence *params = node->getSequence();
384 for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800385 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700386 TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000387 if (symbol && isLoopIndex(symbol))
388 pIndex.push_back(i);
389 }
390 // If none of the loop indices are used as arguments,
391 // there is nothing to check.
392 if (pIndex.empty())
393 return true;
394
395 bool valid = true;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400396 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400397 TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->getShaderVersion());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000398 ASSERT(symbol && symbol->isFunction());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800399 TFunction *function = static_cast<TFunction *>(symbol);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000400 for (ParamIndex::const_iterator i = pIndex.begin();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800401 i != pIndex.end(); ++i)
402 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700403 const TConstParameter &param = function->getParam(*i);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000404 TQualifier qual = param.type->getQualifier();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800405 if ((qual == EvqOut) || (qual == EvqInOut))
406 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700407 error((*params)[*i]->getLine(),
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000408 "Loop index cannot be used as argument to a function out or inout parameter",
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700409 (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000410 valid = false;
411 }
412 }
413
414 return valid;
415}
416
Zhenyao Mo550c6002014-02-26 15:40:48 -0800417bool ValidateLimitations::validateOperation(TIntermOperator *node,
418 TIntermNode* operand)
419{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000420 // Check if loop index is modified in the loop body.
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500421 if (!withinLoopBody() || !node->isAssignment())
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000422 return true;
423
Zhenyao Mo550c6002014-02-26 15:40:48 -0800424 TIntermSymbol *symbol = operand->getAsSymbolNode();
425 if (symbol && isLoopIndex(symbol))
426 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000427 error(node->getLine(),
428 "Loop index cannot be statically assigned to within the body of the loop",
429 symbol->getSymbol().c_str());
430 }
431 return true;
432}
433
Zhenyao Mo550c6002014-02-26 15:40:48 -0800434bool ValidateLimitations::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000435{
436 ASSERT(node != NULL);
437 return node->getAsConstantUnion() != NULL;
438}
439
Zhenyao Mo550c6002014-02-26 15:40:48 -0800440bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000441{
442 ASSERT(node != NULL);
443
444 ValidateConstIndexExpr validate(mLoopStack);
445 node->traverse(&validate);
446 return validate.isValid();
447}
448
Zhenyao Mo550c6002014-02-26 15:40:48 -0800449bool ValidateLimitations::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000450{
451 ASSERT((node->getOp() == EOpIndexDirect) ||
452 (node->getOp() == EOpIndexIndirect));
453
454 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800455 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000456 // The index expression must have integral type.
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000457 if (!index->isScalarInt()) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000458 error(index->getLine(),
459 "Index expression must have integral type",
460 index->getCompleteString().c_str());
461 valid = false;
462 }
463 // The index expession must be a constant-index-expression unless
464 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800465 TIntermTyped *operand = node->getLeft();
Jamie Madill183bde52014-07-02 15:31:19 -0400466 bool skip = (mShaderType == GL_VERTEX_SHADER) &&
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000467 (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800468 if (!skip && !isConstIndexExpr(index))
469 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000470 error(index->getLine(), "Index expression must be constant", "[]");
471 valid = false;
472 }
473 return valid;
474}
475