• 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/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(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 
visitFunctionDefinition(TIntermAggregate * intermAggregate)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".
visitFunctionCall(TIntermAggregate * intermFunctionCall)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 
visitAggregateChildren(TIntermAggregate * intermAggregate)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 
visitSymbol(TIntermSymbol * intermSymbol)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 
visitBinary(Visit visit,TIntermBinary * intermBinary)94 bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
95 {
96     TOperator op = intermBinary->getOp();
97     if (op == EOpInitialize || intermBinary->isAssignment())
98         visitAssignment(intermBinary);
99     else if (op == EOpLogicalAnd || op == EOpLogicalOr)
100         visitLogicalOp(intermBinary);
101     else
102         visitBinaryChildren(intermBinary);
103 
104     return false;
105 }
106 
visitAssignment(TIntermBinary * intermAssignment)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 
visitLogicalOp(TIntermBinary * intermLogicalOp)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 
visitBinaryChildren(TIntermBinary * intermBinary)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 
visitSelection(Visit visit,TIntermSelection * intermSelection)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 
visitLoop(Visit visit,TIntermLoop * intermLoop)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 
connectMultipleNodesToSingleNode(TParentNodeSet * nodes,TGraphNode * node) const219 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 }
228