1 // 2 // Copyright (c) 2002-2013 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 7 #include "compiler/UnfoldShortCircuitAST.h" 8 9 namespace 10 { 11 12 // "x || y" is equivalent to "x ? true : y". 13 TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y) 14 { 15 const TType boolType(EbtBool, EbpUndefined); 16 ConstantUnion *u = new ConstantUnion; 17 u->setBConst(true); 18 TIntermConstantUnion *trueNode = new TIntermConstantUnion( 19 u, TType(EbtBool, EbpUndefined, EvqConst, 1)); 20 return new TIntermSelection(x, trueNode, y, boolType); 21 } 22 23 // "x && y" is equivalent to "x ? y : false". 24 TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y) 25 { 26 const TType boolType(EbtBool, EbpUndefined); 27 ConstantUnion *u = new ConstantUnion; 28 u->setBConst(false); 29 TIntermConstantUnion *falseNode = new TIntermConstantUnion( 30 u, TType(EbtBool, EbpUndefined, EvqConst, 1)); 31 return new TIntermSelection(x, y, falseNode, boolType); 32 } 33 34 } // namespace anonymous 35 36 bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) 37 { 38 TIntermSelection *replacement = NULL; 39 40 switch (node->getOp()) 41 { 42 case EOpLogicalOr: 43 replacement = UnfoldOR(node->getLeft(), node->getRight()); 44 break; 45 case EOpLogicalAnd: 46 replacement = UnfoldAND(node->getLeft(), node->getRight()); 47 break; 48 default: 49 break; 50 } 51 if (replacement) 52 { 53 replacements.push_back( 54 NodeUpdateEntry(getParentNode(), node, replacement)); 55 } 56 return true; 57 } 58 59 void UnfoldShortCircuitAST::updateTree() 60 { 61 for (size_t ii = 0; ii < replacements.size(); ++ii) 62 { 63 const NodeUpdateEntry& entry = replacements[ii]; 64 ASSERT(entry.parent); 65 bool replaced = entry.parent->replaceChildNode( 66 entry.original, entry.replacement); 67 ASSERT(replaced); 68 69 // In AST traversing, a parent is visited before its children. 70 // After we replace a node, if an immediate child is to 71 // be replaced, we need to make sure we don't update the replaced 72 // node; instead, we update the replacement node. 73 for (size_t jj = ii + 1; jj < replacements.size(); ++jj) 74 { 75 NodeUpdateEntry& entry2 = replacements[jj]; 76 if (entry2.parent == entry.original) 77 entry2.parent = entry.replacement; 78 } 79 } 80 } 81 82