blob: d931a18a231200453518b5506dc2c3893a0cf7aa [file] [log] [blame]
Zhenyao Mo550c6002014-02-26 15:40:48 -08001//
2// Copyright (c) 2002-2014 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/LoopInfo.h"
8
9namespace
10{
11
12int EvaluateIntConstant(TIntermConstantUnion *node)
13{
14 ASSERT(node && node->getUnionArrayPointer());
15 return node->getIConst(0);
16}
17
18int GetLoopIntIncrement(TIntermLoop *node)
19{
20 TIntermNode *expr = node->getExpression();
21 // for expression has one of the following forms:
22 // loop_index++
23 // loop_index--
24 // loop_index += constant_expression
25 // loop_index -= constant_expression
26 // ++loop_index
27 // --loop_index
28 // The last two forms are not specified in the spec, but I am assuming
29 // its an oversight.
30 TIntermUnary *unOp = expr->getAsUnaryNode();
31 TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
32
33 TOperator op = EOpNull;
34 TIntermConstantUnion *incrementNode = NULL;
35 if (unOp)
36 {
37 op = unOp->getOp();
38 }
39 else if (binOp)
40 {
41 op = binOp->getOp();
42 ASSERT(binOp->getRight());
43 incrementNode = binOp->getRight()->getAsConstantUnion();
44 ASSERT(incrementNode);
45 }
46
47 int increment = 0;
48 // The operator is one of: ++ -- += -=.
49 switch (op)
50 {
51 case EOpPostIncrement:
52 case EOpPreIncrement:
53 ASSERT(unOp && !binOp);
54 increment = 1;
55 break;
56 case EOpPostDecrement:
57 case EOpPreDecrement:
58 ASSERT(unOp && !binOp);
59 increment = -1;
60 break;
61 case EOpAddAssign:
62 ASSERT(!unOp && binOp);
63 increment = EvaluateIntConstant(incrementNode);
64 break;
65 case EOpSubAssign:
66 ASSERT(!unOp && binOp);
67 increment = - EvaluateIntConstant(incrementNode);
68 break;
69 default:
70 UNREACHABLE();
71 }
72
73 return increment;
74}
75
76} // namespace anonymous
77
78TLoopIndexInfo::TLoopIndexInfo()
79 : mId(-1),
80 mType(EbtVoid),
81 mInitValue(0),
82 mStopValue(0),
83 mIncrementValue(0),
84 mOp(EOpNull),
85 mCurrentValue(0)
86{
87}
88
89void TLoopIndexInfo::fillInfo(TIntermLoop *node)
90{
91 if (node == NULL)
92 return;
93
94 // Here we assume all the operations are valid, because the loop node is
95 // already validated in ValidateLimitations.
Zhenyao Moe40d1e92014-07-16 17:40:36 -070096 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -080097 node->getInit()->getAsAggregate()->getSequence();
Zhenyao Moe40d1e92014-07-16 17:40:36 -070098 TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -080099 TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
100
101 mId = symbol->getId();
102 mType = symbol->getBasicType();
103
104 if (mType == EbtInt)
105 {
106 TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
107 mInitValue = EvaluateIntConstant(initNode);
108 mCurrentValue = mInitValue;
109 mIncrementValue = GetLoopIntIncrement(node);
110
111 TIntermBinary* binOp = node->getCondition()->getAsBinaryNode();
112 mStopValue = EvaluateIntConstant(
113 binOp->getRight()->getAsConstantUnion());
114 mOp = binOp->getOp();
115 }
116}
117
118bool TLoopIndexInfo::satisfiesLoopCondition() const
119{
120 // Relational operator is one of: > >= < <= == or !=.
121 switch (mOp)
122 {
123 case EOpEqual:
124 return (mCurrentValue == mStopValue);
125 case EOpNotEqual:
126 return (mCurrentValue != mStopValue);
127 case EOpLessThan:
128 return (mCurrentValue < mStopValue);
129 case EOpGreaterThan:
130 return (mCurrentValue > mStopValue);
131 case EOpLessThanEqual:
132 return (mCurrentValue <= mStopValue);
133 case EOpGreaterThanEqual:
134 return (mCurrentValue >= mStopValue);
135 default:
136 UNREACHABLE();
137 return false;
138 }
139}
140
141TLoopInfo::TLoopInfo()
142 : loop(NULL)
143{
144}
145
146TLoopInfo::TLoopInfo(TIntermLoop *node)
147 : loop(node)
148{
149 index.fillInfo(node);
150}
151
152TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol)
153{
154 if (!symbol)
155 return NULL;
156 for (iterator iter = begin(); iter != end(); ++iter)
157 {
158 if (iter->index.getId() == symbol->getId())
159 return iter->loop;
160 }
161 return NULL;
162}
163
164TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol)
165{
166 if (!symbol)
167 return NULL;
168 for (iterator iter = begin(); iter != end(); ++iter)
169 {
170 if (iter->index.getId() == symbol->getId())
171 return &(iter->index);
172 }
173 return NULL;
174}
175
176void TLoopStack::step()
177{
178 ASSERT(!empty());
179 rbegin()->index.step();
180}
181
182bool TLoopStack::satisfiesLoopCondition()
183{
184 ASSERT(!empty());
185 return rbegin()->index.satisfiesLoopCondition();
186}
187
188bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol)
189{
190 TIntermLoop *loop = findLoop(symbol);
191 return loop && loop->getUnrollFlag();
192}
193
194int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol)
195{
196 TLoopIndexInfo *info = getIndexInfo(symbol);
197 ASSERT(info);
198 return info->getCurrentValue();
199}
200
201void TLoopStack::push(TIntermLoop *loop)
202{
203 TLoopInfo info(loop);
204 push_back(info);
205}
206
207void TLoopStack::pop()
208{
209 pop_back();
210}
211