1b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org//
296e7ba17f417a48c1a6c31f3d9fbd5611219d14dshannonwoods@chromium.org// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
3b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// Use of this source code is governed by a BSD-style license that can be
4b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// found in the LICENSE file.
5b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org//
6b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
717732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/ValidateLimitations.h"
817732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/InfoSink.h"
917732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/InitializeParseContext.h"
106b9cb25980022d0c792d858bc6f6500c00a6c29dJamie Madill#include "compiler/translator/ParseContext.h"
11183bde5527317fa2208401e5e6b803ef51a0fdcbJamie Madill#include "angle_gl.h"
12b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
13550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Monamespace
14550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo{
150b8d4eb260eec6b3b2c32b88a2bfe400f1cfb0c0zmo@google.com
16b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// Traverses a node to check if it represents a constant index expression.
17b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// Definition:
18b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// constant-index-expressions are a superset of constant-expressions.
19b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// Constant-index-expressions can include loop indices as defined in
20b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// GLSL ES 1.0 spec, Appendix A, section 4.
21b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// The following are constant-index-expressions:
22b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// - Constant expressions
23b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// - Loop indices as defined in section 4
24b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org// - Expressions composed of both of the above
25550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Moclass ValidateConstIndexExpr : public TIntermTraverser
26550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo{
27550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo  public:
28550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    ValidateConstIndexExpr(TLoopStack& stack)
29b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        : mValid(true), mLoopStack(stack) {}
30b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
31b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Returns true if the parsed node represents a constant index expression.
32b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    bool isValid() const { return mValid; }
33b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
34550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    virtual void visitSymbol(TIntermSymbol *symbol)
35550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
36b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        // Only constants and loop indices are allowed in a
37b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        // constant index expression.
38550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        if (mValid)
39550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        {
40b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org            mValid = (symbol->getQualifier() == EvqConst) ||
41550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo                     (mLoopStack.findLoop(symbol));
42b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        }
43b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
44b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
45550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo  private:
46b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    bool mValid;
470b8d4eb260eec6b3b2c32b88a2bfe400f1cfb0c0zmo@google.com    TLoopStack& mLoopStack;
480b8d4eb260eec6b3b2c32b88a2bfe400f1cfb0c0zmo@google.com};
49550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo
50e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Moconst char *GetOperatorString(TOperator op)
51e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo{
52e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    switch (op)
53e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    {
54e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpInitialize: return "=";
55e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAssign: return "=";
56e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAddAssign: return "+=";
57e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpSubAssign: return "-=";
58e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpDivAssign: return "/=";
59e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
60e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      // Fall-through.
61e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMulAssign:
62e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpVectorTimesMatrixAssign:
63e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpVectorTimesScalarAssign:
64e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMatrixTimesScalarAssign:
65e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMatrixTimesMatrixAssign: return "*=";
66e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
67e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      // Fall-through.
68e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpIndexDirect:
69e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpIndexIndirect: return "[]";
70e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
71e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpIndexDirectStruct:
72e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpIndexDirectInterfaceBlock: return ".";
73e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpVectorSwizzle: return ".";
74e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAdd: return "+";
75e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpSub: return "-";
76e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMul: return "*";
77e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpDiv: return "/";
78e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMod: UNIMPLEMENTED(); break;
79e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpEqual: return "==";
80e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpNotEqual: return "!=";
81e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLessThan: return "<";
82e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpGreaterThan: return ">";
83e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLessThanEqual: return "<=";
84e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpGreaterThanEqual: return ">=";
85e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
86e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      // Fall-through.
87e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpVectorTimesScalar:
88e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpVectorTimesMatrix:
89e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMatrixTimesVector:
90e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMatrixTimesScalar:
91e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpMatrixTimesMatrix: return "*";
92e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
93e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLogicalOr: return "||";
94e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLogicalXor: return "^^";
95e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLogicalAnd: return "&&";
96e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpNegative: return "-";
97e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpVectorLogicalNot: return "not";
98e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLogicalNot: return "!";
99e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpPostIncrement: return "++";
100e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpPostDecrement: return "--";
101e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpPreIncrement: return "++";
102e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpPreDecrement: return "--";
103e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
104e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpRadians: return "radians";
105e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpDegrees: return "degrees";
106e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpSin: return "sin";
107e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpCos: return "cos";
108e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpTan: return "tan";
109e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAsin: return "asin";
110e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAcos: return "acos";
111e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAtan: return "atan";
112e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpExp: return "exp";
113e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLog: return "log";
114e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpExp2: return "exp2";
115e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLog2: return "log2";
116e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpSqrt: return "sqrt";
117e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpInverseSqrt: return "inversesqrt";
118e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAbs: return "abs";
119e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpSign: return "sign";
120e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpFloor: return "floor";
121e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpCeil: return "ceil";
122e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpFract: return "fract";
123e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpLength: return "length";
124e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpNormalize: return "normalize";
125e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpDFdx: return "dFdx";
126e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpDFdy: return "dFdy";
127e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpFwidth: return "fwidth";
128e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAny: return "any";
129e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      case EOpAll: return "all";
130e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
131e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo      default: break;
132e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    }
133e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    return "";
134e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo}
135e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo
136550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo}  // namespace anonymous
137b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
138183bde5527317fa2208401e5e6b803ef51a0fdcbJamie MadillValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
139550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo                                         TInfoSinkBase &sink)
140b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    : mShaderType(shaderType),
141b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      mSink(sink),
142b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      mNumErrors(0)
143b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
144b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
145b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
146550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
147b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
148b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Check if loop index is modified in the loop body.
149b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    validateOperation(node, node->getLeft());
150b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
151b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Check indexing.
152550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    switch (node->getOp())
153550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
154b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpIndexDirect:
155b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpIndexIndirect:
156b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        validateIndexing(node);
157b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        break;
158550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      default:
159550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        break;
160b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
161b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
162b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
163b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
164550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
165b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
166b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Check if loop index is modified in the loop body.
167b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    validateOperation(node, node->getOperand());
168b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
169b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
170b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
171b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
172550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
173b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
174b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    switch (node->getOp()) {
175b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpFunctionCall:
176b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        validateFunctionCall(node);
177b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        break;
178b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      default:
179b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        break;
180b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
181b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
182b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
183b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
184550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
185b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
186b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    if (!validateLoopType(node))
187b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
188b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
189550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (!validateForLoopHeader(node))
190b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
191b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
192550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermNode *body = node->getBody();
193550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (body != NULL)
194550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
195550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        mLoopStack.push(node);
196b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        body->traverse(this);
197550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        mLoopStack.pop();
198b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
199b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
200b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The loop is fully processed - no need to visit children.
201b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return false;
202b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
203b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
204b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.orgvoid ValidateLimitations::error(TSourceLoc loc,
205550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo                                const char *reason, const char *token)
206b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
207b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    mSink.prefix(EPrefixError);
208b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    mSink.location(loc);
209b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    mSink << "'" << token << "' : " << reason << "\n";
210b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ++mNumErrors;
211b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
212b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
213b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.orgbool ValidateLimitations::withinLoopBody() const
214b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
215b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return !mLoopStack.empty();
216b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
217b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
218550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
219b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
220550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    return mLoopStack.findLoop(symbol) != NULL;
221b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
222b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
223550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateLoopType(TIntermLoop *node)
224550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo{
225b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    TLoopType type = node->getType();
226b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    if (type == ELoopFor)
227b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return true;
228b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
229b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Reject while and do-while loops.
230b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    error(node->getLine(),
231b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org          "This type of loop is not allowed",
232b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org          type == ELoopWhile ? "while" : "do");
233b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return false;
234b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
235b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
236550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
237b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
238b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ASSERT(node->getType() == ELoopFor);
239b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
240b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //
241b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The for statement has the form:
242b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //    for ( init-declaration ; condition ; expression ) statement
243b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //
244550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    int indexSymbolId = validateForLoopInit(node);
245550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (indexSymbolId < 0)
246b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
247550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (!validateForLoopCond(node, indexSymbolId))
248b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
249550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (!validateForLoopExpr(node, indexSymbolId))
250b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
251b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
252b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
253b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
254b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
255550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Moint ValidateLimitations::validateForLoopInit(TIntermLoop *node)
256b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
257550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermNode *init = node->getInit();
258550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (init == NULL)
259550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
260b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(node->getLine(), "Missing init declaration", "for");
261550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
262b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
263b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
264b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //
265b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // init-declaration has the form:
266b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     type-specifier identifier = constant-expression
267b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //
268550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermAggregate *decl = init->getAsAggregate();
269550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
270550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
271b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(init->getLine(), "Invalid init declaration", "for");
272550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
273b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
274b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // To keep things simple do not allow declaration list.
275e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    TIntermSequence *declSeq = decl->getSequence();
276e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    if (declSeq->size() != 1)
277550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
278b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(decl->getLine(), "Invalid init declaration", "for");
279550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
280b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
281e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
282550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
283550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
284b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(decl->getLine(), "Invalid init declaration", "for");
285550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
286b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
287550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
288550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (symbol == NULL)
289550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
290b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(declInit->getLine(), "Invalid init declaration", "for");
291550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
292b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
293b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The loop index has type int or float.
294b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    TBasicType type = symbol->getBasicType();
2956b7099111f6f00493b24dd05680f60c30b60cb7cshannonwoods@chromium.org    if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
296b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(symbol->getLine(),
297b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Invalid type for loop index", getBasicString(type));
298550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
299b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
300b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The loop index is initialized with constant expression.
301550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (!isConstExpr(declInit->getRight()))
302550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
303b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(declInit->getLine(),
304b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Loop index cannot be initialized with non-constant expression",
305b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              symbol->getSymbol().c_str());
306550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return -1;
307b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
308b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
309550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    return symbol->getId();
310b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
311b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
312550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
313550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo                                              int indexSymbolId)
314b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
315550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermNode *cond = node->getCondition();
316550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (cond == NULL)
317550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
318b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(node->getLine(), "Missing condition", "for");
319b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
320b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
321b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //
322b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // condition has the form:
323b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     loop_index relational_operator constant_expression
324b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //
325550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermBinary *binOp = cond->getAsBinaryNode();
326550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (binOp == NULL)
327550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
328b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(node->getLine(), "Invalid condition", "for");
329b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
330b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
331b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Loop index should be to the left of relational operator.
332550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
333550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (symbol == NULL)
334550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
335b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(binOp->getLine(), "Invalid condition", "for");
336b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
337b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
338550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (symbol->getId() != indexSymbolId)
339550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
340b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(symbol->getLine(),
341b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Expected loop index", symbol->getSymbol().c_str());
342b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
343b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
344b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Relational operator is one of: > >= < <= == or !=.
345550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    switch (binOp->getOp())
346550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
347b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpEqual:
348b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpNotEqual:
349b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpLessThan:
350b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpGreaterThan:
351b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpLessThanEqual:
352b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      case EOpGreaterThanEqual:
353b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        break;
354b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org      default:
355b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(binOp->getLine(),
356b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Invalid relational operator",
357e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo              GetOperatorString(binOp->getOp()));
358b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        break;
359b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
360b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Loop index must be compared with a constant.
361550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (!isConstExpr(binOp->getRight()))
362550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
363b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(binOp->getLine(),
364b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Loop index cannot be compared with non-constant expression",
365b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              symbol->getSymbol().c_str());
366b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
367b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
368b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
369b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
370b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
371b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
372550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
373550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo                                              int indexSymbolId)
374b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
375550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermNode *expr = node->getExpression();
376550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (expr == NULL)
377550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
378b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(node->getLine(), "Missing expression", "for");
379b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
380b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
381b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
382b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // for expression has one of the following forms:
383b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     loop_index++
384b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     loop_index--
385b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     loop_index += constant_expression
386b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     loop_index -= constant_expression
387b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     ++loop_index
388b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    //     --loop_index
389b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The last two forms are not specified in the spec, but I am assuming
390b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // its an oversight.
391550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermUnary *unOp = expr->getAsUnaryNode();
392550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
393b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
394b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    TOperator op = EOpNull;
395550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermSymbol *symbol = NULL;
396550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (unOp != NULL)
397550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
398b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        op = unOp->getOp();
399b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        symbol = unOp->getOperand()->getAsSymbolNode();
400550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    }
401550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    else if (binOp != NULL)
402550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
403b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        op = binOp->getOp();
404b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        symbol = binOp->getLeft()->getAsSymbolNode();
405b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
406b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
407b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The operand must be loop index.
408550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (symbol == NULL)
409550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
410b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(expr->getLine(), "Invalid expression", "for");
411b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
412b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
413550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (symbol->getId() != indexSymbolId)
414550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
415b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(symbol->getLine(),
416b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Expected loop index", symbol->getSymbol().c_str());
417b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return false;
418b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
419b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
420b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The operator is one of: ++ -- += -=.
421550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    switch (op)
422550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
423550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      case EOpPostIncrement:
424550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      case EOpPostDecrement:
425550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      case EOpPreIncrement:
426550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      case EOpPreDecrement:
427550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        ASSERT((unOp != NULL) && (binOp == NULL));
428550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        break;
429550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      case EOpAddAssign:
430550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      case EOpSubAssign:
431550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        ASSERT((unOp == NULL) && (binOp != NULL));
432550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        break;
433550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo      default:
434e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo        error(expr->getLine(), "Invalid operator", GetOperatorString(op));
435550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        return false;
436b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
437b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
438b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Loop index must be incremented/decremented with a constant.
439550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (binOp != NULL)
440550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
441550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        if (!isConstExpr(binOp->getRight()))
442550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        {
443b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org            error(binOp->getLine(),
444b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org                  "Loop index cannot be modified by non-constant expression",
445b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org                  symbol->getSymbol().c_str());
446b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org            return false;
447b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        }
448b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
449b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
450b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
451b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
452b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
453550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
454b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
455b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ASSERT(node->getOp() == EOpFunctionCall);
456b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
457b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // If not within loop body, there is nothing to check.
458b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    if (!withinLoopBody())
459b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return true;
460b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
461b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // List of param indices for which loop indices are used as argument.
462d64b3dab06c30da1e5dd9ba12667ff86388540e2shannon.woods@transgaming.com    typedef std::vector<size_t> ParamIndex;
463b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ParamIndex pIndex;
464e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    TIntermSequence *params = node->getSequence();
465e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo    for (TIntermSequence::size_type i = 0; i < params->size(); ++i)
466550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
467e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo        TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode();
468b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        if (symbol && isLoopIndex(symbol))
469b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org            pIndex.push_back(i);
470b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
471b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // If none of the loop indices are used as arguments,
472b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // there is nothing to check.
473b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    if (pIndex.empty())
474b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return true;
475b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
476b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    bool valid = true;
4778156b6be065905c22db8f5dc3ab0fb715b0e1b52Alok Priyadarshi    TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
4788156b6be065905c22db8f5dc3ab0fb715b0e1b52Alok Priyadarshi    TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
479b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ASSERT(symbol && symbol->isFunction());
480550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TFunction *function = static_cast<TFunction *>(symbol);
481b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    for (ParamIndex::const_iterator i = pIndex.begin();
482550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo         i != pIndex.end(); ++i)
483550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
484550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        const TParameter &param = function->getParam(*i);
485b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        TQualifier qual = param.type->getQualifier();
486550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        if ((qual == EvqOut) || (qual == EvqInOut))
487550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo        {
488e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo            error((*params)[*i]->getLine(),
489b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org                  "Loop index cannot be used as argument to a function out or inout parameter",
490e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo                  (*params)[*i]->getAsSymbolNode()->getSymbol().c_str());
491b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org            valid = false;
492b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        }
493b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
494b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
495b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return valid;
496b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
497b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
498550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateOperation(TIntermOperator *node,
499550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo                                            TIntermNode* operand)
500550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo{
501b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // Check if loop index is modified in the loop body.
502f4b79ba83c82253c012571ab07433692858562e2Jamie Madill    if (!withinLoopBody() || !node->isAssignment())
503b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        return true;
504b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
505550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermSymbol *symbol = operand->getAsSymbolNode();
506550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (symbol && isLoopIndex(symbol))
507550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
508b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(node->getLine(),
509b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Loop index cannot be statically assigned to within the body of the loop",
510b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              symbol->getSymbol().c_str());
511b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
512b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return true;
513b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
514b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
515550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::isConstExpr(TIntermNode *node)
516b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
517b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ASSERT(node != NULL);
518b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return node->getAsConstantUnion() != NULL;
519b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
520b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
521550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
522b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
523b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ASSERT(node != NULL);
524b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
525b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ValidateConstIndexExpr validate(mLoopStack);
526b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    node->traverse(&validate);
527b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return validate.isValid();
528b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
529b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
530550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mobool ValidateLimitations::validateIndexing(TIntermBinary *node)
531b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org{
532b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    ASSERT((node->getOp() == EOpIndexDirect) ||
533b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org           (node->getOp() == EOpIndexIndirect));
534b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
535b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    bool valid = true;
536550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermTyped *index = node->getRight();
537b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The index expression must have integral type.
5386b7099111f6f00493b24dd05680f60c30b60cb7cshannonwoods@chromium.org    if (!index->isScalarInt()) {
539b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(index->getLine(),
540b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              "Index expression must have integral type",
541b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org              index->getCompleteString().c_str());
542b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        valid = false;
543b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
544b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // The index expession must be a constant-index-expression unless
545b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    // the operand is a uniform in a vertex shader.
546550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    TIntermTyped *operand = node->getLeft();
547183bde5527317fa2208401e5e6b803ef51a0fdcbJamie Madill    bool skip = (mShaderType == GL_VERTEX_SHADER) &&
548b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org                (operand->getQualifier() == EvqUniform);
549550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    if (!skip && !isConstIndexExpr(index))
550550c600b99d7ee2463e5878d0a9f66ea24c1414aZhenyao Mo    {
551b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        error(index->getLine(), "Index expression must be constant", "[]");
552b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org        valid = false;
553b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    }
554b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org    return valid;
555b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org}
556b59a778cfe7e36dca41c2cc44198da511f447be8alokp@chromium.org
557