1 //
2 // Copyright 2017 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 // RemoveArrayLengthMethod.cpp:
7 // Fold array length expressions, including cases where the "this" node has side effects.
8 // Example:
9 // int i = (a = b).length();
10 // int j = (func()).length();
11 // becomes:
12 // (a = b);
13 // int i = <constant array length>;
14 // func();
15 // int j = <constant array length>;
16 //
17 // Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps
18 // have been done to expressions containing calls of the array length method.
19 //
20 // Does nothing to length method calls done on runtime-sized arrays.
21
22 #include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h"
23
24 #include "compiler/translator/IntermNode.h"
25 #include "compiler/translator/tree_util/IntermTraverse.h"
26
27 namespace sh
28 {
29
30 namespace
31 {
32
33 class RemoveArrayLengthTraverser : public TIntermTraverser
34 {
35 public:
RemoveArrayLengthTraverser()36 RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {}
37
38 bool visitUnary(Visit visit, TIntermUnary *node) override;
39
nextIteration()40 void nextIteration() { mFoundArrayLength = false; }
41
foundArrayLength() const42 bool foundArrayLength() const { return mFoundArrayLength; }
43
44 private:
45 void insertSideEffectsInParentBlock(TIntermTyped *node);
46
47 bool mFoundArrayLength;
48 };
49
visitUnary(Visit visit,TIntermUnary * node)50 bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node)
51 {
52 // The only case where we leave array length() in place is for runtime-sized arrays.
53 if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray())
54 {
55 mFoundArrayLength = true;
56 insertSideEffectsInParentBlock(node->getOperand());
57 TConstantUnion *constArray = new TConstantUnion[1];
58 constArray->setIConst(node->getOperand()->getOutermostArraySize());
59 queueReplacement(new TIntermConstantUnion(constArray, node->getType()),
60 OriginalNode::IS_DROPPED);
61 return false;
62 }
63 return true;
64 }
65
insertSideEffectsInParentBlock(TIntermTyped * node)66 void RemoveArrayLengthTraverser::insertSideEffectsInParentBlock(TIntermTyped *node)
67 {
68 // If the node is an index type, traverse it and add the indices as side effects. If at the end
69 // an expression without side effect is encountered, such as an opaque uniform or a lone symbol,
70 // don't generate a statement for it.
71 if (!node->hasSideEffects())
72 {
73 return;
74 }
75
76 TIntermBinary *asBinary = node->getAsBinaryNode();
77 if (asBinary && !asBinary->isAssignment())
78 {
79 insertSideEffectsInParentBlock(asBinary->getLeft());
80 insertSideEffectsInParentBlock(asBinary->getRight());
81 }
82 else
83 {
84 insertStatementInParentBlock(node);
85 }
86 }
87
88 } // anonymous namespace
89
RemoveArrayLengthMethod(TCompiler * compiler,TIntermBlock * root)90 bool RemoveArrayLengthMethod(TCompiler *compiler, TIntermBlock *root)
91 {
92 RemoveArrayLengthTraverser traverser;
93 do
94 {
95 traverser.nextIteration();
96 root->traverse(&traverser);
97 if (traverser.foundArrayLength())
98 {
99 if (!traverser.updateTree(compiler, root))
100 {
101 return false;
102 }
103 }
104 } while (traverser.foundArrayLength());
105
106 return true;
107 }
108
109 } // namespace sh
110