blob: 3a17614fa02097c1567ea62551761a154b920d5f [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"
Olli Etuaho77ba4082016-12-16 12:01:18 +00008
Jamie Madill183bde52014-07-02 15:31:19 -04009#include "angle_gl.h"
Olli Etuaho9ec79392017-03-31 23:04:23 +030010#include "compiler/translator/Diagnostics.h"
11#include "compiler/translator/ParseContext.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000012
Jamie Madill45bcc782016-11-07 13:58:48 -050013namespace sh
14{
15
Zhenyao Mo550c6002014-02-26 15:40:48 -080016namespace
17{
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000018
Corentin Wallez1b896c62016-11-16 13:10:44 -050019int GetLoopSymbolId(TIntermLoop *loop)
20{
21 // Here we assume all the operations are valid, because the loop node is
22 // already validated before this call.
23 TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
24 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
25 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
26
27 return symbol->getId();
28}
29
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000030// Traverses a node to check if it represents a constant index expression.
31// Definition:
32// constant-index-expressions are a superset of constant-expressions.
33// Constant-index-expressions can include loop indices as defined in
34// GLSL ES 1.0 spec, Appendix A, section 4.
35// The following are constant-index-expressions:
36// - Constant expressions
37// - Loop indices as defined in section 4
38// - Expressions composed of both of the above
Zhenyao Mo550c6002014-02-26 15:40:48 -080039class ValidateConstIndexExpr : public TIntermTraverser
40{
41 public:
Corentin Wallez1b896c62016-11-16 13:10:44 -050042 ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
43 : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030044 {
45 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000046
47 // Returns true if the parsed node represents a constant index expression.
48 bool isValid() const { return mValid; }
49
Corentin Walleze5a1f272015-08-21 02:58:25 +020050 void visitSymbol(TIntermSymbol *symbol) override
Zhenyao Mo550c6002014-02-26 15:40:48 -080051 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000052 // Only constants and loop indices are allowed in a
53 // constant index expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -080054 if (mValid)
55 {
Corentin Wallez1b896c62016-11-16 13:10:44 -050056 bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
57 symbol->getId()) != mLoopSymbolIds.end();
58 mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000059 }
60 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000061
Zhenyao Mo550c6002014-02-26 15:40:48 -080062 private:
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000063 bool mValid;
Corentin Wallez1b896c62016-11-16 13:10:44 -050064 const std::vector<int> mLoopSymbolIds;
zmo@google.com0b8d4eb2011-04-04 19:17:11 +000065};
Zhenyao Mo550c6002014-02-26 15:40:48 -080066
Olli Etuaho9ec79392017-03-31 23:04:23 +030067// Traverses intermediate tree to ensure that the shader does not exceed the
68// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
69class ValidateLimitationsTraverser : public TLValueTrackingTraverser
70{
71 public:
72 ValidateLimitationsTraverser(sh::GLenum shaderType,
73 const TSymbolTable &symbolTable,
74 int shaderVersion,
75 TDiagnostics *diagnostics);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000076
Olli Etuaho9ec79392017-03-31 23:04:23 +030077 void visitSymbol(TIntermSymbol *node) override;
78 bool visitBinary(Visit, TIntermBinary *) override;
79 bool visitLoop(Visit, TIntermLoop *) override;
80
81 private:
82 void error(TSourceLoc loc, const char *reason, const char *token);
83
84 bool withinLoopBody() const;
85 bool isLoopIndex(TIntermSymbol *symbol);
86 bool validateLoopType(TIntermLoop *node);
87
88 bool validateForLoopHeader(TIntermLoop *node);
89 // If valid, return the index symbol id; Otherwise, return -1.
90 int validateForLoopInit(TIntermLoop *node);
91 bool validateForLoopCond(TIntermLoop *node, int indexSymbolId);
92 bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId);
93
94 // Returns true if indexing does not exceed the minimum functionality
95 // mandated in GLSL 1.0 spec, Appendix A, Section 5.
96 bool isConstExpr(TIntermNode *node);
97 bool isConstIndexExpr(TIntermNode *node);
98 bool validateIndexing(TIntermBinary *node);
99
100 sh::GLenum mShaderType;
101 TDiagnostics *mDiagnostics;
102 std::vector<int> mLoopSymbolIds;
103};
104
105ValidateLimitationsTraverser::ValidateLimitationsTraverser(sh::GLenum shaderType,
106 const TSymbolTable &symbolTable,
107 int shaderVersion,
108 TDiagnostics *diagnostics)
109 : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300110 mShaderType(shaderType),
Olli Etuaho9ec79392017-03-31 23:04:23 +0300111 mDiagnostics(diagnostics)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000112{
Olli Etuaho77ba4082016-12-16 12:01:18 +0000113 ASSERT(diagnostics);
Olli Etuaho8a76dcc2015-12-10 20:25:12 +0200114}
115
Olli Etuaho9ec79392017-03-31 23:04:23 +0300116void ValidateLimitationsTraverser::visitSymbol(TIntermSymbol *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000117{
Olli Etuaho9ec79392017-03-31 23:04:23 +0300118 if (isLoopIndex(node) && isLValueRequiredHere())
119 {
120 error(node->getLine(),
121 "Loop index cannot be statically assigned to within the body of the loop",
122 node->getSymbol().c_str());
123 }
124}
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000125
Olli Etuaho9ec79392017-03-31 23:04:23 +0300126bool ValidateLimitationsTraverser::visitBinary(Visit, TIntermBinary *node)
127{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000128 // Check indexing.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800129 switch (node->getOp())
130 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500131 case EOpIndexDirect:
132 case EOpIndexIndirect:
Olli Etuaho9ec79392017-03-31 23:04:23 +0300133 validateIndexing(node);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500134 break;
135 default:
136 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000137 }
138 return true;
139}
140
Olli Etuaho9ec79392017-03-31 23:04:23 +0300141bool ValidateLimitationsTraverser::visitLoop(Visit, TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000142{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000143 if (!validateLoopType(node))
144 return false;
145
Zhenyao Mo550c6002014-02-26 15:40:48 -0800146 if (!validateForLoopHeader(node))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000147 return false;
148
Zhenyao Mo550c6002014-02-26 15:40:48 -0800149 TIntermNode *body = node->getBody();
150 if (body != NULL)
151 {
Corentin Wallez1b896c62016-11-16 13:10:44 -0500152 mLoopSymbolIds.push_back(GetLoopSymbolId(node));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000153 body->traverse(this);
Corentin Wallez1b896c62016-11-16 13:10:44 -0500154 mLoopSymbolIds.pop_back();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000155 }
156
157 // The loop is fully processed - no need to visit children.
158 return false;
159}
160
Olli Etuaho9ec79392017-03-31 23:04:23 +0300161void ValidateLimitationsTraverser::error(TSourceLoc loc, const char *reason, const char *token)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000162{
Olli Etuaho77ba4082016-12-16 12:01:18 +0000163 mDiagnostics->error(loc, reason, token);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000164}
165
Olli Etuaho9ec79392017-03-31 23:04:23 +0300166bool ValidateLimitationsTraverser::withinLoopBody() const
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000167{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500168 return !mLoopSymbolIds.empty();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000169}
170
Olli Etuaho9ec79392017-03-31 23:04:23 +0300171bool ValidateLimitationsTraverser::isLoopIndex(TIntermSymbol *symbol)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000172{
Corentin Wallez1b896c62016-11-16 13:10:44 -0500173 return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
174 mLoopSymbolIds.end();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000175}
176
Olli Etuaho9ec79392017-03-31 23:04:23 +0300177bool ValidateLimitationsTraverser::validateLoopType(TIntermLoop *node)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800178{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000179 TLoopType type = node->getType();
180 if (type == ELoopFor)
181 return true;
182
183 // Reject while and do-while loops.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500184 error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do");
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000185 return false;
186}
187
Olli Etuaho9ec79392017-03-31 23:04:23 +0300188bool ValidateLimitationsTraverser::validateForLoopHeader(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000189{
190 ASSERT(node->getType() == ELoopFor);
191
192 //
193 // The for statement has the form:
194 // for ( init-declaration ; condition ; expression ) statement
195 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800196 int indexSymbolId = validateForLoopInit(node);
197 if (indexSymbolId < 0)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000198 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800199 if (!validateForLoopCond(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000200 return false;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800201 if (!validateForLoopExpr(node, indexSymbolId))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000202 return false;
203
204 return true;
205}
206
Olli Etuaho9ec79392017-03-31 23:04:23 +0300207int ValidateLimitationsTraverser::validateForLoopInit(TIntermLoop *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000208{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800209 TIntermNode *init = node->getInit();
210 if (init == NULL)
211 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000212 error(node->getLine(), "Missing init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800213 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000214 }
215
216 //
217 // init-declaration has the form:
218 // type-specifier identifier = constant-expression
219 //
Olli Etuaho13389b62016-10-16 11:48:18 +0100220 TIntermDeclaration *decl = init->getAsDeclarationNode();
221 if (decl == nullptr)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800222 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000223 error(init->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800224 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000225 }
226 // To keep things simple do not allow declaration list.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700227 TIntermSequence *declSeq = decl->getSequence();
228 if (declSeq->size() != 1)
Zhenyao Mo550c6002014-02-26 15:40:48 -0800229 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000230 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800231 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000232 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700233 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800234 if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
235 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000236 error(decl->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800237 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000238 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800239 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
240 if (symbol == NULL)
241 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000242 error(declInit->getLine(), "Invalid init declaration", "for");
Zhenyao Mo550c6002014-02-26 15:40:48 -0800243 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000244 }
245 // The loop index has type int or float.
246 TBasicType type = symbol->getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500247 if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat))
248 {
249 error(symbol->getLine(), "Invalid type for loop index", getBasicString(type));
Zhenyao Mo550c6002014-02-26 15:40:48 -0800250 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000251 }
252 // The loop index is initialized with constant expression.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800253 if (!isConstExpr(declInit->getRight()))
254 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255 error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000256 symbol->getSymbol().c_str());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800257 return -1;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000258 }
259
Zhenyao Mo550c6002014-02-26 15:40:48 -0800260 return symbol->getId();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000261}
262
Olli Etuaho9ec79392017-03-31 23:04:23 +0300263bool ValidateLimitationsTraverser::validateForLoopCond(TIntermLoop *node, int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000264{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800265 TIntermNode *cond = node->getCondition();
266 if (cond == NULL)
267 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000268 error(node->getLine(), "Missing condition", "for");
269 return false;
270 }
271 //
272 // condition has the form:
273 // loop_index relational_operator constant_expression
274 //
Zhenyao Mo550c6002014-02-26 15:40:48 -0800275 TIntermBinary *binOp = cond->getAsBinaryNode();
276 if (binOp == NULL)
277 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000278 error(node->getLine(), "Invalid condition", "for");
279 return false;
280 }
281 // Loop index should be to the left of relational operator.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800282 TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
283 if (symbol == NULL)
284 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000285 error(binOp->getLine(), "Invalid condition", "for");
286 return false;
287 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800288 if (symbol->getId() != indexSymbolId)
289 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500290 error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000291 return false;
292 }
293 // Relational operator is one of: > >= < <= == or !=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800294 switch (binOp->getOp())
295 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500296 case EOpEqual:
297 case EOpNotEqual:
298 case EOpLessThan:
299 case EOpGreaterThan:
300 case EOpLessThanEqual:
301 case EOpGreaterThanEqual:
302 break;
303 default:
304 error(binOp->getLine(), "Invalid relational operator",
305 GetOperatorString(binOp->getOp()));
306 break;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000307 }
308 // Loop index must be compared with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800309 if (!isConstExpr(binOp->getRight()))
310 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500311 error(binOp->getLine(), "Loop index cannot be compared with non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000312 symbol->getSymbol().c_str());
313 return false;
314 }
315
316 return true;
317}
318
Olli Etuaho9ec79392017-03-31 23:04:23 +0300319bool ValidateLimitationsTraverser::validateForLoopExpr(TIntermLoop *node, int indexSymbolId)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000320{
Zhenyao Mo550c6002014-02-26 15:40:48 -0800321 TIntermNode *expr = node->getExpression();
322 if (expr == NULL)
323 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000324 error(node->getLine(), "Missing expression", "for");
325 return false;
326 }
327
328 // for expression has one of the following forms:
329 // loop_index++
330 // loop_index--
331 // loop_index += constant_expression
332 // loop_index -= constant_expression
333 // ++loop_index
334 // --loop_index
335 // The last two forms are not specified in the spec, but I am assuming
336 // its an oversight.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500337 TIntermUnary *unOp = expr->getAsUnaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800338 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000339
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500340 TOperator op = EOpNull;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800341 TIntermSymbol *symbol = NULL;
342 if (unOp != NULL)
343 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500344 op = unOp->getOp();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000345 symbol = unOp->getOperand()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800346 }
347 else if (binOp != NULL)
348 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500349 op = binOp->getOp();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000350 symbol = binOp->getLeft()->getAsSymbolNode();
351 }
352
353 // The operand must be loop index.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800354 if (symbol == NULL)
355 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000356 error(expr->getLine(), "Invalid expression", "for");
357 return false;
358 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800359 if (symbol->getId() != indexSymbolId)
360 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500361 error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str());
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000362 return false;
363 }
364
365 // The operator is one of: ++ -- += -=.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800366 switch (op)
367 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500368 case EOpPostIncrement:
369 case EOpPostDecrement:
370 case EOpPreIncrement:
371 case EOpPreDecrement:
372 ASSERT((unOp != NULL) && (binOp == NULL));
373 break;
374 case EOpAddAssign:
375 case EOpSubAssign:
376 ASSERT((unOp == NULL) && (binOp != NULL));
377 break;
378 default:
379 error(expr->getLine(), "Invalid operator", GetOperatorString(op));
380 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000381 }
382
383 // Loop index must be incremented/decremented with a constant.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800384 if (binOp != NULL)
385 {
386 if (!isConstExpr(binOp->getRight()))
387 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500388 error(binOp->getLine(), "Loop index cannot be modified by non-constant expression",
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000389 symbol->getSymbol().c_str());
390 return false;
391 }
392 }
393
394 return true;
395}
396
Olli Etuaho9ec79392017-03-31 23:04:23 +0300397bool ValidateLimitationsTraverser::isConstExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000398{
Olli Etuahod5610572015-12-10 19:42:09 +0200399 ASSERT(node != nullptr);
400 return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000401}
402
Olli Etuaho9ec79392017-03-31 23:04:23 +0300403bool ValidateLimitationsTraverser::isConstIndexExpr(TIntermNode *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000404{
405 ASSERT(node != NULL);
406
Corentin Wallez1b896c62016-11-16 13:10:44 -0500407 ValidateConstIndexExpr validate(mLoopSymbolIds);
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000408 node->traverse(&validate);
409 return validate.isValid();
410}
411
Olli Etuaho9ec79392017-03-31 23:04:23 +0300412bool ValidateLimitationsTraverser::validateIndexing(TIntermBinary *node)
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000413{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500414 ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect));
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000415
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500416 bool valid = true;
Zhenyao Mo550c6002014-02-26 15:40:48 -0800417 TIntermTyped *index = node->getRight();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000418 // The index expession must be a constant-index-expression unless
419 // the operand is a uniform in a vertex shader.
Zhenyao Mo550c6002014-02-26 15:40:48 -0800420 TIntermTyped *operand = node->getLeft();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500421 bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800422 if (!skip && !isConstIndexExpr(index))
423 {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000424 error(index->getLine(), "Index expression must be constant", "[]");
425 valid = false;
426 }
427 return valid;
428}
429
Olli Etuaho9ec79392017-03-31 23:04:23 +0300430} // namespace anonymous
431
432bool ValidateLimitations(TIntermNode *root,
433 GLenum shaderType,
434 const TSymbolTable &symbolTable,
435 int shaderVersion,
436 TDiagnostics *diagnostics)
437{
438 ValidateLimitationsTraverser validate(shaderType, symbolTable, shaderVersion, diagnostics);
439 root->traverse(&validate);
440 return diagnostics->numErrors() == 0;
441}
442
Jamie Madill45bcc782016-11-07 13:58:48 -0500443} // namespace sh