Commit c22f37cf by David Neto

Generate correctly structured do-while loops.

The loop test is always emitted before the loop body. For do-while loops, use a phi node to track whether we're on the first loop iteration, and only check the loop test on the second and subsequent iterations. For do-while loops, the loop test branch no longer occurs at the top of the loop, so it must get its own selection merge instruction. A block can't be the target of more than one merge instruction. So when the loop test executes after the body (as in do-while in GLSL) we need to introduce a dummy block to be the target of the selection merge just before the loop test conditional branch. The other arm of the branch exits the loop and hence is the "break block" exception in the structured control flow rules.
parent 51b31b57
......@@ -1147,28 +1147,18 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
// body emission needs to know what the for-loop terminal is when it sees a "continue"
loopTerminal.push(node->getTerminal());
builder.makeNewLoop();
bool bodyOut = false;
if (! node->testFirst()) {
builder.endLoopHeaderWithoutTest();
if (node->getBody()) {
breakForLoop.push(true);
node->getBody()->traverse(this);
breakForLoop.pop();
}
bodyOut = true;
builder.createBranchToLoopTest();
}
builder.makeNewLoop(node->testFirst());
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.createLoopTestBranch(condition);
} else {
builder.createBranchToBody();
}
if (! bodyOut && node->getBody()) {
if (node->getBody()) {
breakForLoop.push(true);
node->getBody()->traverse(this);
breakForLoop.pop();
......
......@@ -1736,16 +1736,29 @@ void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
}
// Comments in header
void Builder::makeNewLoop()
void Builder::makeNewLoop(bool loopTestFirst)
{
Loop loop = { };
loop.function = &getBuildPoint()->getParent();
loop.header = new Block(getUniqueId(), *loop.function);
loop.merge = new Block(getUniqueId(), *loop.function);
loop.test = NULL;
loops.push({ });
Loop& loop = loops.top();
loops.push(loop);
loop.function = &getBuildPoint()->getParent();
loop.header = new Block(getUniqueId(), *loop.function);
loop.merge = new Block(getUniqueId(), *loop.function);
// Delaying creation of the loop body perturbs test results less,
// which makes for easier patch review.
// TODO(dneto): Create the loop body block here, instead of
// upon first use.
loop.body = 0;
loop.testFirst = loopTestFirst;
loop.isFirstIteration = 0;
// The loop test is always emitted before the loop body.
// But if the loop test executes at the bottom of the loop, then
// execute the test only on the second and subsequent iterations.
// Remember the block that branches to the loop header. This
// is required for the test-after-body case.
Block* preheader = getBuildPoint();
// Branch into the loop
createBranch(loop.header);
......@@ -1753,56 +1766,95 @@ void Builder::makeNewLoop()
// Set ourselves inside the loop
loop.function->addBlock(loop.header);
setBuildPoint(loop.header);
if (!loopTestFirst) {
// Generate code to defer the loop test until the second and
// subsequent iterations.
// A phi node determines whether we're on the first iteration.
loop.isFirstIteration = new Instruction(getUniqueId(), makeBoolType(), OpPhi);
// It's always the first iteration when coming from the preheader.
// All other branches to this loop header will need to indicate "false",
// but we don't yet know where they will come from.
loop.isFirstIteration->addIdOperand(makeBoolConstant(true));
loop.isFirstIteration->addIdOperand(preheader->getId());
getBuildPoint()->addInstruction(loop.isFirstIteration);
// Mark the end of the structured loop. This must exist in the loop header block.
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
// Generate code to see if this is the first iteration of the loop.
// It needs to be in its own block, since the loop merge and
// the selection merge instructions can't both be in the same
// (header) block.
Block* firstIterationCheck = new Block(getUniqueId(), *loop.function);
createBranch(firstIterationCheck);
loop.function->addBlock(firstIterationCheck);
setBuildPoint(firstIterationCheck);
loop.body = new Block(getUniqueId(), *loop.function);
// Control flow after this "if" normally reconverges at the loop body.
// However, the loop test has a "break branch" out of this selection
// construct because it can transfer control to the loop merge block.
createMerge(OpSelectionMerge, loop.body, SelectionControlMaskNone);
Block* loopTest = new Block(getUniqueId(), *loop.function);
createConditionalBranch(loop.isFirstIteration->getResultId(), loop.body, loopTest);
loop.function->addBlock(loopTest);
setBuildPoint(loopTest);
}
}
void Builder::createLoopTestBranch(Id condition)
{
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);
createConditionalBranch(condition, body, loop.merge);
loop.function->addBlock(body);
setBuildPoint(body);
// Generate the merge instruction. If the loop test executes before
// the body, then this is a loop merge. Otherwise the loop merge
// has already been generated and this is a conditional merge.
if (loop.testFirst) {
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
loop.body = new Block(getUniqueId(), *loop.function);
// Branching to the "body" block will keep control inside
// the loop.
createConditionalBranch(condition, loop.body, loop.merge);
loop.function->addBlock(loop.body);
setBuildPoint(loop.body);
} else {
// The branch to the loop merge block is the allowed exception
// to the structured control flow. Otherwise, control flow will
// continue to loop.body block. Since that is already the target
// of a merge instruction, and a block can't be the target of more
// than one merge instruction, we need to make an intermediate block.
Block* stayInLoopBlock = new Block(getUniqueId(), *loop.function);
createMerge(OpSelectionMerge, stayInLoopBlock, SelectionControlMaskNone);
// This is the loop test.
createConditionalBranch(condition, stayInLoopBlock, loop.merge);
// The dummy block just branches to the real loop body.
loop.function->addBlock(stayInLoopBlock);
setBuildPoint(stayInLoopBlock);
createBranchToBody();
}
}
void Builder::endLoopHeaderWithoutTest()
void Builder::createBranchToBody()
{
Loop& loop = loops.top();
assert(loop.body);
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);
// This is a reconvergence of control flow, so no merge instruction
// is required.
createBranch(loop.body);
loop.function->addBlock(loop.body);
setBuildPoint(loop.body);
}
void Builder::createLoopContinue()
{
Loop& loop = loops.top();
if (loop.test)
createBranch(loop.test);
else
createBranch(loop.header);
createBranchToLoopHeaderFromInside(loops.top());
// Set up a block for dead code.
createAndSetNoPredecessorBlock("post-loop-continue");
}
......@@ -1821,7 +1873,7 @@ void Builder::closeLoop()
Loop& loop = loops.top();
// Branch back to the top
createBranch(loop.header);
createBranchToLoopHeaderFromInside(loop);
// Add the merge block and set the build point to it
loop.function->addBlock(loop.merge);
......@@ -1830,6 +1882,18 @@ void Builder::closeLoop()
loops.pop();
}
// Create a branch to the header of the given loop, from inside
// the loop body.
// Adjusts the phi node for the first-iteration value if needeed.
void Builder::createBranchToLoopHeaderFromInside(const Loop& loop)
{
createBranch(loop.header);
if (loop.isFirstIteration) {
loop.isFirstIteration->addIdOperand(makeBoolConstant(false));
loop.isFirstIteration->addIdOperand(getBuildPoint()->getId());
}
}
void Builder::clearAccessChain()
{
accessChain.base = 0;
......
......@@ -357,35 +357,25 @@ public:
// Finish off the innermost switch.
void endSwitch(std::vector<Block*>& segmentBB);
// Start the beginning of a new loop.
void makeNewLoop();
// Start the beginning of a new loop, and prepare the builder to
// generate code for the loop test.
// The loopTestFirst parameter is true when the loop test executes before
// the body. (It is false for do-while loops.)
void makeNewLoop(bool loopTestFirst);
// 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.
// The true branch goes to the first block in the loop body, and
// the false branch goes to the loop's merge block. The builder insertion
// point will be placed at the start of the body.
void createLoopTestBranch(Id condition);
// 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();
// Generate an unconditional branch to the loop body. The builder insertion
// point will be placed at the start of the body. Use this when there is
// no loop test.
void createBranchToBody();
// Add a branch to the test of the current (innermost) loop.
// The way we generate code, that's also the loop header.
void createLoopContinue();
// Add an exit (e.g. "break") for the innermost loop that you're in
......@@ -499,6 +489,9 @@ protected:
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
struct Loop; // Defined below.
void createBranchToLoopHeaderFromInside(const Loop& loop);
SourceLanguage source;
int sourceVersion;
std::vector<const char*> extensions;
......@@ -543,11 +536,18 @@ protected:
// 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;
// The body block is the first basic block in the body of the loop, i.e.
// the code that is to be repeatedly executed, aside from loop control.
// This member is null until we generate code that references the loop
// body block.
Block* body;
// True when the loop test executes before the body.
bool testFirst;
// When the test executes after the body, this is defined as the phi
// instruction that tells us whether we are on the first iteration of
// the loop. Otherwise this is null.
Instruction* isFirstIteration;
// The function containing the loop.
Function* function;
};
......
......@@ -5,7 +5,7 @@ Linked vertex stage:
// Module Version 99
// Generated by (magic number): 51a00bb
// Id's are bound by 26
// Id's are bound by 30
Source ESSL 300
1: ExtInstImport "GLSL.std.450"
......@@ -13,45 +13,52 @@ Linked vertex stage:
EntryPoint Vertex 4
Name 4 "main"
Name 9 "i"
Name 24 "gl_VertexID"
Name 25 "gl_InstanceID"
Name 28 "gl_VertexID"
Name 29 "gl_InstanceID"
Decorate 9(i) PrecisionHigh
Decorate 24(gl_VertexID) PrecisionHigh
Decorate 24(gl_VertexID) BuiltIn VertexId
Decorate 24(gl_VertexID) NoStaticUse
Decorate 25(gl_InstanceID) PrecisionHigh
Decorate 25(gl_InstanceID) BuiltIn InstanceId
Decorate 25(gl_InstanceID) NoStaticUse
Decorate 28(gl_VertexID) PrecisionHigh
Decorate 28(gl_VertexID) BuiltIn VertexId
Decorate 28(gl_VertexID) NoStaticUse
Decorate 29(gl_InstanceID) PrecisionHigh
Decorate 29(gl_InstanceID) BuiltIn InstanceId
Decorate 29(gl_InstanceID) NoStaticUse
2: TypeVoid
3: TypeFunction 2
7: TypeInt 32 1
8: TypePointer Function 7(int)
10: 7(int) Constant 0
16: 7(int) Constant 1
19: 7(int) Constant 10
20: TypeBool
23: TypePointer Input 7(int)
24(gl_VertexID): 23(ptr) Variable Input
25(gl_InstanceID): 23(ptr) Variable Input
14: TypeBool
15: 14(bool) ConstantTrue
20: 7(int) Constant 10
24: 7(int) Constant 1
26: 14(bool) ConstantFalse
27: TypePointer Input 7(int)
28(gl_VertexID): 27(ptr) Variable Input
29(gl_InstanceID): 27(ptr) Variable Input
4(main): 2 Function None 3
5: Label
9(i): 8(ptr) Variable Function
Store 9(i) 10
Branch 11
11: Label
13: 14(bool) Phi 15 5 26 17
LoopMerge 12 None
Branch 13
13: Label
15: 7(int) Load 9(i)
17: 7(int) IAdd 15 16
Store 9(i) 17
Branch 14
14: Label
18: 7(int) Load 9(i)
21: 20(bool) SLessThan 18 19
BranchConditional 21 22 12
Branch 16
16: Label
SelectionMerge 17 None
BranchConditional 13 17 18
18: Label
19: 7(int) Load 9(i)
21: 14(bool) SLessThan 19 20
SelectionMerge 22 None
BranchConditional 21 22 12
22: Label
Branch 11
Branch 17
17: Label
23: 7(int) Load 9(i)
25: 7(int) IAdd 23 24
Store 9(i) 25
Branch 11
12: Label
Branch 6
6: Label
......
......@@ -5,7 +5,7 @@ Linked vertex stage:
// Module Version 99
// Generated by (magic number): 51a00bb
// Id's are bound by 48
// Id's are bound by 52
Source ESSL 300
1: ExtInstImport "GLSL.std.450"
......@@ -13,97 +13,104 @@ Linked vertex stage:
EntryPoint Vertex 4
Name 4 "main"
Name 9 "i"
Name 15 "A"
Name 22 "B"
Name 25 "C"
Name 31 "D"
Name 34 "E"
Name 36 "F"
Name 43 "G"
Name 46 "gl_VertexID"
Name 47 "gl_InstanceID"
Name 25 "A"
Name 31 "B"
Name 34 "C"
Name 40 "D"
Name 43 "E"
Name 45 "F"
Name 47 "G"
Name 50 "gl_VertexID"
Name 51 "gl_InstanceID"
Decorate 9(i) PrecisionHigh
Decorate 15(A) PrecisionHigh
Decorate 22(B) PrecisionHigh
Decorate 25(C) PrecisionHigh
Decorate 31(D) PrecisionHigh
Decorate 34(E) PrecisionHigh
Decorate 36(F) PrecisionHigh
Decorate 43(G) PrecisionHigh
Decorate 46(gl_VertexID) PrecisionHigh
Decorate 46(gl_VertexID) BuiltIn VertexId
Decorate 46(gl_VertexID) NoStaticUse
Decorate 47(gl_InstanceID) PrecisionHigh
Decorate 47(gl_InstanceID) BuiltIn InstanceId
Decorate 47(gl_InstanceID) NoStaticUse
Decorate 25(A) PrecisionHigh
Decorate 31(B) PrecisionHigh
Decorate 34(C) PrecisionHigh
Decorate 40(D) PrecisionHigh
Decorate 43(E) PrecisionHigh
Decorate 45(F) PrecisionHigh
Decorate 47(G) PrecisionHigh
Decorate 50(gl_VertexID) PrecisionHigh
Decorate 50(gl_VertexID) BuiltIn VertexId
Decorate 50(gl_VertexID) NoStaticUse
Decorate 51(gl_InstanceID) PrecisionHigh
Decorate 51(gl_InstanceID) BuiltIn InstanceId
Decorate 51(gl_InstanceID) NoStaticUse
2: TypeVoid
3: TypeFunction 2
7: TypeInt 32 1
8: TypePointer Function 7(int)
10: 7(int) Constant 0
17: 7(int) Constant 2
18: TypeBool
23: 7(int) Constant 1
27: 7(int) Constant 5
32: 7(int) Constant 3
35: 7(int) Constant 42
37: 7(int) Constant 99
40: 7(int) Constant 19
44: 7(int) Constant 12
45: TypePointer Input 7(int)
46(gl_VertexID): 45(ptr) Variable Input
47(gl_InstanceID): 45(ptr) Variable Input
14: TypeBool
15: 14(bool) ConstantTrue
20: 7(int) Constant 1
22: 7(int) Constant 19
27: 7(int) Constant 2
32: 14(bool) ConstantFalse
36: 7(int) Constant 5
41: 7(int) Constant 3
44: 7(int) Constant 42
46: 7(int) Constant 99
48: 7(int) Constant 12
49: TypePointer Input 7(int)
50(gl_VertexID): 49(ptr) Variable Input
51(gl_InstanceID): 49(ptr) Variable Input
4(main): 2 Function None 3
5: Label
9(i): 8(ptr) Variable Function
15(A): 8(ptr) Variable Function
22(B): 8(ptr) Variable Function
25(C): 8(ptr) Variable Function
31(D): 8(ptr) Variable Function
34(E): 8(ptr) Variable Function
36(F): 8(ptr) Variable Function
43(G): 8(ptr) Variable Function
25(A): 8(ptr) Variable Function
31(B): 8(ptr) Variable Function
34(C): 8(ptr) Variable Function
40(D): 8(ptr) Variable Function
43(E): 8(ptr) Variable Function
45(F): 8(ptr) Variable Function
47(G): 8(ptr) Variable Function
Store 9(i) 10
Branch 11
11: Label
13: 14(bool) Phi 15 5 32 29 32 39
LoopMerge 12 None
Branch 13
13: Label
Store 15(A) 10
16: 7(int) Load 9(i)
19: 18(bool) IEqual 16 17
SelectionMerge 21 None
BranchConditional 19 20 21
20: Label
Store 22(B) 23
Branch 14
Branch 16
16: Label
SelectionMerge 17 None
BranchConditional 13 17 18
18: Label
19: 7(int) Load 9(i)
21: 7(int) IAdd 19 20
Store 9(i) 21
23: 14(bool) SLessThan 21 22
SelectionMerge 24 None
BranchConditional 23 24 12
24: Label
Store 25(C) 17
Branch 21
21: Label
Branch 17
17: Label
Store 25(A) 10
26: 7(int) Load 9(i)
28: 18(bool) IEqual 26 27
28: 14(bool) IEqual 26 27
SelectionMerge 30 None
BranchConditional 28 29 30
29: Label
Store 31(D) 32
Branch 12
Store 31(B) 20
Branch 11
33: Label
Store 34(E) 35
Store 34(C) 27
Branch 30
30: Label
Store 36(F) 37
Branch 14
14: Label
38: 7(int) Load 9(i)
39: 7(int) IAdd 38 23
Store 9(i) 39
41: 18(bool) SLessThan 39 40
BranchConditional 41 42 12
42: Label
35: 7(int) Load 9(i)
37: 14(bool) IEqual 35 36
SelectionMerge 39 None
BranchConditional 37 38 39
38: Label
Store 40(D) 41
Branch 12
42: Label
Store 43(E) 44
Branch 39
39: Label
Store 45(F) 46
Branch 11
12: Label
Store 43(G) 44
Store 47(G) 48
Branch 6
6: Label
Return
......
......@@ -5,7 +5,7 @@ Linked fragment stage:
// Module Version 99
// Generated by (magic number): 51a00bb
// Id's are bound by 34
// Id's are bound by 38
Source GLSL 110
1: ExtInstImport "GLSL.std.450"
......@@ -14,11 +14,11 @@ Linked fragment stage:
Name 4 "main"
Name 10 "color"
Name 12 "BaseColor"
Name 19 "bigColor"
Name 26 "d"
Name 32 "gl_FragColor"
Name 25 "d"
Name 30 "bigColor"
Name 36 "gl_FragColor"
Decorate 12(BaseColor) Smooth
Decorate 32(gl_FragColor) BuiltIn FragColor
Decorate 36(gl_FragColor) BuiltIn FragColor
2: TypeVoid
3: TypeFunction 2
7: TypeFloat 32
......@@ -26,13 +26,15 @@ Linked fragment stage:
9: TypePointer Function 8(fvec4)
11: TypePointer Input 8(fvec4)
12(BaseColor): 11(ptr) Variable Input
18: TypePointer UniformConstant 8(fvec4)
19(bigColor): 18(ptr) Variable UniformConstant
25: TypePointer UniformConstant 7(float)
26(d): 25(ptr) Variable UniformConstant
28: TypeBool
31: TypePointer Output 8(fvec4)
32(gl_FragColor): 31(ptr) Variable Output
17: TypeBool
18: 17(bool) ConstantTrue
24: TypePointer UniformConstant 7(float)
25(d): 24(ptr) Variable UniformConstant
29: TypePointer UniformConstant 8(fvec4)
30(bigColor): 29(ptr) Variable UniformConstant
34: 17(bool) ConstantFalse
35: TypePointer Output 8(fvec4)
36(gl_FragColor): 35(ptr) Variable Output
4(main): 2 Function None 3
5: Label
10(color): 9(ptr) Variable Function
......@@ -40,25 +42,30 @@ Linked fragment stage:
Store 10(color) 13
Branch 14
14: Label
16: 17(bool) Phi 18 5 34 20
LoopMerge 15 None
Branch 16
16: Label
20: 8(fvec4) Load 19(bigColor)
21: 8(fvec4) Load 10(color)
22: 8(fvec4) FAdd 21 20
Store 10(color) 22
Branch 17
17: Label
23: 8(fvec4) Load 10(color)
24: 7(float) CompositeExtract 23 0
27: 7(float) Load 26(d)
29: 28(bool) FOrdLessThan 24 27
BranchConditional 29 30 15
30: Label
Branch 14
Branch 19
19: Label
SelectionMerge 20 None
BranchConditional 16 20 21
21: Label
22: 8(fvec4) Load 10(color)
23: 7(float) CompositeExtract 22 0
26: 7(float) Load 25(d)
27: 17(bool) FOrdLessThan 23 26
SelectionMerge 28 None
BranchConditional 27 28 15
28: Label
Branch 20
20: Label
31: 8(fvec4) Load 30(bigColor)
32: 8(fvec4) Load 10(color)
33: 8(fvec4) FAdd 32 31
Store 10(color) 33
Branch 14
15: Label
33: 8(fvec4) Load 10(color)
Store 32(gl_FragColor) 33
37: 8(fvec4) Load 10(color)
Store 36(gl_FragColor) 37
Branch 6
6: Label
Return
......
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