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 ¶m = 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