Commit 3cbb27a1 by Olli Etuaho Committed by Commit Bot

Simplify loop conditions so that they won't generate statements

Introduce an AST traverser that can move the evaluation of certain types of loop conditions and loop expressions inside the loop. This way subsequent AST transformations don't have to worry about cases where they have to insert new statements to implement a loop condition or expression. This includes the revert of "Unfold short-circuiting operators in loop conditions correctly". The new traverser covers the loop cases that used to be handled in UnfoldShortCircuitToIf. BUG=angleproject:1465 TEST=WebGL conformance tests, dEQP-GLES2.functional.shaders.*select_iteration_count* Change-Id: I88e50e007e924d5884a217117690ac7fa2f96d38 Reviewed-on: https://chromium-review.googlesource.com/362570Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 66fb8206
...@@ -188,6 +188,8 @@ ...@@ -188,6 +188,8 @@
'compiler/translator/SeparateDeclarations.h', 'compiler/translator/SeparateDeclarations.h',
'compiler/translator/SeparateExpressionsReturningArrays.cpp', 'compiler/translator/SeparateExpressionsReturningArrays.cpp',
'compiler/translator/SeparateExpressionsReturningArrays.h', 'compiler/translator/SeparateExpressionsReturningArrays.h',
'compiler/translator/SimplifyLoopConditions.cpp',
'compiler/translator/SimplifyLoopConditions.h',
'compiler/translator/SplitSequenceOperator.cpp', 'compiler/translator/SplitSequenceOperator.cpp',
'compiler/translator/SplitSequenceOperator.h', 'compiler/translator/SplitSequenceOperator.h',
'compiler/translator/StructureHLSL.cpp', 'compiler/translator/StructureHLSL.cpp',
......
...@@ -197,6 +197,7 @@ void TIntermTyped::setTypePreservePrecision(const TType &t) ...@@ -197,6 +197,7 @@ void TIntermTyped::setTypePreservePrecision(const TType &t)
bool TIntermLoop::replaceChildNode( bool TIntermLoop::replaceChildNode(
TIntermNode *original, TIntermNode *replacement) TIntermNode *original, TIntermNode *replacement)
{ {
ASSERT(original != nullptr); // This risks replacing multiple children.
REPLACE_IF_IS(mInit, TIntermNode, original, replacement); REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
REPLACE_IF_IS(mCond, TIntermTyped, original, replacement); REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement); REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
......
...@@ -195,6 +195,10 @@ class TIntermLoop : public TIntermNode ...@@ -195,6 +195,10 @@ class TIntermLoop : public TIntermNode
TIntermTyped *getExpression() { return mExpr; } TIntermTyped *getExpression() { return mExpr; }
TIntermAggregate *getBody() { return mBody; } TIntermAggregate *getBody() { return mBody; }
void setCondition(TIntermTyped *condition) { mCond = condition; }
void setExpression(TIntermTyped *expression) { mExpr = expression; }
void setBody(TIntermAggregate *body) { mBody = body; }
void setUnrollFlag(bool flag) { mUnrollFlag = flag; } void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
bool getUnrollFlag() const { return mUnrollFlag; } bool getUnrollFlag() const { return mUnrollFlag; }
...@@ -912,9 +916,9 @@ class TLValueTrackingTraverser : public TIntermTraverser ...@@ -912,9 +916,9 @@ class TLValueTrackingTraverser : public TIntermTraverser
} }
virtual ~TLValueTrackingTraverser() {} virtual ~TLValueTrackingTraverser() {}
void traverseBinary(TIntermBinary *node) override; void traverseBinary(TIntermBinary *node) final;
void traverseUnary(TIntermUnary *node) override; void traverseUnary(TIntermUnary *node) final;
void traverseAggregate(TIntermAggregate *node) override; void traverseAggregate(TIntermAggregate *node) final;
protected: protected:
bool isLValueRequiredHere() const bool isLValueRequiredHere() const
......
//
// Copyright (c) 2016 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.
//
// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions
// to regular statements inside the loop. This way further transformations that generate statements
// from loop conditions and loop expressions work correctly.
//
#include "compiler/translator/SimplifyLoopConditions.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"
namespace
{
TIntermConstantUnion *CreateBoolConstantNode(bool value)
{
TConstantUnion *u = new TConstantUnion;
u->setBConst(value);
TIntermConstantUnion *node =
new TIntermConstantUnion(u, TType(EbtBool, EbpUndefined, EvqConst, 1));
return node;
}
class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
{
public:
SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask,
const TSymbolTable &symbolTable,
int shaderVersion);
void traverseLoop(TIntermLoop *node) override;
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
void nextIteration();
bool foundLoopToChange() const { return mFoundLoopToChange; }
protected:
// Marked to true once an operation that needs to be hoisted out of the expression has been
// found. After that, no more AST updates are performed on that traversal.
bool mFoundLoopToChange;
bool mInsideLoopConditionOrExpression;
IntermNodePatternMatcher mConditionsToSimplify;
};
SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
unsigned int conditionsToSimplifyMask,
const TSymbolTable &symbolTable,
int shaderVersion)
: TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
mFoundLoopToChange(false),
mInsideLoopConditionOrExpression(false),
mConditionsToSimplify(conditionsToSimplifyMask)
{
}
void SimplifyLoopConditionsTraverser::nextIteration()
{
mFoundLoopToChange = false;
mInsideLoopConditionOrExpression = false;
nextTemporaryIndex();
}
bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
{
// The visit functions operate in three modes:
// 1. If a matching expression has already been found, we return early since only one loop can
// be transformed on one traversal.
// 2. We try to find loops. In case a node is not inside a loop and can not contain loops, we
// stop traversing the subtree.
// 3. If we're inside a loop condition or expression, we check for expressions that should be
// moved out of the loop condition or expression. If one is found, the loop is processed.
if (mFoundLoopToChange)
return false;
if (!mInsideLoopConditionOrExpression)
return false;
mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
return !mFoundLoopToChange;
}
bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
if (mFoundLoopToChange)
return false;
// If we're outside a loop condition, we only need to traverse nodes that may contain loops.
if (!mInsideLoopConditionOrExpression)
return (node->getOp() == EOpSequence || node->getOp() == EOpFunction);
mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
return !mFoundLoopToChange;
}
bool SimplifyLoopConditionsTraverser::visitSelection(Visit visit, TIntermSelection *node)
{
if (mFoundLoopToChange)
return false;
// Don't traverse ternary operators outside loop conditions.
if (!mInsideLoopConditionOrExpression)
return !node->usesTernaryOperator();
mFoundLoopToChange = mConditionsToSimplify.match(node);
return !mFoundLoopToChange;
}
void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
{
if (mFoundLoopToChange)
return;
// Mark that we're inside a loop condition or expression, and transform the loop if needed.
incrementDepth(node);
// Note: No need to traverse the loop init node.
mInsideLoopConditionOrExpression = true;
TLoopType loopType = node->getType();
if (node->getCondition())
{
node->getCondition()->traverse(this);
if (mFoundLoopToChange)
{
// Replace the loop condition with a boolean variable that's updated on each iteration.
if (loopType == ELoopWhile)
{
// Transform:
// while (expr) { body; }
// into
// bool s0 = expr;
// while (s0) { { body; } s0 = expr; }
TIntermSequence tempInitSeq;
tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy()));
insertStatementsInParentBlock(tempInitSeq);
TIntermAggregate *newBody = new TIntermAggregate(EOpSequence);
if (node->getBody())
{
ASSERT(node->getBody()->getOp() == EOpSequence);
newBody->getSequence()->push_back(node->getBody());
}
newBody->getSequence()->push_back(
createTempAssignment(node->getCondition()->deepCopy()));
// Can't use queueReplacement to replace old body, since it may have been nullptr.
// It's safe to do the replacements in place here - this node won't be traversed
// further.
node->setBody(newBody);
node->setCondition(createTempSymbol(node->getCondition()->getType()));
}
else if (loopType == ELoopDoWhile)
{
// Transform:
// do {
// body;
// } while (expr);
// into
// bool s0 = true;
// do {
// { body; }
// s0 = expr;
// while (s0);
TIntermSequence tempInitSeq;
tempInitSeq.push_back(createTempInitDeclaration(CreateBoolConstantNode(true)));
insertStatementsInParentBlock(tempInitSeq);
TIntermAggregate *newBody = new TIntermAggregate(EOpSequence);
if (node->getBody())
{
ASSERT(node->getBody()->getOp() == EOpSequence);
newBody->getSequence()->push_back(node->getBody());
}
newBody->getSequence()->push_back(
createTempAssignment(node->getCondition()->deepCopy()));
// Can't use queueReplacement to replace old body, since it may have been nullptr.
// It's safe to do the replacements in place here - this node won't be traversed
// further.
node->setBody(newBody);
node->setCondition(createTempSymbol(node->getCondition()->getType()));
}
else if (loopType == ELoopFor)
{
// Move the loop condition inside the loop.
// Transform:
// for (init; expr; exprB) { body; }
// into
// {
// init;
// bool s0 = expr;
// while (s0) { { body; } exprB; s0 = expr; }
// }
TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence);
if (node->getInit())
{
loopScope->getSequence()->push_back(node->getInit());
}
loopScope->getSequence()->push_back(
createTempInitDeclaration(node->getCondition()->deepCopy()));
TIntermAggregate *whileLoopBody = new TIntermAggregate(EOpSequence);
if (node->getBody())
{
whileLoopBody->getSequence()->push_back(node->getBody());
}
whileLoopBody->getSequence()->push_back(node->getExpression());
whileLoopBody->getSequence()->push_back(
createTempAssignment(node->getCondition()->deepCopy()));
TIntermLoop *whileLoop = new TIntermLoop(
ELoopWhile, nullptr, createTempSymbol(node->getCondition()->getType()), nullptr,
whileLoopBody);
loopScope->getSequence()->push_back(whileLoop);
queueReplacementWithParent(getAncestorNode(1), node, loopScope,
OriginalNode::IS_DROPPED);
}
}
}
if (!mFoundLoopToChange && node->getExpression())
{
node->getExpression()->traverse(this);
if (mFoundLoopToChange)
{
ASSERT(loopType == ELoopFor);
// Move the loop expression to inside the loop.
// Transform:
// for (init; expr; exprB) { body; }
// into
// for (init; expr; ) { { body; } exprB; }
TIntermTyped *loopExpression = node->getExpression();
node->setExpression(nullptr);
TIntermAggregate *oldBody = node->getBody();
node->setBody(new TIntermAggregate(EOpSequence));
if (oldBody != nullptr)
{
node->getBody()->getSequence()->push_back(oldBody);
}
node->getBody()->getSequence()->push_back(loopExpression);
}
}
mInsideLoopConditionOrExpression = false;
if (!mFoundLoopToChange && node->getBody())
node->getBody()->traverse(this);
decrementDepth();
}
} // namespace
void SimplifyLoopConditions(TIntermNode *root,
unsigned int conditionsToSimplifyMask,
unsigned int *temporaryIndex,
const TSymbolTable &symbolTable,
int shaderVersion)
{
SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable, shaderVersion);
ASSERT(temporaryIndex != nullptr);
traverser.useTemporaryIndex(temporaryIndex);
// Process one loop at a time, and reset the traverser between iterations.
do
{
traverser.nextIteration();
root->traverse(&traverser);
if (traverser.foundLoopToChange())
traverser.updateTree();
} while (traverser.foundLoopToChange());
}
//
// Copyright (c) 2016 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.
//
// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions
// to regular statements inside the loop. This way further transformations that generate statements
// from loop conditions and loop expressions work correctly.
//
#ifndef COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_
#define COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_
class TIntermNode;
class TSymbolTable;
void SimplifyLoopConditions(TIntermNode *root,
unsigned int conditionsToSimplify,
unsigned int *temporaryIndex,
const TSymbolTable &symbolTable,
int shaderVersion);
#endif // COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "compiler/translator/SeparateArrayInitialization.h" #include "compiler/translator/SeparateArrayInitialization.h"
#include "compiler/translator/SeparateDeclarations.h" #include "compiler/translator/SeparateDeclarations.h"
#include "compiler/translator/SeparateExpressionsReturningArrays.h" #include "compiler/translator/SeparateExpressionsReturningArrays.h"
#include "compiler/translator/SimplifyLoopConditions.h"
#include "compiler/translator/SplitSequenceOperator.h" #include "compiler/translator/SplitSequenceOperator.h"
#include "compiler/translator/UnfoldShortCircuitToIf.h" #include "compiler/translator/UnfoldShortCircuitToIf.h"
...@@ -34,9 +35,14 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) ...@@ -34,9 +35,14 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
SeparateDeclarations(root); SeparateDeclarations(root);
// TODO (oetuaho): Sequence operators should also be split in case there is dynamic indexing of // Note that SimplifyLoopConditions needs to be run before any other AST transformations that
// a vector or matrix as an l-value inside (RemoveDynamicIndexing transformation step generates // may need to generate new statements from loop conditions or loop expressions.
// statements in this case). SimplifyLoopConditions(root,
IntermNodePatternMatcher::kExpressionReturningArray |
IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
getTemporaryIndex(), getSymbolTable(), getShaderVersion());
SplitSequenceOperator(root, SplitSequenceOperator(root,
IntermNodePatternMatcher::kExpressionReturningArray | IntermNodePatternMatcher::kExpressionReturningArray |
IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
......
...@@ -23,43 +23,22 @@ class UnfoldShortCircuitTraverser : public TIntermTraverser ...@@ -23,43 +23,22 @@ class UnfoldShortCircuitTraverser : public TIntermTraverser
UnfoldShortCircuitTraverser(); UnfoldShortCircuitTraverser();
bool visitBinary(Visit visit, TIntermBinary *node) override; bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override; bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitLoop(Visit visit, TIntermLoop *node) override;
void nextIteration(); void nextIteration();
bool foundShortCircuit() const { return mFoundShortCircuit; } bool foundShortCircuit() const { return mFoundShortCircuit; }
protected: 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. // Marked to true once an operation that needs to be unfolded has been found.
// After that, no more unfolding is performed on that traversal. // After that, no more unfolding is performed on that traversal.
bool mFoundShortCircuit; 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; IntermNodePatternMatcher mPatternToUnfoldMatcher;
}; };
UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser() UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser()
: TIntermTraverser(true, false, true), : TIntermTraverser(true, false, true),
mFoundShortCircuit(false), mFoundShortCircuit(false),
mParentLoop(nullptr),
mLoopParent(nullptr),
mInLoopCondition(false),
mInLoopExpression(false),
mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression) mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression)
{ {
} }
...@@ -85,7 +64,6 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) ...@@ -85,7 +64,6 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
switch (node->getOp()) switch (node->getOp())
{ {
case EOpLogicalOr: case EOpLogicalOr:
if (!copyLoopConditionOrExpression(getParentNode(), node))
{ {
// "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true;
// else s = y;", // else s = y;",
...@@ -109,10 +87,9 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) ...@@ -109,10 +87,9 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
insertStatementsInParentBlock(insertions); insertStatementsInParentBlock(insertions);
queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED); queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED);
}
return false; return false;
}
case EOpLogicalAnd: case EOpLogicalAnd:
if (!copyLoopConditionOrExpression(getParentNode(), node))
{ {
// "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y;
// else s = false;", // else s = false;",
...@@ -127,14 +104,15 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) ...@@ -127,14 +104,15 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
ASSERT(node->getRight()->getType() == boolType); ASSERT(node->getRight()->getType() == boolType);
assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight())); assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
TIntermSelection *ifNode = new TIntermSelection(createTempSymbol(boolType), assignRightBlock, nullptr); TIntermSelection *ifNode =
new TIntermSelection(createTempSymbol(boolType), assignRightBlock, nullptr);
insertions.push_back(ifNode); insertions.push_back(ifNode);
insertStatementsInParentBlock(insertions); insertStatementsInParentBlock(insertions);
queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED); queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED);
}
return false; return false;
}
default: default:
UNREACHABLE(); UNREACHABLE();
return true; return true;
...@@ -157,8 +135,6 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection * ...@@ -157,8 +135,6 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *
ASSERT(node->usesTernaryOperator()); ASSERT(node->usesTernaryOperator());
// Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
if (!copyLoopConditionOrExpression(getParentNode(), node))
{
TIntermSequence insertions; TIntermSequence insertions;
TIntermSymbol *tempSymbol = createTempSymbol(node->getType()); TIntermSymbol *tempSymbol = createTempSymbol(node->getType());
...@@ -182,172 +158,7 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection * ...@@ -182,172 +158,7 @@ bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *
TIntermSymbol *ternaryResult = createTempSymbol(node->getType()); TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
queueReplacement(node, ternaryResult, OriginalNode::IS_DROPPED); queueReplacement(node, ternaryResult, OriginalNode::IS_DROPPED);
}
return false;
}
bool UnfoldShortCircuitTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
if (visit == PreVisit && mFoundShortCircuit)
return false; // No need to traverse further
if (node->getOp() == EOpComma)
{
ASSERT(visit != PreVisit || !mFoundShortCircuit);
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.
clearReplacementQueue();
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);
queueReplacement(node, (*seq)[i], OriginalNode::IS_DROPPED);
}
}
}
return 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);
if (node->getInit())
{
node->getInit()->traverse(this);
if (mFoundShortCircuit)
{
decrementDepth();
return false;
}
}
if (node->getCondition())
{
mInLoopCondition = true;
node->getCondition()->traverse(this);
mInLoopCondition = false;
if (mFoundShortCircuit)
{
decrementDepth();
return false;
}
}
if (node->getExpression())
{
mInLoopExpression = true;
node->getExpression()->traverse(this);
mInLoopExpression = false;
if (mFoundShortCircuit)
{
decrementDepth();
return false;
}
}
if (node->getBody())
node->getBody()->traverse(this);
decrementDepth();
}
return false;
}
bool UnfoldShortCircuitTraverser::copyLoopConditionOrExpression(TIntermNode *parent,
TIntermTyped *node)
{
if (mInLoopCondition)
{
queueReplacementWithParent(parent, node, createTempSymbol(node->getType()),
OriginalNode::IS_DROPPED);
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.
queueReplacementWithParent(mParentLoop, initializer, nullptr,
OriginalNode::IS_DROPPED);
loopScope->getSequence()->push_back(initializer);
}
loopScope->getSequence()->push_back(createTempInitDeclaration(node));
loopScope->getSequence()->push_back(mParentLoop);
queueReplacementWithParent(mLoopParent, mParentLoop, loopScope,
OriginalNode::BECOMES_CHILD);
// 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;
}
if (mInLoopExpression)
{
TIntermTyped *movedExpression = mParentLoop->getExpression();
queueReplacementWithParent(mParentLoop, movedExpression, nullptr, OriginalNode::IS_DROPPED);
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; return false;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment