| // |
| // Copyright (c) 2016 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. |
| // |
| // SplitSequenceOperator is an AST traverser that detects sequence operator expressions that |
| // go through further AST transformations that generate statements, and splits them so that |
| // possible side effects of earlier parts of the sequence operator expression are guaranteed to be |
| // evaluated before the latter parts of the sequence operator expression are evaluated. |
| // |
| |
| #include "compiler/translator/SplitSequenceOperator.h" |
| |
| #include "compiler/translator/IntermNode.h" |
| #include "compiler/translator/IntermNodePatternMatcher.h" |
| |
| namespace sh |
| { |
| |
| namespace |
| { |
| |
| class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser |
| { |
| public: |
| SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, |
| const TSymbolTable &symbolTable, |
| int shaderVersion); |
| |
| bool visitBinary(Visit visit, TIntermBinary *node) override; |
| bool visitAggregate(Visit visit, TIntermAggregate *node) override; |
| bool visitTernary(Visit visit, TIntermTernary *node) override; |
| |
| void nextIteration(); |
| bool foundExpressionToSplit() const { return mFoundExpressionToSplit; } |
| |
| 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 mFoundExpressionToSplit; |
| int mInsideSequenceOperator; |
| |
| IntermNodePatternMatcher mPatternToSplitMatcher; |
| }; |
| |
| SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, |
| const TSymbolTable &symbolTable, |
| int shaderVersion) |
| : TLValueTrackingTraverser(true, false, true, symbolTable, shaderVersion), |
| mFoundExpressionToSplit(false), |
| mInsideSequenceOperator(0), |
| mPatternToSplitMatcher(patternsToSplitMask) |
| { |
| } |
| |
| void SplitSequenceOperatorTraverser::nextIteration() |
| { |
| mFoundExpressionToSplit = false; |
| mInsideSequenceOperator = 0; |
| nextTemporaryIndex(); |
| } |
| |
| bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node) |
| { |
| if (mFoundExpressionToSplit) |
| return false; |
| |
| if (mInsideSequenceOperator > 0 && visit == PreVisit) |
| { |
| // Detect expressions that need to be simplified |
| mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode()); |
| return !mFoundExpressionToSplit; |
| } |
| |
| return true; |
| } |
| |
| bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node) |
| { |
| if (node->getOp() == EOpComma) |
| { |
| if (visit == PreVisit) |
| { |
| if (mFoundExpressionToSplit) |
| { |
| return false; |
| } |
| mInsideSequenceOperator++; |
| } |
| else if (visit == PostVisit) |
| { |
| // Split sequence operators starting from the outermost one to preserve correct |
| // execution order. |
| if (mFoundExpressionToSplit && mInsideSequenceOperator == 1) |
| { |
| // Move the left side operand into a separate statement in the parent block. |
| TIntermSequence insertions; |
| insertions.push_back(node->getLeft()); |
| insertStatementsInParentBlock(insertions); |
| // Replace the comma node with its right side operand. |
| queueReplacement(node, node->getRight(), OriginalNode::IS_DROPPED); |
| } |
| mInsideSequenceOperator--; |
| } |
| return true; |
| } |
| |
| if (mFoundExpressionToSplit) |
| return false; |
| |
| if (mInsideSequenceOperator > 0 && visit == PreVisit) |
| { |
| // Detect expressions that need to be simplified |
| mFoundExpressionToSplit = |
| mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere()); |
| return !mFoundExpressionToSplit; |
| } |
| |
| return true; |
| } |
| |
| bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node) |
| { |
| if (mFoundExpressionToSplit) |
| return false; |
| |
| if (mInsideSequenceOperator > 0 && visit == PreVisit) |
| { |
| // Detect expressions that need to be simplified |
| mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); |
| return !mFoundExpressionToSplit; |
| } |
| |
| return true; |
| } |
| |
| } // namespace |
| |
| void SplitSequenceOperator(TIntermNode *root, |
| int patternsToSplitMask, |
| unsigned int *temporaryIndex, |
| const TSymbolTable &symbolTable, |
| int shaderVersion) |
| { |
| SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable, shaderVersion); |
| ASSERT(temporaryIndex != nullptr); |
| traverser.useTemporaryIndex(temporaryIndex); |
| // Separate one expression at a time, and reset the traverser between iterations. |
| do |
| { |
| traverser.nextIteration(); |
| root->traverse(&traverser); |
| if (traverser.foundExpressionToSplit()) |
| traverser.updateTree(); |
| } while (traverser.foundExpressionToSplit()); |
| } |
| |
| } // namespace sh |