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