1 | // |
2 | // Copyright (c) 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: |
36 | RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {} |
37 | |
38 | bool visitUnary(Visit visit, TIntermUnary *node) override; |
39 | |
40 | void nextIteration() { mFoundArrayLength = false; } |
41 | |
42 | bool foundArrayLength() const { return mFoundArrayLength; } |
43 | |
44 | private: |
45 | bool mFoundArrayLength; |
46 | }; |
47 | |
48 | bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node) |
49 | { |
50 | // The only case where we leave array length() in place is for runtime-sized arrays. |
51 | if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray()) |
52 | { |
53 | mFoundArrayLength = true; |
54 | if (!node->getOperand()->hasSideEffects()) |
55 | { |
56 | queueReplacement(node->fold(nullptr), OriginalNode::IS_DROPPED); |
57 | return false; |
58 | } |
59 | insertStatementInParentBlock(node->getOperand()->deepCopy()); |
60 | TConstantUnion *constArray = new TConstantUnion[1]; |
61 | constArray->setIConst(node->getOperand()->getOutermostArraySize()); |
62 | queueReplacement(new TIntermConstantUnion(constArray, node->getType()), |
63 | OriginalNode::IS_DROPPED); |
64 | return false; |
65 | } |
66 | return true; |
67 | } |
68 | |
69 | } // anonymous namespace |
70 | |
71 | void RemoveArrayLengthMethod(TIntermBlock *root) |
72 | { |
73 | RemoveArrayLengthTraverser traverser; |
74 | do |
75 | { |
76 | traverser.nextIteration(); |
77 | root->traverse(&traverser); |
78 | if (traverser.foundArrayLength()) |
79 | traverser.updateTree(); |
80 | } while (traverser.foundArrayLength()); |
81 | } |
82 | |
83 | } // namespace sh |
84 | |