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