glslang -> SPV: improved support for do-while/continue. Contributed by David Neto (dneto@google.com).

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@31205 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich
2015-05-15 18:44:16 +00:00
parent 93dfbe1309
commit 593a3f7f6b
15 changed files with 473 additions and 20 deletions

View File

@@ -1159,19 +1159,21 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
bool bodyOut = false;
if (! node->testFirst()) {
builder.endLoopHeaderWithoutTest();
if (node->getBody()) {
breakForLoop.push(true);
node->getBody()->traverse(this);
breakForLoop.pop();
}
bodyOut = true;
builder.createBranchToLoopTest();
}
if (node->getTest()) {
node->getTest()->traverse(this);
// the AST only contained the test computation, not the branch, we have to add it
spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));
builder.createLoopHeaderBranch(condition);
builder.createLoopTestBranch(condition);
}
if (! bodyOut && node->getBody()) {
@@ -1208,7 +1210,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T
case glslang::EOpContinue:
if (loopTerminal.top())
loopTerminal.top()->traverse(this);
builder.createLoopBackEdge();
builder.createLoopContinue();
break;
case glslang::EOpReturn:
if (inMain)

View File

@@ -1719,6 +1719,7 @@ void Builder::makeNewLoop()
loop.function = &getBuildPoint()->getParent();
loop.header = new Block(getUniqueId(), *loop.function);
loop.merge = new Block(getUniqueId(), *loop.function);
loop.test = NULL;
loops.push(loop);
@@ -1730,43 +1731,75 @@ void Builder::makeNewLoop()
setBuildPoint(loop.header);
}
void Builder::createLoopHeaderBranch(Id condition)
void Builder::createLoopTestBranch(Id condition)
{
Loop loop = loops.top();
Loop& loop = loops.top();
// If loop.test exists, then we've already generated the LoopMerge
// for this loop.
if (!loop.test)
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
// Branching to the "body" block will keep control inside
// the loop.
Block* body = new Block(getUniqueId(), *loop.function);
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
createConditionalBranch(condition, body, loop.merge);
loop.function->addBlock(body);
setBuildPoint(body);
}
// Add a back-edge (e.g "continue") for the innermost loop that you're in
void Builder::createLoopBackEdge(bool implicit)
void Builder::endLoopHeaderWithoutTest()
{
Loop loop = loops.top();
Loop& loop = loops.top();
// Just branch back, and set up a block for dead code if it's a user continue
createBranch(loop.header);
if (! implicit)
createAndSetNoPredecessorBlock("post-loop-continue");
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
Block* body = new Block(getUniqueId(), *loop.function);
createBranch(body);
loop.function->addBlock(body);
setBuildPoint(body);
assert(!loop.test);
loop.test = new Block(getUniqueId(), *loop.function);
}
void Builder::createBranchToLoopTest()
{
Loop& loop = loops.top();
Block* testBlock = loop.test;
assert(testBlock);
createBranch(testBlock);
loop.function->addBlock(testBlock);
setBuildPoint(testBlock);
}
void Builder::createLoopContinue()
{
Loop& loop = loops.top();
if (loop.test)
createBranch(loop.test);
else
createBranch(loop.header);
// Set up a block for dead code.
createAndSetNoPredecessorBlock("post-loop-continue");
}
// Add an exit (e.g. "break") for the innermost loop that you're in
void Builder::createLoopExit()
{
createBranch(loops.top().merge);
// Set up a block for dead code.
createAndSetNoPredecessorBlock("post-loop-break");
}
// Close the innermost loop
void Builder::closeLoop()
{
Loop& loop = loops.top();
// Branch back to the top
createLoopBackEdge(true);
createBranch(loop.header);
// Add the merge block and set the build point to it
Loop loop = loops.top();
loop.function->addBlock(loop.merge);
setBuildPoint(loop.merge);

View File

@@ -357,13 +357,33 @@ public:
// Start the beginning of a new loop.
void makeNewLoop();
// Add the branch at the end of the loop header, and leave the build position
// in the first block of the body.
// 'condition' is true if should exit the loop
void createLoopHeaderBranch(Id condition);
// Add the branch for the loop test, based on the given condition.
// The true branch goes to the block that remains inside the loop, and
// the false branch goes to the loop's merge block. The builder insertion
// point will be placed at the start of the inside-the-loop block.
void createLoopTestBranch(Id condition);
// Add a back-edge (e.g "continue") for the innermost loop that you're in
void createLoopBackEdge(bool implicit=false);
// Finish generating the loop header block in the case where the loop test
// is at the bottom of the loop. It will include the LoopMerge instruction
// and a branch to the rest of the body. The loop header block must be
// separate from the rest of the body to make room for the the two kinds
// of *Merge instructions that might have to occur just before a branch:
// the loop header must have a LoopMerge as its second-last instruction,
// and the body might begin with a conditional branch, which must have its
// own SelectionMerge instruction.
// Also create the basic block that will contain the loop test, but don't
// insert it into the function yet. Any "continue" constructs in this loop
// will branch to the loop test block. The builder insertion point will be
// placed at the start of the body block.
void endLoopHeaderWithoutTest();
// Generate a branch to the loop test block. This can only be called if
// the loop test is at the bottom of the loop. The builder insertion point
// is left at the start of the test block.
void createBranchToLoopTest();
// Add a branch to the test of the current (innermost) loop.
void createLoopContinue();
// Add an exit (e.g. "break") for the innermost loop that you're in
void createLoopExit();
@@ -507,8 +527,23 @@ protected:
// Data that needs to be kept in order to properly handle loops.
struct Loop {
// The header is the first block generated for the loop.
// It dominates all the blocks in the loop, i.e. it is always
// executed before any others.
// If the loop test is executed before the body (as in "while" and
// "for" loops), then the header begins with the test code.
// Otherwise, the loop is a "do-while" loop and the header contains the
// start of the body of the loop (if the body exists).
Block* header;
// The merge block marks the end of the loop. Control is transferred
// to the merge block when either the loop test fails, or when a
// nested "break" is encountered.
Block* merge;
// If not NULL, the test block is the basic block containing the loop
// test and the conditional branch back to the header or the merge
// block. This is created for "do-while" loops, and is the target of
// any "continue" constructs that might exist.
Block* test;
Function* function;
};