initial import
[vuplus_webkit] / Source / ThirdParty / ANGLE / src / compiler / ForLoopUnroll.cpp
1 //
2 // Copyright (c) 2002-2011 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/ForLoopUnroll.h"
8
9 void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info)
10 {
11     ASSERT(node->getType() == ELoopFor);
12     ASSERT(node->getUnrollFlag());
13
14     TIntermNode* init = node->getInit();
15     ASSERT(init != NULL);
16     TIntermAggregate* decl = init->getAsAggregate();
17     ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration));
18     TIntermSequence& declSeq = decl->getSequence();
19     ASSERT(declSeq.size() == 1);
20     TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
21     ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize));
22     TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
23     ASSERT(symbol != NULL);
24     ASSERT(symbol->getBasicType() == EbtInt);
25
26     info.id = symbol->getId();
27
28     ASSERT(declInit->getRight() != NULL);
29     TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
30     ASSERT(initNode != NULL);
31
32     info.initValue = evaluateIntConstant(initNode);
33     info.currentValue = info.initValue;
34
35     TIntermNode* cond = node->getCondition();
36     ASSERT(cond != NULL);
37     TIntermBinary* binOp = cond->getAsBinaryNode();
38     ASSERT(binOp != NULL);
39     ASSERT(binOp->getRight() != NULL);
40     ASSERT(binOp->getRight()->getAsConstantUnion() != NULL);
41
42     info.incrementValue = getLoopIncrement(node);
43     info.stopValue = evaluateIntConstant(
44         binOp->getRight()->getAsConstantUnion());
45     info.op = binOp->getOp();
46 }
47
48 void ForLoopUnroll::Step()
49 {
50     ASSERT(mLoopIndexStack.size() > 0);
51     TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
52     info.currentValue += info.incrementValue;
53 }
54
55 bool ForLoopUnroll::SatisfiesLoopCondition()
56 {
57     ASSERT(mLoopIndexStack.size() > 0);
58     TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
59     // Relational operator is one of: > >= < <= == or !=.
60     switch (info.op) {
61       case EOpEqual:
62         return (info.currentValue == info.stopValue);
63       case EOpNotEqual:
64         return (info.currentValue != info.stopValue);
65       case EOpLessThan:
66         return (info.currentValue < info.stopValue);
67       case EOpGreaterThan:
68         return (info.currentValue > info.stopValue);
69       case EOpLessThanEqual:
70         return (info.currentValue <= info.stopValue);
71       case EOpGreaterThanEqual:
72         return (info.currentValue >= info.stopValue);
73       default:
74         UNREACHABLE();
75     }
76     return false;
77 }
78
79 bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol)
80 {
81     for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
82          i != mLoopIndexStack.end();
83          ++i) {
84         if (i->id == symbol->getId())
85             return true;
86     }
87     return false;
88 }
89
90 int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol)
91 {
92     for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
93          i != mLoopIndexStack.end();
94          ++i) {
95         if (i->id == symbol->getId())
96             return i->currentValue;
97     }
98     UNREACHABLE();
99     return false;
100 }
101
102 void ForLoopUnroll::Push(TLoopIndexInfo& info)
103 {
104     mLoopIndexStack.push_back(info);
105 }
106
107 void ForLoopUnroll::Pop()
108 {
109     mLoopIndexStack.pop_back();
110 }
111
112 int ForLoopUnroll::getLoopIncrement(TIntermLoop* node)
113 {
114     TIntermNode* expr = node->getExpression();
115     ASSERT(expr != NULL);
116     // for expression has one of the following forms:
117     //     loop_index++
118     //     loop_index--
119     //     loop_index += constant_expression
120     //     loop_index -= constant_expression
121     //     ++loop_index
122     //     --loop_index
123     // The last two forms are not specified in the spec, but I am assuming
124     // its an oversight.
125     TIntermUnary* unOp = expr->getAsUnaryNode();
126     TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
127
128     TOperator op = EOpNull;
129     TIntermConstantUnion* incrementNode = NULL;
130     if (unOp != NULL) {
131         op = unOp->getOp();
132     } else if (binOp != NULL) {
133         op = binOp->getOp();
134         ASSERT(binOp->getRight() != NULL);
135         incrementNode = binOp->getRight()->getAsConstantUnion();
136         ASSERT(incrementNode != NULL);
137     }
138
139     int increment = 0;
140     // The operator is one of: ++ -- += -=.
141     switch (op) {
142         case EOpPostIncrement:
143         case EOpPreIncrement:
144             ASSERT((unOp != NULL) && (binOp == NULL));
145             increment = 1;
146             break;
147         case EOpPostDecrement:
148         case EOpPreDecrement:
149             ASSERT((unOp != NULL) && (binOp == NULL));
150             increment = -1;
151             break;
152         case EOpAddAssign:
153             ASSERT((unOp == NULL) && (binOp != NULL));
154             increment = evaluateIntConstant(incrementNode);
155             break;
156         case EOpSubAssign:
157             ASSERT((unOp == NULL) && (binOp != NULL));
158             increment = - evaluateIntConstant(incrementNode);
159             break;
160         default:
161             ASSERT(false);
162     }
163
164     return increment;
165 }
166
167 int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
168 {
169     ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
170     return node->getUnionArrayPointer()->getIConst();
171 }
172