blob: f6f029cc1cb9d3eb02845761901bd0faee4926c9 [file] [log] [blame]
Olli Etuahobb5a7e22017-08-30 13:03:12 +03001//
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#include "compiler/translator/RemoveArrayLengthMethod.h"
21
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/IntermTraverse.h"
24
25namespace sh
26{
27
28namespace
29{
30
31class RemoveArrayLengthTraverser : public TIntermTraverser
32{
33 public:
34 RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {}
35
36 bool visitUnary(Visit visit, TIntermUnary *node) override;
37
38 void nextIteration() { mFoundArrayLength = false; }
39
40 bool foundArrayLength() const { return mFoundArrayLength; }
41
42 private:
43 bool mFoundArrayLength;
44};
45
46bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node)
47{
48 if (node->getOp() == EOpArrayLength)
49 {
50 mFoundArrayLength = true;
51 if (!node->getOperand()->hasSideEffects())
52 {
53 queueReplacement(node->fold(nullptr), OriginalNode::IS_DROPPED);
54 return false;
55 }
56 insertStatementInParentBlock(node->getOperand()->deepCopy());
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
66} // anonymous namespace
67
68void RemoveArrayLengthMethod(TIntermBlock *root)
69{
70 RemoveArrayLengthTraverser traverser;
71 do
72 {
73 traverser.nextIteration();
74 root->traverse(&traverser);
75 if (traverser.foundArrayLength())
76 traverser.updateTree();
77 } while (traverser.foundArrayLength());
78}
79
80} // namespace sh