15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "compiler/ValidateLimitations.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "compiler/InfoSink.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "compiler/InitializeParseContext.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "compiler/ParseHelper.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->index.id == symbol->getId()) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->index.id == symbol->getId()) { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(i->loop != NULL); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i->loop->setUnrollFlag(true); 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNREACHABLE(); 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Traverses a node to check if it represents a constant index expression. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Definition: 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// constant-index-expressions are a superset of constant-expressions. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Constant-index-expressions can include loop indices as defined in 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GLSL ES 1.0 spec, Appendix A, section 4. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following are constant-index-expressions: 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Constant expressions 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Loop indices as defined in section 4 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Expressions composed of both of the above 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ValidateConstIndexExpr : public TIntermTraverser { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValidateConstIndexExpr(const TLoopStack& stack) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : mValid(true), mLoopStack(stack) {} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if the parsed node represents a constant index expression. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool isValid() const { return mValid; } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void visitSymbol(TIntermSymbol* symbol) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only constants and loop indices are allowed in a 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // constant index expression. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mValid) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mValid = (symbol->getQualifier() == EvqConst) || 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsLoopIndex(symbol, mLoopStack); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private: 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool mValid; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TLoopStack& mLoopStack; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Traverses a node to check if it uses a loop index. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If an int loop index is used in its body as a sampler array index, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mark the loop for unroll. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ValidateLoopIndexExpr : public TIntermTraverser { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public: 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValidateLoopIndexExpr(TLoopStack& stack) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : mUsesFloatLoopIndex(false), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUsesIntLoopIndex(false), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mLoopStack(stack) {} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool usesIntLoopIndex() const { return mUsesIntLoopIndex; } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void visitSymbol(TIntermSymbol* symbol) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsLoopIndex(symbol, mLoopStack)) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (symbol->getBasicType()) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EbtFloat: 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUsesFloatLoopIndex = true; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EbtInt: 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUsesIntLoopIndex = true; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkLoopForUnroll(symbol, mLoopStack); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UNREACHABLE(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private: 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool mUsesFloatLoopIndex; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool mUsesIntLoopIndex; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLoopStack& mLoopStack; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ValidateLimitations::ValidateLimitations(ShShaderType shaderType, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TInfoSinkBase& sink) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : mShaderType(shaderType), 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mSink(sink), 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mNumErrors(0) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if loop index is modified in the loop body. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validateOperation(node, node->getLeft()); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check indexing. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (node->getOp()) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpIndexDirect: 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validateIndexing(node); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpIndexIndirect: 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__APPLE__) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop unrolling is a work-around for a Mac Cg compiler bug where it 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // crashes when a sampler array's index is also the loop index. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Once Apple fixes this bug, we should remove the code in this CL. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See http://codereview.appspot.com/4331048/. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((node->getLeft() != NULL) && (node->getRight() != NULL) && 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (node->getLeft()->getAsSymbolNode())) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsSampler(symbol->getBasicType()) && symbol->isArray()) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValidateLoopIndexExpr validate(mLoopStack); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->getRight()->traverse(&validate); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (validate.usesFloatLoopIndex()) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(node->getLine(), 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "sampler array index is float loop index", 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "for"); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validateIndexing(node); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: break; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if loop index is modified in the loop body. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validateOperation(node, node->getOperand()); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (node->getOp()) { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpFunctionCall: 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validateFunctionCall(node); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!validateLoopType(node)) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLoopInfo info; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&info, 0, sizeof(TLoopInfo)); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.loop = node; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!validateForLoopHeader(node, &info)) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermNode* body = node->getBody(); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (body != NULL) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mLoopStack.push_back(info); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body->traverse(this); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mLoopStack.pop_back(); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The loop is fully processed - no need to visit children. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ValidateLimitations::error(TSourceLoc loc, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *reason, const char* token) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mSink.prefix(EPrefixError); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mSink.location(loc); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mSink << "'" << token << "' : " << reason << "\n"; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++mNumErrors; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::withinLoopBody() const 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !mLoopStack.empty(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsLoopIndex(symbol, mLoopStack); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::validateLoopType(TIntermLoop* node) { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLoopType type = node->getType(); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == ELoopFor) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reject while and do-while loops. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(node->getLine(), 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "This type of loop is not allowed", 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type == ELoopWhile ? "while" : "do"); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLoopInfo* info) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(node->getType() == ELoopFor); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The for statement has the form: 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for ( init-declaration ; condition ; expression ) statement 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!validateForLoopInit(node, info)) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!validateForLoopCond(node, info)) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!validateForLoopExpr(node, info)) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::validateForLoopInit(TIntermLoop* node, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLoopInfo* info) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermNode* init = node->getInit(); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (init == NULL) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(node->getLine(), "Missing init declaration", "for"); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // init-declaration has the form: 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type-specifier identifier = constant-expression 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermAggregate* decl = init->getAsAggregate(); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(init->getLine(), "Invalid init declaration", "for"); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To keep things simple do not allow declaration list. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermSequence& declSeq = decl->getSequence(); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (declSeq.size() != 1) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(decl->getLine(), "Invalid init declaration", "for"); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(decl->getLine(), "Invalid init declaration", "for"); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (symbol == NULL) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(declInit->getLine(), "Invalid init declaration", "for"); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The loop index has type int or float. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TBasicType type = symbol->getBasicType(); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((type != EbtInt) && (type != EbtFloat)) { 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error(symbol->getLine(), 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Invalid type for loop index", getBasicString(type)); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The loop index is initialized with constant expression. 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!isConstExpr(declInit->getRight())) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(declInit->getLine(), 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Loop index cannot be initialized with non-constant expression", 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) symbol->getSymbol().c_str()); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->index.id = symbol->getId(); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TLoopInfo* info) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermNode* cond = node->getCondition(); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cond == NULL) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(node->getLine(), "Missing condition", "for"); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // condition has the form: 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // loop_index relational_operator constant_expression 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermBinary* binOp = cond->getAsBinaryNode(); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (binOp == NULL) { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(node->getLine(), "Invalid condition", "for"); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop index should be to the left of relational operator. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode(); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (symbol == NULL) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(binOp->getLine(), "Invalid condition", "for"); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (symbol->getId() != info->index.id) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(symbol->getLine(), 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Expected loop index", symbol->getSymbol().c_str()); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Relational operator is one of: > >= < <= == or !=. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (binOp->getOp()) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpEqual: 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpNotEqual: 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpLessThan: 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpGreaterThan: 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpLessThanEqual: 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case EOpGreaterThanEqual: 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error(binOp->getLine(), 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Invalid relational operator", 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getOperatorString(binOp->getOp())); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop index must be compared with a constant. 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!isConstExpr(binOp->getRight())) { 334 error(binOp->getLine(), 335 "Loop index cannot be compared with non-constant expression", 336 symbol->getSymbol().c_str()); 337 return false; 338 } 339 340 return true; 341} 342 343bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node, 344 TLoopInfo* info) 345{ 346 TIntermNode* expr = node->getExpression(); 347 if (expr == NULL) { 348 error(node->getLine(), "Missing expression", "for"); 349 return false; 350 } 351 352 // for expression has one of the following forms: 353 // loop_index++ 354 // loop_index-- 355 // loop_index += constant_expression 356 // loop_index -= constant_expression 357 // ++loop_index 358 // --loop_index 359 // The last two forms are not specified in the spec, but I am assuming 360 // its an oversight. 361 TIntermUnary* unOp = expr->getAsUnaryNode(); 362 TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); 363 364 TOperator op = EOpNull; 365 TIntermSymbol* symbol = NULL; 366 if (unOp != NULL) { 367 op = unOp->getOp(); 368 symbol = unOp->getOperand()->getAsSymbolNode(); 369 } else if (binOp != NULL) { 370 op = binOp->getOp(); 371 symbol = binOp->getLeft()->getAsSymbolNode(); 372 } 373 374 // The operand must be loop index. 375 if (symbol == NULL) { 376 error(expr->getLine(), "Invalid expression", "for"); 377 return false; 378 } 379 if (symbol->getId() != info->index.id) { 380 error(symbol->getLine(), 381 "Expected loop index", symbol->getSymbol().c_str()); 382 return false; 383 } 384 385 // The operator is one of: ++ -- += -=. 386 switch (op) { 387 case EOpPostIncrement: 388 case EOpPostDecrement: 389 case EOpPreIncrement: 390 case EOpPreDecrement: 391 ASSERT((unOp != NULL) && (binOp == NULL)); 392 break; 393 case EOpAddAssign: 394 case EOpSubAssign: 395 ASSERT((unOp == NULL) && (binOp != NULL)); 396 break; 397 default: 398 error(expr->getLine(), "Invalid operator", getOperatorString(op)); 399 return false; 400 } 401 402 // Loop index must be incremented/decremented with a constant. 403 if (binOp != NULL) { 404 if (!isConstExpr(binOp->getRight())) { 405 error(binOp->getLine(), 406 "Loop index cannot be modified by non-constant expression", 407 symbol->getSymbol().c_str()); 408 return false; 409 } 410 } 411 412 return true; 413} 414 415bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) 416{ 417 ASSERT(node->getOp() == EOpFunctionCall); 418 419 // If not within loop body, there is nothing to check. 420 if (!withinLoopBody()) 421 return true; 422 423 // List of param indices for which loop indices are used as argument. 424 typedef std::vector<size_t> ParamIndex; 425 ParamIndex pIndex; 426 TIntermSequence& params = node->getSequence(); 427 for (TIntermSequence::size_type i = 0; i < params.size(); ++i) { 428 TIntermSymbol* symbol = params[i]->getAsSymbolNode(); 429 if (symbol && isLoopIndex(symbol)) 430 pIndex.push_back(i); 431 } 432 // If none of the loop indices are used as arguments, 433 // there is nothing to check. 434 if (pIndex.empty()) 435 return true; 436 437 bool valid = true; 438 TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable; 439 TSymbol* symbol = symbolTable.find(node->getName()); 440 ASSERT(symbol && symbol->isFunction()); 441 TFunction* function = static_cast<TFunction*>(symbol); 442 for (ParamIndex::const_iterator i = pIndex.begin(); 443 i != pIndex.end(); ++i) { 444 const TParameter& param = function->getParam(*i); 445 TQualifier qual = param.type->getQualifier(); 446 if ((qual == EvqOut) || (qual == EvqInOut)) { 447 error(params[*i]->getLine(), 448 "Loop index cannot be used as argument to a function out or inout parameter", 449 params[*i]->getAsSymbolNode()->getSymbol().c_str()); 450 valid = false; 451 } 452 } 453 454 return valid; 455} 456 457bool ValidateLimitations::validateOperation(TIntermOperator* node, 458 TIntermNode* operand) { 459 // Check if loop index is modified in the loop body. 460 if (!withinLoopBody() || !node->modifiesState()) 461 return true; 462 463 const TIntermSymbol* symbol = operand->getAsSymbolNode(); 464 if (symbol && isLoopIndex(symbol)) { 465 error(node->getLine(), 466 "Loop index cannot be statically assigned to within the body of the loop", 467 symbol->getSymbol().c_str()); 468 } 469 return true; 470} 471 472bool ValidateLimitations::isConstExpr(TIntermNode* node) 473{ 474 ASSERT(node != NULL); 475 return node->getAsConstantUnion() != NULL; 476} 477 478bool ValidateLimitations::isConstIndexExpr(TIntermNode* node) 479{ 480 ASSERT(node != NULL); 481 482 ValidateConstIndexExpr validate(mLoopStack); 483 node->traverse(&validate); 484 return validate.isValid(); 485} 486 487bool ValidateLimitations::validateIndexing(TIntermBinary* node) 488{ 489 ASSERT((node->getOp() == EOpIndexDirect) || 490 (node->getOp() == EOpIndexIndirect)); 491 492 bool valid = true; 493 TIntermTyped* index = node->getRight(); 494 // The index expression must have integral type. 495 if (!index->isScalar() || (index->getBasicType() != EbtInt)) { 496 error(index->getLine(), 497 "Index expression must have integral type", 498 index->getCompleteString().c_str()); 499 valid = false; 500 } 501 // The index expession must be a constant-index-expression unless 502 // the operand is a uniform in a vertex shader. 503 TIntermTyped* operand = node->getLeft(); 504 bool skip = (mShaderType == SH_VERTEX_SHADER) && 505 (operand->getQualifier() == EvqUniform); 506 if (!skip && !isConstIndexExpr(index)) { 507 error(index->getLine(), "Index expression must be constant", "[]"); 508 valid = false; 509 } 510 return valid; 511} 512 513