// // Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // RemoveArrayLengthMethod.cpp: // Fold array length expressions, including cases where the "this" node has side effects. // Example: // int i = (a = b).length(); // int j = (func()).length(); // becomes: // (a = b); // int i = ; // func(); // int j = ; // // Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps // have been done to expressions containing calls of the array length method. // // Does nothing to length method calls done on runtime-sized arrays. #include "compiler/translator/RemoveArrayLengthMethod.h" #include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermTraverse.h" namespace sh { namespace { class RemoveArrayLengthTraverser : public TIntermTraverser { public: RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {} bool visitUnary(Visit visit, TIntermUnary *node) override; void nextIteration() { mFoundArrayLength = false; } bool foundArrayLength() const { return mFoundArrayLength; } private: bool mFoundArrayLength; }; bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node) { // The only case where we leave array length() in place is for runtime-sized arrays. if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray()) { mFoundArrayLength = true; if (!node->getOperand()->hasSideEffects()) { queueReplacement(node->fold(nullptr), OriginalNode::IS_DROPPED); return false; } insertStatementInParentBlock(node->getOperand()->deepCopy()); TConstantUnion *constArray = new TConstantUnion[1]; constArray->setIConst(node->getOperand()->getOutermostArraySize()); queueReplacement(new TIntermConstantUnion(constArray, node->getType()), OriginalNode::IS_DROPPED); return false; } return true; } } // anonymous namespace void RemoveArrayLengthMethod(TIntermBlock *root) { RemoveArrayLengthTraverser traverser; do { traverser.nextIteration(); root->traverse(&traverser); if (traverser.foundArrayLength()) traverser.updateTree(); } while (traverser.foundArrayLength()); } } // namespace sh