• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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