blob: d631af44fc62be1c43369b2bf00600d6ec96509f [file] [log] [blame]
zmo@google.com0b8d4eb2011-04-04 19:17:11 +00001//
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
9void 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
48void ForLoopUnroll::Step()
49{
50 ASSERT(mLoopIndexStack.size() > 0);
51 TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
52 info.currentValue += info.incrementValue;
53}
54
55bool 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
79bool 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
90int 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
102void ForLoopUnroll::Push(TLoopIndexInfo& info)
103{
104 mLoopIndexStack.push_back(info);
105}
106
107void ForLoopUnroll::Pop()
108{
109 mLoopIndexStack.pop_back();
110}
111
112int 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
167int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
168{
169 ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
170 return node->getUnionArrayPointer()->getIConst();
171}
172