RemoveArrayLengthMethod.cpp (3284B)
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: 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 void insertSideEffectsInParentBlock(TIntermTyped *node); 46 47 bool mFoundArrayLength; 48 }; 49 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 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 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