Line data Source code
1 : //
2 : // Copyright (c) 2002-2015 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 : // SeparateExpressionsReturningArrays splits array-returning expressions that are not array names from more complex
7 : // expressions, assigning them to a temporary variable a#.
8 : // Examples where a, b and c are all arrays:
9 : // (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2;
10 : // type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i];
11 :
12 : #include "compiler/translator/SeparateExpressionsReturningArrays.h"
13 :
14 : #include "compiler/translator/IntermNode.h"
15 : #include "compiler/translator/IntermNodePatternMatcher.h"
16 :
17 : namespace sh
18 : {
19 :
20 : namespace
21 : {
22 :
23 : // Traverser that separates one array expression into a statement at a time.
24 0 : class SeparateExpressionsTraverser : public TIntermTraverser
25 : {
26 : public:
27 : SeparateExpressionsTraverser();
28 :
29 : bool visitBinary(Visit visit, TIntermBinary *node) override;
30 : bool visitAggregate(Visit visit, TIntermAggregate *node) override;
31 :
32 : void nextIteration();
33 0 : bool foundArrayExpression() const { return mFoundArrayExpression; }
34 :
35 : protected:
36 : // Marked to true once an operation that needs to be hoisted out of the expression has been found.
37 : // After that, no more AST updates are performed on that traversal.
38 : bool mFoundArrayExpression;
39 :
40 : IntermNodePatternMatcher mPatternToSeparateMatcher;
41 : };
42 :
43 0 : SeparateExpressionsTraverser::SeparateExpressionsTraverser()
44 : : TIntermTraverser(true, false, false),
45 : mFoundArrayExpression(false),
46 0 : mPatternToSeparateMatcher(IntermNodePatternMatcher::kExpressionReturningArray)
47 : {
48 0 : }
49 :
50 : // Performs a shallow copy of an assignment node.
51 : // These shallow copies are useful when a node gets inserted into an aggregate node
52 : // and also needs to be replaced in its original location by a different node.
53 0 : TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
54 : {
55 0 : return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight());
56 : }
57 :
58 : // Performs a shallow copy of a constructor/function call node.
59 0 : TIntermAggregate *CopyAggregateNode(TIntermAggregate *node)
60 : {
61 0 : TIntermAggregate *copyNode = new TIntermAggregate(node->getOp());
62 0 : TIntermSequence *copySeq = copyNode->getSequence();
63 0 : copySeq->insert(copySeq->begin(), node->getSequence()->begin(), node->getSequence()->end());
64 0 : copyNode->setType(node->getType());
65 0 : *copyNode->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
66 0 : if (node->isUserDefined())
67 : {
68 0 : copyNode->setUserDefined();
69 : }
70 0 : return copyNode;
71 : }
72 :
73 0 : bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
74 : {
75 0 : if (mFoundArrayExpression)
76 0 : return false;
77 :
78 : // Return if the expression is not an array or if we're not inside a complex expression.
79 0 : if (!mPatternToSeparateMatcher.match(node, getParentNode()))
80 0 : return true;
81 :
82 0 : ASSERT(node->getOp() == EOpAssign);
83 :
84 0 : mFoundArrayExpression = true;
85 :
86 0 : TIntermSequence insertions;
87 0 : insertions.push_back(CopyAssignmentNode(node));
88 : // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just
89 : // use the original target of the assignment. Care must be taken so that this doesn't happen
90 : // when the same array symbol is a target of assignment more than once in one expression.
91 0 : insertions.push_back(createTempInitDeclaration(node->getLeft()));
92 0 : insertStatementsInParentBlock(insertions);
93 :
94 0 : queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
95 :
96 0 : return false;
97 : }
98 :
99 0 : bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
100 : {
101 0 : if (mFoundArrayExpression)
102 0 : return false; // No need to traverse further
103 :
104 0 : if (!mPatternToSeparateMatcher.match(node, getParentNode()))
105 0 : return true;
106 :
107 0 : ASSERT(node->isConstructor() || node->getOp() == EOpFunctionCall);
108 :
109 0 : mFoundArrayExpression = true;
110 :
111 0 : TIntermSequence insertions;
112 0 : insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node)));
113 0 : insertStatementsInParentBlock(insertions);
114 :
115 0 : queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
116 :
117 0 : return false;
118 : }
119 :
120 0 : void SeparateExpressionsTraverser::nextIteration()
121 : {
122 0 : mFoundArrayExpression = false;
123 0 : nextTemporaryIndex();
124 0 : }
125 :
126 : } // namespace
127 :
128 0 : void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex)
129 : {
130 0 : SeparateExpressionsTraverser traverser;
131 0 : ASSERT(temporaryIndex != nullptr);
132 0 : traverser.useTemporaryIndex(temporaryIndex);
133 : // Separate one expression at a time, and reset the traverser between iterations.
134 0 : do
135 : {
136 0 : traverser.nextIteration();
137 0 : root->traverse(&traverser);
138 0 : if (traverser.foundArrayExpression())
139 0 : traverser.updateTree();
140 : }
141 : while (traverser.foundArrayExpression());
142 0 : }
143 :
144 : } // namespace sh
|