michael@0: // michael@0: // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: // UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements. michael@0: // The results are assigned to s# temporaries, which are used by the main translator instead of michael@0: // the original expression. michael@0: // michael@0: michael@0: #include "compiler/UnfoldShortCircuit.h" michael@0: michael@0: #include "compiler/InfoSink.h" michael@0: #include "compiler/OutputHLSL.h" michael@0: michael@0: namespace sh michael@0: { michael@0: UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL) michael@0: { michael@0: mTemporaryIndex = 0; michael@0: } michael@0: michael@0: void UnfoldShortCircuit::traverse(TIntermNode *node) michael@0: { michael@0: int rewindIndex = mTemporaryIndex; michael@0: node->traverse(this); michael@0: mTemporaryIndex = rewindIndex; michael@0: } michael@0: michael@0: bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) michael@0: { michael@0: TInfoSinkBase &out = mOutputHLSL->getBodyStream(); michael@0: michael@0: switch (node->getOp()) michael@0: { michael@0: case EOpLogicalOr: michael@0: // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;", michael@0: // and then further simplifies down to "bool s = x; if(!s) s = y;". michael@0: { michael@0: int i = mTemporaryIndex; michael@0: michael@0: out << "bool s" << i << ";\n"; michael@0: michael@0: out << "{\n"; michael@0: michael@0: mTemporaryIndex = i + 1; michael@0: node->getLeft()->traverse(this); michael@0: out << "s" << i << " = "; michael@0: mTemporaryIndex = i + 1; michael@0: node->getLeft()->traverse(mOutputHLSL); michael@0: out << ";\n"; michael@0: out << "if(!s" << i << ")\n" michael@0: "{\n"; michael@0: mTemporaryIndex = i + 1; michael@0: node->getRight()->traverse(this); michael@0: out << " s" << i << " = "; michael@0: mTemporaryIndex = i + 1; michael@0: node->getRight()->traverse(mOutputHLSL); michael@0: out << ";\n" michael@0: "}\n"; michael@0: michael@0: out << "}\n"; michael@0: michael@0: mTemporaryIndex = i + 1; michael@0: } michael@0: return false; michael@0: case EOpLogicalAnd: michael@0: // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;", michael@0: // and then further simplifies down to "bool s = x; if(s) s = y;". michael@0: { michael@0: int i = mTemporaryIndex; michael@0: michael@0: out << "bool s" << i << ";\n"; michael@0: michael@0: out << "{\n"; michael@0: michael@0: mTemporaryIndex = i + 1; michael@0: node->getLeft()->traverse(this); michael@0: out << "s" << i << " = "; michael@0: mTemporaryIndex = i + 1; michael@0: node->getLeft()->traverse(mOutputHLSL); michael@0: out << ";\n"; michael@0: out << "if(s" << i << ")\n" michael@0: "{\n"; michael@0: mTemporaryIndex = i + 1; michael@0: node->getRight()->traverse(this); michael@0: out << " s" << i << " = "; michael@0: mTemporaryIndex = i + 1; michael@0: node->getRight()->traverse(mOutputHLSL); michael@0: out << ";\n" michael@0: "}\n"; michael@0: michael@0: out << "}\n"; michael@0: michael@0: mTemporaryIndex = i + 1; michael@0: } michael@0: return false; michael@0: default: michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) michael@0: { michael@0: TInfoSinkBase &out = mOutputHLSL->getBodyStream(); michael@0: michael@0: // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" michael@0: if (node->usesTernaryOperator()) michael@0: { michael@0: int i = mTemporaryIndex; michael@0: michael@0: out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n"; michael@0: michael@0: out << "{\n"; michael@0: michael@0: mTemporaryIndex = i + 1; michael@0: node->getCondition()->traverse(this); michael@0: out << "if("; michael@0: mTemporaryIndex = i + 1; michael@0: node->getCondition()->traverse(mOutputHLSL); michael@0: out << ")\n" michael@0: "{\n"; michael@0: mTemporaryIndex = i + 1; michael@0: node->getTrueBlock()->traverse(this); michael@0: out << " s" << i << " = "; michael@0: mTemporaryIndex = i + 1; michael@0: node->getTrueBlock()->traverse(mOutputHLSL); michael@0: out << ";\n" michael@0: "}\n" michael@0: "else\n" michael@0: "{\n"; michael@0: mTemporaryIndex = i + 1; michael@0: node->getFalseBlock()->traverse(this); michael@0: out << " s" << i << " = "; michael@0: mTemporaryIndex = i + 1; michael@0: node->getFalseBlock()->traverse(mOutputHLSL); michael@0: out << ";\n" michael@0: "}\n"; michael@0: michael@0: out << "}\n"; michael@0: michael@0: mTemporaryIndex = i + 1; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node) michael@0: { michael@0: int rewindIndex = mTemporaryIndex; michael@0: michael@0: if (node->getInit()) michael@0: { michael@0: node->getInit()->traverse(this); michael@0: } michael@0: michael@0: if (node->getCondition()) michael@0: { michael@0: node->getCondition()->traverse(this); michael@0: } michael@0: michael@0: if (node->getExpression()) michael@0: { michael@0: node->getExpression()->traverse(this); michael@0: } michael@0: michael@0: mTemporaryIndex = rewindIndex; michael@0: michael@0: return false; michael@0: } michael@0: michael@0: int UnfoldShortCircuit::getNextTemporaryIndex() michael@0: { michael@0: return mTemporaryIndex++; michael@0: } michael@0: }