Commit 1212bcac by Corentin Wallez Committed by Commit Bot

translator: separate declarations after rewriting loops

Otherwise when trying to add the declarations back, things might fail because the loop initialization is a sequence and not a block. BUG=668028 Change-Id: I8d84a25c25765e9655c16ce56604ae08f0f8176c Reviewed-on: https://chromium-review.googlesource.com/414305 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 00cf8940
......@@ -106,4 +106,13 @@ bool IntermNodePatternMatcher::match(TIntermTernary *node)
return false;
}
bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
{
if ((mMask & kMultiDeclaration) != 0)
{
return node->getSequence()->size() > 1;
}
return false;
}
} // namespace sh
......@@ -18,6 +18,7 @@ class TIntermAggregate;
class TIntermBinary;
class TIntermNode;
class TIntermTernary;
class TIntermDeclaration;
class IntermNodePatternMatcher
{
......@@ -34,7 +35,10 @@ class IntermNodePatternMatcher
kExpressionReturningArray = 0x0002,
// Matches dynamic indexing of vectors or matrices in l-values.
kDynamicIndexingOfVectorOrMatrixInLValue = 0x0004
kDynamicIndexingOfVectorOrMatrixInLValue = 0x0004,
// Matches declarations with more than one declared variables
kMultiDeclaration = 0x0008,
};
IntermNodePatternMatcher(const unsigned int mask);
......@@ -46,6 +50,7 @@ class IntermNodePatternMatcher
bool match(TIntermAggregate *node, TIntermNode *parentNode);
bool match(TIntermTernary *node);
bool match(TIntermDeclaration *node);
private:
const unsigned int mMask;
......
......@@ -40,6 +40,7 @@ class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
void nextIteration();
bool foundLoopToChange() const { return mFoundLoopToChange; }
......@@ -48,7 +49,7 @@ class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
// 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;
bool mInsideLoopInitConditionOrExpression;
IntermNodePatternMatcher mConditionsToSimplify;
};
......@@ -58,7 +59,7 @@ SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
int shaderVersion)
: TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
mFoundLoopToChange(false),
mInsideLoopConditionOrExpression(false),
mInsideLoopInitConditionOrExpression(false),
mConditionsToSimplify(conditionsToSimplifyMask)
{
}
......@@ -66,24 +67,25 @@ SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
void SimplifyLoopConditionsTraverser::nextIteration()
{
mFoundLoopToChange = false;
mInsideLoopConditionOrExpression = false;
mInsideLoopInitConditionOrExpression = false;
nextTemporaryIndex();
}
// 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 initialization, 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.
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)
if (!mInsideLoopInitConditionOrExpression)
return false;
mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
......@@ -95,8 +97,7 @@ bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggrega
if (mFoundLoopToChange)
return false;
// If we're outside a loop condition, we only need to traverse nodes that may contain loops.
if (!mInsideLoopConditionOrExpression)
if (!mInsideLoopInitConditionOrExpression)
return false;
mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
......@@ -108,8 +109,19 @@ bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *
if (mFoundLoopToChange)
return false;
// Don't traverse ternary operators outside loop conditions.
if (!mInsideLoopConditionOrExpression)
if (!mInsideLoopInitConditionOrExpression)
return false;
mFoundLoopToChange = mConditionsToSimplify.match(node);
return !mFoundLoopToChange;
}
bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
if (mFoundLoopToChange)
return false;
if (!mInsideLoopInitConditionOrExpression)
return false;
mFoundLoopToChange = mConditionsToSimplify.match(node);
......@@ -127,136 +139,122 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
// Note: No need to traverse the loop init node.
mInsideLoopConditionOrExpression = true;
TLoopType loopType = node->getType();
mInsideLoopInitConditionOrExpression = true;
TLoopType loopType = node->getType();
if (node->getCondition())
if (!mFoundLoopToChange && node->getInit())
{
node->getInit()->traverse(this);
}
if (!mFoundLoopToChange && node->getCondition())
{
node->getCondition()->traverse(this);
}
if (!mFoundLoopToChange && node->getExpression())
{
node->getExpression()->traverse(this);
}
if (mFoundLoopToChange)
if (mFoundLoopToChange)
{
// Replace the loop condition with a boolean variable that's updated on each iteration.
if (loopType == ELoopWhile)
{
// 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);
TIntermBlock *newBody = new TIntermBlock();
if (node->getBody())
{
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:
// while (expr) { body; }
// into
// bool s0 = expr;
// while (s0) { { body; } s0 = expr; }
TIntermSequence tempInitSeq;
tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy()));
insertStatementsInParentBlock(tempInitSeq);
TIntermBlock *newBody = new TIntermBlock();
if (node->getBody())
{
// 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);
TIntermBlock *newBody = new TIntermBlock();
if (node->getBody())
{
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()));
newBody->getSequence()->push_back(node->getBody());
}
else if (loopType == ELoopFor)
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);
TIntermBlock *newBody = new TIntermBlock();
if (node->getBody())
{
// Move the loop condition inside the loop.
// Transform:
// for (init; expr; exprB) { body; }
// into
// {
// init;
// bool s0 = expr;
// while (s0) { { body; } exprB; s0 = expr; }
// }
TIntermBlock *loopScope = new TIntermBlock();
if (node->getInit())
{
loopScope->getSequence()->push_back(node->getInit());
}
loopScope->getSequence()->push_back(
createTempInitDeclaration(node->getCondition()->deepCopy()));
TIntermBlock *whileLoopBody = new TIntermBlock();
if (node->getBody())
{
whileLoopBody->getSequence()->push_back(node->getBody());
}
if (node->getExpression())
{
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);
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()));
}
}
if (!mFoundLoopToChange && node->getExpression())
{
node->getExpression()->traverse(this);
if (mFoundLoopToChange)
else if (loopType == ELoopFor)
{
ASSERT(loopType == ELoopFor);
// Move the loop expression to inside the loop.
// Move the loop condition inside the loop.
// Transform:
// for (init; expr; exprB) { body; }
// into
// for (init; expr; ) { { body; } exprB; }
TIntermTyped *loopExpression = node->getExpression();
node->setExpression(nullptr);
TIntermBlock *oldBody = node->getBody();
node->setBody(new TIntermBlock());
if (oldBody != nullptr)
// {
// init;
// bool s0 = expr;
// while (s0) { { body; } exprB; s0 = expr; }
// }
TIntermBlock *loopScope = new TIntermBlock();
if (node->getInit())
{
loopScope->getSequence()->push_back(node->getInit());
}
loopScope->getSequence()->push_back(
createTempInitDeclaration(node->getCondition()->deepCopy()));
TIntermBlock *whileLoopBody = new TIntermBlock();
if (node->getBody())
{
whileLoopBody->getSequence()->push_back(node->getBody());
}
if (node->getExpression())
{
node->getBody()->getSequence()->push_back(oldBody);
whileLoopBody->getSequence()->push_back(node->getExpression());
}
node->getBody()->getSequence()->push_back(loopExpression);
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);
}
}
mInsideLoopConditionOrExpression = false;
mInsideLoopInitConditionOrExpression = false;
if (!mFoundLoopToChange && node->getBody())
node->getBody()->traverse(this);
......
......@@ -39,16 +39,19 @@ void TranslatorHLSL::translate(TIntermNode *root, ShCompileOptions compileOption
sh::AddDefaultReturnStatements(root);
SeparateDeclarations(root);
// Note that SimplifyLoopConditions needs to be run before any other AST transformations that
// may need to generate new statements from loop conditions or loop expressions.
SimplifyLoopConditions(root,
IntermNodePatternMatcher::kExpressionReturningArray |
IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue |
IntermNodePatternMatcher::kMultiDeclaration,
getTemporaryIndex(), getSymbolTable(), getShaderVersion());
// Note that separate declarations need to be run before other AST transformations that
// generate new statements from expressions.
SeparateDeclarations(root);
SplitSequenceOperator(root,
IntermNodePatternMatcher::kExpressionReturningArray |
IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
......
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