diff options
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.cpp')
-rw-r--r-- | gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.cpp new file mode 100644 index 0000000000..58d8a0a9be --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.cpp @@ -0,0 +1,138 @@ +// +// Copyright 2002 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. +// +// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names +// from more complex expressions, assigning them to a temporary variable a#. +// Examples where a, b and c are all arrays: +// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2; +// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i]; + +#include "compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.h" + +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// Traverser that separates one array expression into a statement at a time. +class SeparateExpressionsTraverser : public TIntermTraverser +{ + public: + SeparateExpressionsTraverser(TSymbolTable *symbolTable); + + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + void nextIteration(); + bool foundArrayExpression() const { return mFoundArrayExpression; } + + protected: + // Marked to true once an operation that needs to be hoisted out of the expression has been + // found. After that, no more AST updates are performed on that traversal. + bool mFoundArrayExpression; + + IntermNodePatternMatcher mPatternToSeparateMatcher; +}; + +SeparateExpressionsTraverser::SeparateExpressionsTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), + mFoundArrayExpression(false), + mPatternToSeparateMatcher(IntermNodePatternMatcher::kExpressionReturningArray) +{} + +// Performs a shallow copy of an assignment node. +// These shallow copies are useful when a node gets inserted into an aggregate node +// and also needs to be replaced in its original location by a different node. +TIntermBinary *CopyAssignmentNode(TIntermBinary *node) +{ + return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight()); +} + +bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (mFoundArrayExpression) + return false; + + // Return if the expression is not an array or if we're not inside a complex expression. + if (!mPatternToSeparateMatcher.match(node, getParentNode())) + return true; + + ASSERT(node->getOp() == EOpAssign); + + mFoundArrayExpression = true; + + TIntermSequence insertions; + insertions.push_back(CopyAssignmentNode(node)); + // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just + // use the original target of the assignment. Care must be taken so that this doesn't happen + // when the same array symbol is a target of assignment more than once in one expression. + TIntermDeclaration *arrayVariableDeclaration; + TVariable *arrayVariable = + DeclareTempVariable(mSymbolTable, node->getLeft(), EvqTemporary, &arrayVariableDeclaration); + insertions.push_back(arrayVariableDeclaration); + insertStatementsInParentBlock(insertions); + + queueReplacement(CreateTempSymbolNode(arrayVariable), OriginalNode::IS_DROPPED); + + return false; +} + +bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFoundArrayExpression) + return false; // No need to traverse further + + if (!mPatternToSeparateMatcher.match(node, getParentNode())) + return true; + + ASSERT(node->isConstructor() || node->getOp() == EOpCallFunctionInAST); + + mFoundArrayExpression = true; + + TIntermDeclaration *arrayVariableDeclaration; + TVariable *arrayVariable = DeclareTempVariable(mSymbolTable, node->shallowCopy(), EvqTemporary, + &arrayVariableDeclaration); + insertStatementInParentBlock(arrayVariableDeclaration); + + queueReplacement(CreateTempSymbolNode(arrayVariable), OriginalNode::IS_DROPPED); + + return false; +} + +void SeparateExpressionsTraverser::nextIteration() +{ + mFoundArrayExpression = false; +} + +} // namespace + +bool SeparateExpressionsReturningArrays(TCompiler *compiler, + TIntermNode *root, + TSymbolTable *symbolTable) +{ + SeparateExpressionsTraverser traverser(symbolTable); + // Separate one expression at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundArrayExpression()) + { + if (!traverser.updateTree(compiler, root)) + { + return false; + } + } + } while (traverser.foundArrayExpression()); + + return true; +} + +} // namespace sh |