maxvujovic@gmail.com | 66ebd01 | 2012-05-30 22:18:11 +0000 | [diff] [blame] | 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 | TDependencyGraphBuilder::TLeftmostSymbolMaintainer::TSubtreePlaceholder |
| 10 | TDependencyGraphBuilder::TLeftmostSymbolMaintainer::kLeftSubtree; |
| 11 | |
| 12 | TDependencyGraphBuilder::TLeftmostSymbolMaintainer::TSubtreePlaceholder |
| 13 | TDependencyGraphBuilder::TLeftmostSymbolMaintainer::kRightSubtree; |
| 14 | |
| 15 | void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph) |
| 16 | { |
| 17 | TDependencyGraphBuilder builder(graph); |
| 18 | builder.build(node); |
| 19 | } |
| 20 | |
| 21 | bool 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 | |
| 32 | void 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". |
| 50 | void 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 | |
| 82 | void 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 | |
| 92 | void 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 | |
| 108 | bool 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 | |
| 121 | void 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 | |
| 161 | void 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 | |
| 179 | void 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 | |
| 190 | bool 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 | |
| 211 | bool 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 | |
| 233 | void 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 | } |