| // | |
| // Copyright 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 = <constant array length>; | |
| // func(); | |
| // int j = <constant array length>; | |
| // | |
| // 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/tree_ops/RemoveArrayLengthMethod.h" | |
| #include "compiler/translator/IntermNode.h" | |
| #include "compiler/translator/tree_util/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 | |
| bool RemoveArrayLengthMethod(TCompiler *compiler, TIntermBlock *root) | |
| { | |
| RemoveArrayLengthTraverser traverser; | |
| do | |
| { | |
| traverser.nextIteration(); | |
| root->traverse(&traverser); | |
| if (traverser.foundArrayLength()) | |
| { | |
| if (!traverser.updateTree(compiler, root)) | |
| { | |
| return false; | |
| } | |
| } | |
| } while (traverser.foundArrayLength()); | |
| return true; | |
| } | |
| } // namespace sh |