blob: 02d7f35e1f122e165fbb3e859857004e86d39b82 [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.
Olli Etuahoebee5b32017-11-23 12:56:32 +020019//
20// Does nothing to length method calls done on runtime-sized arrays.
Olli Etuahobb5a7e22017-08-30 13:03:12 +030021
22#include "compiler/translator/RemoveArrayLengthMethod.h"
23
24#include "compiler/translator/IntermNode.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020025#include "compiler/translator/tree_util/IntermTraverse.h"
Olli Etuahobb5a7e22017-08-30 13:03:12 +030026
27namespace sh
28{
29
30namespace
31{
32
33class 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
48bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node)
49{
Olli Etuahoebee5b32017-11-23 12:56:32 +020050 // The only case where we leave array length() in place is for runtime-sized arrays.
51 if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray())
Olli Etuahobb5a7e22017-08-30 13:03:12 +030052 {
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
71void 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