1//
2// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/translator/ForLoopUnroll.h"
8
9bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
10{
11    if (mUnrollCondition != kSamplerArrayIndex)
12        return true;
13
14    // If a sampler array index is also the loop index,
15    //   1) if the index type is integer, mark the loop for unrolling;
16    //   2) if the index type if float, set a flag to later fail compile.
17    switch (node->getOp())
18    {
19      case EOpIndexIndirect:
20        if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode())
21        {
22            TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode();
23            if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty())
24            {
25                mVisitSamplerArrayIndexNodeInsideLoop = true;
26                node->getRight()->traverse(this);
27                mVisitSamplerArrayIndexNodeInsideLoop = false;
28                // We have already visited all the children.
29                return false;
30            }
31        }
32        break;
33      default:
34        break;
35    }
36    return true;
37}
38
39bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
40{
41    if (mUnrollCondition == kIntegerIndex)
42    {
43        // Check if loop index type is integer.
44        // This is called after ValidateLimitations pass, so all the calls
45        // should be valid. See ValidateLimitations::validateForLoopInit().
46        TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence();
47        TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
48        if (symbol->getBasicType() == EbtInt)
49            node->setUnrollFlag(true);
50    }
51
52    TIntermNode *body = node->getBody();
53    if (body != NULL)
54    {
55        mLoopStack.push(node);
56        body->traverse(this);
57        mLoopStack.pop();
58    }
59    // The loop is fully processed - no need to visit children.
60    return false;
61}
62
63void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol)
64{
65    if (!mVisitSamplerArrayIndexNodeInsideLoop)
66        return;
67    TIntermLoop *loop = mLoopStack.findLoop(symbol);
68    if (loop)
69    {
70        switch (symbol->getBasicType())
71        {
72          case EbtFloat:
73            mSamplerArrayIndexIsFloatLoopIndex = true;
74            break;
75          case EbtInt:
76            loop->setUnrollFlag(true);
77            break;
78          default:
79            UNREACHABLE();
80        }
81    }
82}
83