blob: 8e45c37d7ecf57cc326c33ac084577e7e0b47b22 [file] [log] [blame]
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +00001//
2// Copyright (c) 2012 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/depgraph/DependencyGraphBuilder.h"
8
9TDependencyGraphBuilder::TLeftmostSymbolMaintainer::TSubtreePlaceholder
10 TDependencyGraphBuilder::TLeftmostSymbolMaintainer::kLeftSubtree;
11
12TDependencyGraphBuilder::TLeftmostSymbolMaintainer::TSubtreePlaceholder
13 TDependencyGraphBuilder::TLeftmostSymbolMaintainer::kRightSubtree;
14
15void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph)
16{
17 TDependencyGraphBuilder builder(graph);
18 builder.build(node);
19}
20
21bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate)
22{
23 switch (intermAggregate->getOp()) {
24 case EOpFunction: visitFunctionDefinition(intermAggregate); break;
25 case EOpFunctionCall: visitFunctionCall(intermAggregate); break;
26 default: visitAggregateChildren(intermAggregate); break;
27 }
28
29 return false;
30}
31
32void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate)
33{
34 // Function defintions should only exist in the global scope.
35 ASSERT(mIsGlobalScope);
36
37 // Currently, we do not support user defined functions.
38 if (intermAggregate->getName() != "main(")
39 return;
40
41 mIsGlobalScope = false;
42
43 visitAggregateChildren(intermAggregate);
44
45 mIsGlobalScope = true;
46}
47
48// Takes an expression like "f(x)" and creates a dependency graph like
49// "x -> argument 0 -> function call".
50void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall)
51{
52 TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall);
53
54 // Run through the function call arguments.
55 int argumentNumber = 0;
56 TIntermSequence& intermArguments = intermFunctionCall->getSequence();
57 for (TIntermSequence::const_iterator iter = intermArguments.begin();
58 iter != intermArguments.end();
59 ++iter, ++argumentNumber)
60 {
61 TNodeSetMaintainer nodeSetMaintainer(this);
62
63 TIntermNode* intermArgument = *iter;
64 intermArgument->traverse(this);
65
66 if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) {
67 TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber);
68 connectMultipleNodesToSingleNode(argumentNodes, argument);
69 argument->addDependentNode(functionCall);
70 }
71 }
72
73 // Push the leftmost symbol of this function call into the current set of dependent symbols to
74 // represent the result of this function call.
75 // Thus, an expression like "y = f(x)" will yield a dependency graph like
76 // "x -> argument 0 -> function call -> y".
77 // This line essentially passes the function call node back up to an earlier visitAssignment
78 // call, which will create the connection "function call -> y".
79 mNodeSets.insertIntoTopSet(functionCall);
80}
81
82void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate)
83{
84 TIntermSequence& sequence = intermAggregate->getSequence();
85 for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter)
86 {
87 TIntermNode* intermChild = *iter;
88 intermChild->traverse(this);
89 }
90}
91
92void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol)
93{
94 // Push this symbol into the set of dependent symbols for the current assignment or condition
95 // that we are traversing.
96 TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol, mIsGlobalScope);
97 mNodeSets.insertIntoTopSet(symbol);
98
99 // If this symbol is the current leftmost symbol under an assignment, replace the previous
100 // leftmost symbol with this symbol.
101 if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() !=
102 &TLeftmostSymbolMaintainer::kRightSubtree) {
103 mLeftmostSymbols.pop();
104 mLeftmostSymbols.push(symbol);
105 }
106}
107
108bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
109{
110 TOperator op = intermBinary->getOp();
111 if (op == EOpInitialize || intermBinary->modifiesState())
112 visitAssignment(intermBinary);
113 else if (op == EOpLogicalAnd || op == EOpLogicalOr)
114 visitLogicalOp(intermBinary);
115 else
116 visitBinaryChildren(intermBinary);
117
118 return false;
119}
120
121void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment)
122{
123 TIntermTyped* intermLeft = intermAssignment->getLeft();
124 if (!intermLeft)
125 return;
126
127 TGraphSymbol* leftmostSymbol = NULL;
128
129 {
130 TNodeSetMaintainer nodeSetMaintainer(this);
131
132 {
133 TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, TLeftmostSymbolMaintainer::kLeftSubtree);
134 intermLeft->traverse(this);
135 leftmostSymbol = mLeftmostSymbols.top();
136
137 // After traversing the left subtree of this assignment, we should have found a real
138 // leftmost symbol, and the leftmost symbol should not be a placeholder.
139 ASSERT(leftmostSymbol != &TLeftmostSymbolMaintainer::kLeftSubtree);
140 ASSERT(leftmostSymbol != &TLeftmostSymbolMaintainer::kRightSubtree);
141 }
142
143 if (TIntermTyped* intermRight = intermAssignment->getRight()) {
144 TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, TLeftmostSymbolMaintainer::kRightSubtree);
145 intermRight->traverse(this);
146 }
147
148 if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet())
149 connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol);
150 }
151
152 // Push the leftmost symbol of this assignment into the current set of dependent symbols to
153 // represent the result of this assignment.
154 // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a".
155 // This line essentially passes the leftmost symbol of the nested assignment ("b" in this
156 // example) back up to the earlier visitAssignment call for the outer assignment, which will
157 // create the connection "b -> a".
158 mNodeSets.insertIntoTopSet(leftmostSymbol);
159}
160
161void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp)
162{
163 if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) {
164 TNodeSetPropagatingMaintainer nodeSetMaintainer(this);
165
166 intermLeft->traverse(this);
167 if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) {
168 TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp);
169 connectMultipleNodesToSingleNode(leftNodes, logicalOp);
170 }
171 }
172
173 if (TIntermTyped* intermRight = intermLogicalOp->getRight()) {
174 TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, TLeftmostSymbolMaintainer::kRightSubtree);
175 intermRight->traverse(this);
176 }
177}
178
179void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary)
180{
181 if (TIntermTyped* intermLeft = intermBinary->getLeft())
182 intermLeft->traverse(this);
183
184 if (TIntermTyped* intermRight = intermBinary->getRight()) {
185 TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, TLeftmostSymbolMaintainer::kRightSubtree);
186 intermRight->traverse(this);
187 }
188}
189
190bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection)
191{
192 if (TIntermNode* intermCondition = intermSelection->getCondition()) {
193 TNodeSetMaintainer nodeSetMaintainer(this);
194
195 intermCondition->traverse(this);
196 if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
197 TGraphSelection* selection = mGraph->createSelection(intermSelection);
198 connectMultipleNodesToSingleNode(conditionNodes, selection);
199 }
200 }
201
202 if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock())
203 intermTrueBlock->traverse(this);
204
205 if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock())
206 intermFalseBlock->traverse(this);
207
208 return false;
209}
210
211bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop)
212{
213 if (TIntermTyped* intermCondition = intermLoop->getCondition()) {
214 TNodeSetMaintainer nodeSetMaintainer(this);
215
216 intermCondition->traverse(this);
217 if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
218 TGraphLoop* loop = mGraph->createLoop(intermLoop);
219 connectMultipleNodesToSingleNode(conditionNodes, loop);
220 }
221 }
222
223 if (TIntermNode* intermBody = intermLoop->getBody())
224 intermBody->traverse(this);
225
226 if (TIntermTyped* intermExpression = intermLoop->getExpression())
227 intermExpression->traverse(this);
228
229 return false;
230}
231
232
233void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes,
234 TGraphNode* node) const
235{
236 for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter)
237 {
238 TGraphParentNode* currentNode = *iter;
239 currentNode->addDependentNode(node);
240 }
241}