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