| // |
| // 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++; |
| } |
| } |