SplitSequenceOperator.cpp (5537B)
1 // 2 // Copyright 2016 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 // SplitSequenceOperator is an AST traverser that detects sequence operator expressions that 7 // go through further AST transformations that generate statements, and splits them so that 8 // possible side effects of earlier parts of the sequence operator expression are guaranteed to be 9 // evaluated before the latter parts of the sequence operator expression are evaluated. 10 // 11 12 #include "compiler/translator/tree_ops/SplitSequenceOperator.h" 13 14 #include "compiler/translator/tree_util/IntermNodePatternMatcher.h" 15 #include "compiler/translator/tree_util/IntermTraverse.h" 16 17 namespace sh 18 { 19 20 namespace 21 { 22 23 class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser 24 { 25 public: 26 SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, TSymbolTable *symbolTable); 27 28 bool visitUnary(Visit visit, TIntermUnary *node) override; 29 bool visitBinary(Visit visit, TIntermBinary *node) override; 30 bool visitAggregate(Visit visit, TIntermAggregate *node) override; 31 bool visitTernary(Visit visit, TIntermTernary *node) override; 32 33 void nextIteration(); 34 bool foundExpressionToSplit() const { return mFoundExpressionToSplit; } 35 36 protected: 37 // Marked to true once an operation that needs to be hoisted out of the expression has been 38 // found. After that, no more AST updates are performed on that traversal. 39 bool mFoundExpressionToSplit; 40 int mInsideSequenceOperator; 41 42 IntermNodePatternMatcher mPatternToSplitMatcher; 43 }; 44 45 SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, 46 TSymbolTable *symbolTable) 47 : TLValueTrackingTraverser(true, false, true, symbolTable), 48 mFoundExpressionToSplit(false), 49 mInsideSequenceOperator(0), 50 mPatternToSplitMatcher(patternsToSplitMask) 51 {} 52 53 void SplitSequenceOperatorTraverser::nextIteration() 54 { 55 mFoundExpressionToSplit = false; 56 mInsideSequenceOperator = 0; 57 } 58 59 bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node) 60 { 61 if (mFoundExpressionToSplit) 62 return false; 63 64 if (mInsideSequenceOperator > 0 && visit == PreVisit) 65 { 66 // Detect expressions that need to be simplified 67 mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode()); 68 return !mFoundExpressionToSplit; 69 } 70 71 return true; 72 } 73 74 bool SplitSequenceOperatorTraverser::visitUnary(Visit visit, TIntermUnary *node) 75 { 76 if (mFoundExpressionToSplit) 77 return false; 78 79 if (mInsideSequenceOperator > 0 && visit == PreVisit) 80 { 81 // Detect expressions that need to be simplified 82 mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); 83 return !mFoundExpressionToSplit; 84 } 85 86 return true; 87 } 88 89 bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node) 90 { 91 if (node->getOp() == EOpComma) 92 { 93 if (visit == PreVisit) 94 { 95 if (mFoundExpressionToSplit) 96 { 97 return false; 98 } 99 mInsideSequenceOperator++; 100 } 101 else if (visit == PostVisit) 102 { 103 // Split sequence operators starting from the outermost one to preserve correct 104 // execution order. 105 if (mFoundExpressionToSplit && mInsideSequenceOperator == 1) 106 { 107 // Move the left side operand into a separate statement in the parent block. 108 TIntermSequence insertions; 109 insertions.push_back(node->getLeft()); 110 insertStatementsInParentBlock(insertions); 111 // Replace the comma node with its right side operand. 112 queueReplacement(node->getRight(), OriginalNode::IS_DROPPED); 113 } 114 mInsideSequenceOperator--; 115 } 116 return true; 117 } 118 119 if (mFoundExpressionToSplit) 120 return false; 121 122 if (mInsideSequenceOperator > 0 && visit == PreVisit) 123 { 124 // Detect expressions that need to be simplified 125 mFoundExpressionToSplit = 126 mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere()); 127 return !mFoundExpressionToSplit; 128 } 129 130 return true; 131 } 132 133 bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node) 134 { 135 if (mFoundExpressionToSplit) 136 return false; 137 138 if (mInsideSequenceOperator > 0 && visit == PreVisit) 139 { 140 // Detect expressions that need to be simplified 141 mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); 142 return !mFoundExpressionToSplit; 143 } 144 145 return true; 146 } 147 148 } // namespace 149 150 bool SplitSequenceOperator(TCompiler *compiler, 151 TIntermNode *root, 152 int patternsToSplitMask, 153 TSymbolTable *symbolTable) 154 { 155 SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable); 156 // Separate one expression at a time, and reset the traverser between iterations. 157 do 158 { 159 traverser.nextIteration(); 160 root->traverse(&traverser); 161 if (traverser.foundExpressionToSplit()) 162 { 163 if (!traverser.updateTree(compiler, root)) 164 { 165 return false; 166 } 167 } 168 } while (traverser.foundExpressionToSplit()); 169 170 return true; 171 } 172 173 } // namespace sh