summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp318
1 files changed, 68 insertions, 250 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
index be23b524d7..774f1fc704 100644
--- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
@@ -3,14 +3,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else statements.
+// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else
+// statements.
// The results are assigned to s# temporaries, which are used by the main translator instead of
// the original expression.
//
#include "compiler/translator/UnfoldShortCircuitToIf.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IntermTraverse.h"
+
+namespace sh
+{
namespace
{
@@ -19,44 +24,26 @@ namespace
class UnfoldShortCircuitTraverser : public TIntermTraverser
{
public:
- UnfoldShortCircuitTraverser();
+ UnfoldShortCircuitTraverser(TSymbolTable *symbolTable);
bool visitBinary(Visit visit, TIntermBinary *node) override;
- bool visitAggregate(Visit visit, TIntermAggregate *node) override;
- bool visitSelection(Visit visit, TIntermSelection *node) override;
- bool visitLoop(Visit visit, TIntermLoop *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
void nextIteration();
bool foundShortCircuit() const { return mFoundShortCircuit; }
protected:
- // Check if the traversal is inside a loop condition or expression, in which case the unfolded
- // expression needs to be copied inside the loop. Returns true if the copying is done, in which
- // case no further unfolding should be done on the same traversal.
- // The parameters are the node that will be unfolded to multiple statements and so can't remain
- // inside a loop condition, and its parent.
- bool copyLoopConditionOrExpression(TIntermNode *parent, TIntermTyped *node);
-
// Marked to true once an operation that needs to be unfolded has been found.
// After that, no more unfolding is performed on that traversal.
bool mFoundShortCircuit;
- // Set to the loop node while a loop condition or expression is being traversed.
- TIntermLoop *mParentLoop;
- // Parent of the loop node while a loop condition or expression is being traversed.
- TIntermNode *mLoopParent;
-
- bool mInLoopCondition;
- bool mInLoopExpression;
+ IntermNodePatternMatcher mPatternToUnfoldMatcher;
};
-UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser()
- : TIntermTraverser(true, false, true),
+UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable),
mFoundShortCircuit(false),
- mParentLoop(nullptr),
- mLoopParent(nullptr),
- mInLoopCondition(false),
- mInLoopExpression(false)
+ mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression)
{
}
@@ -64,19 +51,23 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
{
if (mFoundShortCircuit)
return false;
+
+ if (visit != PreVisit)
+ return true;
+
+ if (!mPatternToUnfoldMatcher.match(node, getParentNode()))
+ return true;
+
// If our right node doesn't have side effects, we know we don't need to unfold this
// expression: there will be no short-circuiting side effects to avoid
// (note: unfolding doesn't depend on the left node -- it will always be evaluated)
- if (!node->getRight()->hasSideEffects())
- {
- return true;
- }
+ ASSERT(node->getRight()->hasSideEffects());
+
+ mFoundShortCircuit = true;
switch (node->getOp())
{
- case EOpLogicalOr:
- mFoundShortCircuit = true;
- if (!copyLoopConditionOrExpression(getParentNode(), node))
+ case EOpLogicalOr:
{
// "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true;
// else s = y;",
@@ -88,24 +79,21 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
ASSERT(node->getLeft()->getType() == boolType);
insertions.push_back(createTempInitDeclaration(node->getLeft()));
- TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
+ TIntermBlock *assignRightBlock = new TIntermBlock();
ASSERT(node->getRight()->getType() == boolType);
assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
- TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, boolType);
- notTempSymbol->setOperand(createTempSymbol(boolType));
- TIntermSelection *ifNode = new TIntermSelection(notTempSymbol, assignRightBlock, nullptr);
+ TIntermUnary *notTempSymbol =
+ new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType));
+ TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr);
insertions.push_back(ifNode);
insertStatementsInParentBlock(insertions);
- NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
- mReplacements.push_back(replaceVariable);
+ queueReplacement(createTempSymbol(boolType), OriginalNode::IS_DROPPED);
+ return false;
}
- return false;
- case EOpLogicalAnd:
- mFoundShortCircuit = true;
- if (!copyLoopConditionOrExpression(getParentNode(), node))
+ case EOpLogicalAnd:
{
// "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y;
// else s = false;",
@@ -116,246 +104,75 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
ASSERT(node->getLeft()->getType() == boolType);
insertions.push_back(createTempInitDeclaration(node->getLeft()));
- TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
+ TIntermBlock *assignRightBlock = new TIntermBlock();
ASSERT(node->getRight()->getType() == boolType);
assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
- TIntermSelection *ifNode = new TIntermSelection(createTempSymbol(boolType), assignRightBlock, nullptr);
+ TIntermIfElse *ifNode =
+ new TIntermIfElse(createTempSymbol(boolType), assignRightBlock, nullptr);
insertions.push_back(ifNode);
insertStatementsInParentBlock(insertions);
- NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
- mReplacements.push_back(replaceVariable);
+ queueReplacement(createTempSymbol(boolType), OriginalNode::IS_DROPPED);
+ return false;
}
- return false;
- default:
- return true;
+ default:
+ UNREACHABLE();
+ return true;
}
}
-bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *node)
+bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
if (mFoundShortCircuit)
return false;
- // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
- if (visit == PreVisit && node->usesTernaryOperator())
- {
- mFoundShortCircuit = true;
- if (!copyLoopConditionOrExpression(getParentNode(), node))
- {
- TIntermSequence insertions;
-
- TIntermSymbol *tempSymbol = createTempSymbol(node->getType());
- TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
- tempDeclaration->getSequence()->push_back(tempSymbol);
- insertions.push_back(tempDeclaration);
-
- TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
- TIntermBinary *trueAssignment =
- createTempAssignment(node->getTrueBlock()->getAsTyped());
- trueBlock->getSequence()->push_back(trueAssignment);
-
- TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
- TIntermBinary *falseAssignment =
- createTempAssignment(node->getFalseBlock()->getAsTyped());
- falseBlock->getSequence()->push_back(falseAssignment);
-
- TIntermSelection *ifNode =
- new TIntermSelection(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
- insertions.push_back(ifNode);
-
- insertStatementsInParentBlock(insertions);
-
- TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
- NodeUpdateEntry replaceVariable(getParentNode(), node, ternaryResult, false);
- mReplacements.push_back(replaceVariable);
- }
- return false;
- }
-
- return true;
-}
-
-bool UnfoldShortCircuitTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
-{
- if (visit == PreVisit && mFoundShortCircuit)
- return false; // No need to traverse further
+ if (visit != PreVisit)
+ return true;
- if (node->getOp() == EOpComma)
- {
- ASSERT(visit != PreVisit || !mFoundShortCircuit);
+ if (!mPatternToUnfoldMatcher.match(node))
+ return true;
- if (visit == PostVisit && mFoundShortCircuit)
- {
- // We can be sure that we arrived here because there was a short-circuiting operator
- // inside the sequence operator since we only start traversing the sequence operator in
- // case a short-circuiting operator has not been found so far.
- // We need to unfold the sequence (comma) operator, otherwise the evaluation order of
- // statements would be messed up by unfolded operations inside.
- // Don't do any other unfolding on this round of traversal.
- mReplacements.clear();
- mMultiReplacements.clear();
- mInsertions.clear();
-
- if (!copyLoopConditionOrExpression(getParentNode(), node))
- {
- TIntermSequence insertions;
- TIntermSequence *seq = node->getSequence();
-
- TIntermSequence::size_type i = 0;
- ASSERT(!seq->empty());
- while (i < seq->size() - 1)
- {
- TIntermTyped *child = (*seq)[i]->getAsTyped();
- insertions.push_back(child);
- ++i;
- }
-
- insertStatementsInParentBlock(insertions);
-
- NodeUpdateEntry replaceVariable(getParentNode(), node, (*seq)[i], false);
- mReplacements.push_back(replaceVariable);
- }
- }
- }
- return true;
-}
+ mFoundShortCircuit = true;
-bool UnfoldShortCircuitTraverser::visitLoop(Visit visit, TIntermLoop *node)
-{
- if (visit == PreVisit)
- {
- if (mFoundShortCircuit)
- return false; // No need to traverse further
-
- mLoopParent = getParentNode();
- mParentLoop = node;
- incrementDepth(node);
+ // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
+ TIntermSequence insertions;
- if (node->getInit())
- {
- node->getInit()->traverse(this);
- if (mFoundShortCircuit)
- {
- decrementDepth();
- return false;
- }
- }
+ TIntermDeclaration *tempDeclaration = createTempDeclaration(node->getType());
+ insertions.push_back(tempDeclaration);
- if (node->getCondition())
- {
- mInLoopCondition = true;
- node->getCondition()->traverse(this);
- mInLoopCondition = false;
-
- if (mFoundShortCircuit)
- {
- decrementDepth();
- return false;
- }
- }
+ TIntermBlock *trueBlock = new TIntermBlock();
+ TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression());
+ trueBlock->getSequence()->push_back(trueAssignment);
- if (node->getExpression())
- {
- mInLoopExpression = true;
- node->getExpression()->traverse(this);
- mInLoopExpression = false;
-
- if (mFoundShortCircuit)
- {
- decrementDepth();
- return false;
- }
- }
+ TIntermBlock *falseBlock = new TIntermBlock();
+ TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression());
+ falseBlock->getSequence()->push_back(falseAssignment);
- if (node->getBody())
- node->getBody()->traverse(this);
+ TIntermIfElse *ifNode =
+ new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
+ insertions.push_back(ifNode);
- decrementDepth();
- }
- return false;
-}
+ insertStatementsInParentBlock(insertions);
-bool UnfoldShortCircuitTraverser::copyLoopConditionOrExpression(TIntermNode *parent,
- TIntermTyped *node)
-{
- if (mInLoopCondition)
- {
- mReplacements.push_back(
- NodeUpdateEntry(parent, node, createTempSymbol(node->getType()), false));
- TIntermAggregate *body = mParentLoop->getBody();
- TIntermSequence empty;
- if (mParentLoop->getType() == ELoopDoWhile)
- {
- // Declare the temporary variable before the loop.
- TIntermSequence insertionsBeforeLoop;
- insertionsBeforeLoop.push_back(createTempDeclaration(node->getType()));
- insertStatementsInParentBlock(insertionsBeforeLoop);
-
- // Move a part of do-while loop condition to inside the loop.
- TIntermSequence insertionsInLoop;
- insertionsInLoop.push_back(createTempAssignment(node));
- mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1,
- empty, insertionsInLoop));
- }
- else
- {
- // The loop initializer expression and one copy of the part of the loop condition are
- // executed before the loop. They need to be in a new scope.
- TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence);
-
- TIntermNode *initializer = mParentLoop->getInit();
- if (initializer != nullptr)
- {
- // Move the initializer to the newly created outer scope, so that condition can
- // depend on it.
- mReplacements.push_back(NodeUpdateEntry(mParentLoop, initializer, nullptr, false));
- loopScope->getSequence()->push_back(initializer);
- }
-
- loopScope->getSequence()->push_back(createTempInitDeclaration(node));
- loopScope->getSequence()->push_back(mParentLoop);
- mReplacements.push_back(NodeUpdateEntry(mLoopParent, mParentLoop, loopScope, true));
-
- // The second copy of the part of the loop condition is executed inside the loop.
- TIntermSequence insertionsInLoop;
- insertionsInLoop.push_back(createTempAssignment(node->deepCopy()));
- mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1,
- empty, insertionsInLoop));
- }
- return true;
- }
+ TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
+ queueReplacement(ternaryResult, OriginalNode::IS_DROPPED);
- if (mInLoopExpression)
- {
- TIntermTyped *movedExpression = mParentLoop->getExpression();
- mReplacements.push_back(NodeUpdateEntry(mParentLoop, movedExpression, nullptr, false));
- TIntermAggregate *body = mParentLoop->getBody();
- TIntermSequence empty;
- TIntermSequence insertions;
- insertions.push_back(movedExpression);
- mInsertions.push_back(
- NodeInsertMultipleEntry(body, body->getSequence()->size() - 1, empty, insertions));
- return true;
- }
return false;
}
void UnfoldShortCircuitTraverser::nextIteration()
{
mFoundShortCircuit = false;
- nextTemporaryIndex();
+ nextTemporaryId();
}
-} // namespace
+} // namespace
-void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex)
+void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable)
{
- UnfoldShortCircuitTraverser traverser;
- ASSERT(temporaryIndex != nullptr);
- traverser.useTemporaryIndex(temporaryIndex);
+ UnfoldShortCircuitTraverser traverser(symbolTable);
// Unfold one operator at a time, and reset the traverser between iterations.
do
{
@@ -363,6 +180,7 @@ void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex)
root->traverse(&traverser);
if (traverser.foundShortCircuit())
traverser.updateTree();
- }
- while (traverser.foundShortCircuit());
+ } while (traverser.foundShortCircuit());
}
+
+} // namespace sh