| // |
| // Copyright (c) 2002-2013 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. |
| // |
| |
| #include "compiler/UnfoldShortCircuitAST.h" |
| |
| namespace |
| { |
| |
| // "x || y" is equivalent to "x ? true : y". |
| TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y) |
| { |
| const TType boolType(EbtBool, EbpUndefined); |
| ConstantUnion *u = new ConstantUnion; |
| u->setBConst(true); |
| TIntermConstantUnion *trueNode = new TIntermConstantUnion( |
| u, TType(EbtBool, EbpUndefined, EvqConst, 1)); |
| return new TIntermSelection(x, trueNode, y, boolType); |
| } |
| |
| // "x && y" is equivalent to "x ? y : false". |
| TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y) |
| { |
| const TType boolType(EbtBool, EbpUndefined); |
| ConstantUnion *u = new ConstantUnion; |
| u->setBConst(false); |
| TIntermConstantUnion *falseNode = new TIntermConstantUnion( |
| u, TType(EbtBool, EbpUndefined, EvqConst, 1)); |
| return new TIntermSelection(x, y, falseNode, boolType); |
| } |
| |
| } // namespace anonymous |
| |
| bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) |
| { |
| TIntermSelection *replacement = NULL; |
| |
| switch (node->getOp()) |
| { |
| case EOpLogicalOr: |
| replacement = UnfoldOR(node->getLeft(), node->getRight()); |
| break; |
| case EOpLogicalAnd: |
| replacement = UnfoldAND(node->getLeft(), node->getRight()); |
| break; |
| default: |
| break; |
| } |
| if (replacement) |
| { |
| replacements.push_back( |
| NodeUpdateEntry(getParentNode(), node, replacement)); |
| } |
| return true; |
| } |
| |
| void UnfoldShortCircuitAST::updateTree() |
| { |
| for (size_t ii = 0; ii < replacements.size(); ++ii) |
| { |
| const NodeUpdateEntry& entry = replacements[ii]; |
| ASSERT(entry.parent); |
| bool replaced = entry.parent->replaceChildNode( |
| entry.original, entry.replacement); |
| ASSERT(replaced); |
| |
| // In AST traversing, a parent is visited before its children. |
| // After we replace a node, if an immediate child is to |
| // be replaced, we need to make sure we don't update the replaced |
| // node; instead, we update the replacement node. |
| for (size_t jj = ii + 1; jj < replacements.size(); ++jj) |
| { |
| NodeUpdateEntry& entry2 = replacements[jj]; |
| if (entry2.parent == entry.original) |
| entry2.parent = entry.replacement; |
| } |
| } |
| } |
| |