• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ForLoopUnroll.h"
8 
9 namespace {
10 
11 class IntegerForLoopUnrollMarker : public TIntermTraverser {
12 public:
13 
visitLoop(Visit,TIntermLoop * node)14     virtual bool visitLoop(Visit, TIntermLoop* node)
15     {
16         // This is called after ValidateLimitations pass, so all the ASSERT
17         // should never fail.
18         // See ValidateLimitations::validateForLoopInit().
19         ASSERT(node);
20         ASSERT(node->getType() == ELoopFor);
21         ASSERT(node->getInit());
22         TIntermAggregate* decl = node->getInit()->getAsAggregate();
23         ASSERT(decl && decl->getOp() == EOpDeclaration);
24         TIntermSequence& declSeq = decl->getSequence();
25         ASSERT(declSeq.size() == 1);
26         TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
27         ASSERT(declInit && declInit->getOp() == EOpInitialize);
28         ASSERT(declInit->getLeft());
29         TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
30         ASSERT(symbol);
31         TBasicType type = symbol->getBasicType();
32         ASSERT(type == EbtInt || type == EbtFloat);
33         if (type == EbtInt)
34             node->setUnrollFlag(true);
35         return true;
36     }
37 
38 };
39 
40 }  // anonymous namepsace
41 
FillLoopIndexInfo(TIntermLoop * node,TLoopIndexInfo & info)42 void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info)
43 {
44     ASSERT(node->getType() == ELoopFor);
45     ASSERT(node->getUnrollFlag());
46 
47     TIntermNode* init = node->getInit();
48     ASSERT(init != NULL);
49     TIntermAggregate* decl = init->getAsAggregate();
50     ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration));
51     TIntermSequence& declSeq = decl->getSequence();
52     ASSERT(declSeq.size() == 1);
53     TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
54     ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize));
55     TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
56     ASSERT(symbol != NULL);
57     ASSERT(symbol->getBasicType() == EbtInt);
58 
59     info.id = symbol->getId();
60 
61     ASSERT(declInit->getRight() != NULL);
62     TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
63     ASSERT(initNode != NULL);
64 
65     info.initValue = evaluateIntConstant(initNode);
66     info.currentValue = info.initValue;
67 
68     TIntermNode* cond = node->getCondition();
69     ASSERT(cond != NULL);
70     TIntermBinary* binOp = cond->getAsBinaryNode();
71     ASSERT(binOp != NULL);
72     ASSERT(binOp->getRight() != NULL);
73     ASSERT(binOp->getRight()->getAsConstantUnion() != NULL);
74 
75     info.incrementValue = getLoopIncrement(node);
76     info.stopValue = evaluateIntConstant(
77         binOp->getRight()->getAsConstantUnion());
78     info.op = binOp->getOp();
79 }
80 
Step()81 void ForLoopUnroll::Step()
82 {
83     ASSERT(mLoopIndexStack.size() > 0);
84     TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
85     info.currentValue += info.incrementValue;
86 }
87 
SatisfiesLoopCondition()88 bool ForLoopUnroll::SatisfiesLoopCondition()
89 {
90     ASSERT(mLoopIndexStack.size() > 0);
91     TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
92     // Relational operator is one of: > >= < <= == or !=.
93     switch (info.op) {
94       case EOpEqual:
95         return (info.currentValue == info.stopValue);
96       case EOpNotEqual:
97         return (info.currentValue != info.stopValue);
98       case EOpLessThan:
99         return (info.currentValue < info.stopValue);
100       case EOpGreaterThan:
101         return (info.currentValue > info.stopValue);
102       case EOpLessThanEqual:
103         return (info.currentValue <= info.stopValue);
104       case EOpGreaterThanEqual:
105         return (info.currentValue >= info.stopValue);
106       default:
107         UNREACHABLE();
108     }
109     return false;
110 }
111 
NeedsToReplaceSymbolWithValue(TIntermSymbol * symbol)112 bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol)
113 {
114     for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
115          i != mLoopIndexStack.end();
116          ++i) {
117         if (i->id == symbol->getId())
118             return true;
119     }
120     return false;
121 }
122 
GetLoopIndexValue(TIntermSymbol * symbol)123 int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol)
124 {
125     for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
126          i != mLoopIndexStack.end();
127          ++i) {
128         if (i->id == symbol->getId())
129             return i->currentValue;
130     }
131     UNREACHABLE();
132     return false;
133 }
134 
Push(TLoopIndexInfo & info)135 void ForLoopUnroll::Push(TLoopIndexInfo& info)
136 {
137     mLoopIndexStack.push_back(info);
138 }
139 
Pop()140 void ForLoopUnroll::Pop()
141 {
142     mLoopIndexStack.pop_back();
143 }
144 
145 // static
MarkForLoopsWithIntegerIndicesForUnrolling(TIntermNode * root)146 void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(
147     TIntermNode* root)
148 {
149     ASSERT(root);
150 
151     IntegerForLoopUnrollMarker marker;
152     root->traverse(&marker);
153 }
154 
getLoopIncrement(TIntermLoop * node)155 int ForLoopUnroll::getLoopIncrement(TIntermLoop* node)
156 {
157     TIntermNode* expr = node->getExpression();
158     ASSERT(expr != NULL);
159     // for expression has one of the following forms:
160     //     loop_index++
161     //     loop_index--
162     //     loop_index += constant_expression
163     //     loop_index -= constant_expression
164     //     ++loop_index
165     //     --loop_index
166     // The last two forms are not specified in the spec, but I am assuming
167     // its an oversight.
168     TIntermUnary* unOp = expr->getAsUnaryNode();
169     TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
170 
171     TOperator op = EOpNull;
172     TIntermConstantUnion* incrementNode = NULL;
173     if (unOp != NULL) {
174         op = unOp->getOp();
175     } else if (binOp != NULL) {
176         op = binOp->getOp();
177         ASSERT(binOp->getRight() != NULL);
178         incrementNode = binOp->getRight()->getAsConstantUnion();
179         ASSERT(incrementNode != NULL);
180     }
181 
182     int increment = 0;
183     // The operator is one of: ++ -- += -=.
184     switch (op) {
185         case EOpPostIncrement:
186         case EOpPreIncrement:
187             ASSERT((unOp != NULL) && (binOp == NULL));
188             increment = 1;
189             break;
190         case EOpPostDecrement:
191         case EOpPreDecrement:
192             ASSERT((unOp != NULL) && (binOp == NULL));
193             increment = -1;
194             break;
195         case EOpAddAssign:
196             ASSERT((unOp == NULL) && (binOp != NULL));
197             increment = evaluateIntConstant(incrementNode);
198             break;
199         case EOpSubAssign:
200             ASSERT((unOp == NULL) && (binOp != NULL));
201             increment = - evaluateIntConstant(incrementNode);
202             break;
203         default:
204             ASSERT(false);
205     }
206 
207     return increment;
208 }
209 
evaluateIntConstant(TIntermConstantUnion * node)210 int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
211 {
212     ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
213     return node->getIConst(0);
214 }
215 
216