| // | |
| // 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. | |
| // | |
| // UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements. | |
| // The results are assigned to s# temporaries, which are used by the main translator instead of | |
| // the original expression. | |
| // | |
| #include "compiler/UnfoldShortCircuit.h" | |
| #include "compiler/InfoSink.h" | |
| #include "compiler/OutputHLSL.h" | |
| namespace sh | |
| { | |
| UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL) | |
| { | |
| mTemporaryIndex = 0; | |
| } | |
| void UnfoldShortCircuit::traverse(TIntermNode *node) | |
| { | |
| int rewindIndex = mTemporaryIndex; | |
| node->traverse(this); | |
| mTemporaryIndex = rewindIndex; | |
| } | |
| bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) | |
| { | |
| TInfoSinkBase &out = mOutputHLSL->getBodyStream(); | |
| switch (node->getOp()) | |
| { | |
| case EOpLogicalOr: | |
| // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;", | |
| // and then further simplifies down to "bool s = x; if(!s) s = y;". | |
| { | |
| int i = mTemporaryIndex; | |
| out << "bool s" << i << ";\n"; | |
| out << "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getLeft()->traverse(this); | |
| out << "s" << i << " = "; | |
| mTemporaryIndex = i + 1; | |
| node->getLeft()->traverse(mOutputHLSL); | |
| out << ";\n"; | |
| out << "if(!s" << i << ")\n" | |
| "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getRight()->traverse(this); | |
| out << " s" << i << " = "; | |
| mTemporaryIndex = i + 1; | |
| node->getRight()->traverse(mOutputHLSL); | |
| out << ";\n" | |
| "}\n"; | |
| out << "}\n"; | |
| mTemporaryIndex = i + 1; | |
| } | |
| return false; | |
| case EOpLogicalAnd: | |
| // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;", | |
| // and then further simplifies down to "bool s = x; if(s) s = y;". | |
| { | |
| int i = mTemporaryIndex; | |
| out << "bool s" << i << ";\n"; | |
| out << "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getLeft()->traverse(this); | |
| out << "s" << i << " = "; | |
| mTemporaryIndex = i + 1; | |
| node->getLeft()->traverse(mOutputHLSL); | |
| out << ";\n"; | |
| out << "if(s" << i << ")\n" | |
| "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getRight()->traverse(this); | |
| out << " s" << i << " = "; | |
| mTemporaryIndex = i + 1; | |
| node->getRight()->traverse(mOutputHLSL); | |
| out << ";\n" | |
| "}\n"; | |
| out << "}\n"; | |
| mTemporaryIndex = i + 1; | |
| } | |
| return false; | |
| default: | |
| return true; | |
| } | |
| } | |
| bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) | |
| { | |
| TInfoSinkBase &out = mOutputHLSL->getBodyStream(); | |
| // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" | |
| if (node->usesTernaryOperator()) | |
| { | |
| int i = mTemporaryIndex; | |
| out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n"; | |
| out << "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getCondition()->traverse(this); | |
| out << "if("; | |
| mTemporaryIndex = i + 1; | |
| node->getCondition()->traverse(mOutputHLSL); | |
| out << ")\n" | |
| "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getTrueBlock()->traverse(this); | |
| out << " s" << i << " = "; | |
| mTemporaryIndex = i + 1; | |
| node->getTrueBlock()->traverse(mOutputHLSL); | |
| out << ";\n" | |
| "}\n" | |
| "else\n" | |
| "{\n"; | |
| mTemporaryIndex = i + 1; | |
| node->getFalseBlock()->traverse(this); | |
| out << " s" << i << " = "; | |
| mTemporaryIndex = i + 1; | |
| node->getFalseBlock()->traverse(mOutputHLSL); | |
| out << ";\n" | |
| "}\n"; | |
| out << "}\n"; | |
| mTemporaryIndex = i + 1; | |
| } | |
| return false; | |
| } | |
| bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node) | |
| { | |
| int rewindIndex = mTemporaryIndex; | |
| if (node->getInit()) | |
| { | |
| node->getInit()->traverse(this); | |
| } | |
| if (node->getCondition()) | |
| { | |
| node->getCondition()->traverse(this); | |
| } | |
| if (node->getExpression()) | |
| { | |
| node->getExpression()->traverse(this); | |
| } | |
| mTemporaryIndex = rewindIndex; | |
| return false; | |
| } | |
| int UnfoldShortCircuit::getNextTemporaryIndex() | |
| { | |
| return mTemporaryIndex++; | |
| } | |
| } |