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