Rework inReadableOrder() as a recursive descent.

Add a test for unreachable merge block.

Update test results with the new order: mainly delaying merge blocks and
removing unreachable ones.
This commit is contained in:
Dejan Mircevski 2016-01-19 10:01:27 -05:00
parent 9c591487ad
commit 38d039d063
10 changed files with 131 additions and 107 deletions

View File

@ -17,53 +17,52 @@
#include "spvIR.h"
#include <algorithm>
#include <cassert>
#include <deque>
#include <unordered_map>
#include <unordered_set>
using spv::Block;
using spv::Id;
using BlockSet = std::unordered_set<Id>;
using IdToBool = std::unordered_map<Id, bool>;
namespace {
// True if any of prerequisites have not yet been visited. May add new,
// zero-initialized, values to visited, but doesn't modify any existing values.
bool delay(const BlockSet& prereqs, IdToBool& visited) {
return std::any_of(prereqs.begin(), prereqs.end(),
[&visited](Id b) { return !visited[b]; });
}
// Traverses CFG in a readable order, invoking a pre-set callback on each block.
// Use by calling visit() on the root block.
class ReadableOrderTraverser {
public:
explicit ReadableOrderTraverser(std::function<void(Block*)> callback)
: callback_(callback) {}
// Visits the block if it hasn't been visited already and isn't currently
// being delayed. Invokes callback(block), then descends into its successors.
// Delays merge-block processing until all the branches have been completed.
void visit(Block* block) {
assert(block);
if (visited_[block] || delayed_[block]) return;
callback_(block);
visited_[block] = true;
Block* mergeBlock = nullptr;
auto mergeInst = block->getMergeInstruction();
if (mergeInst) {
Id mergeId = mergeInst->getIdOperand(0);
mergeBlock =
block->getParent().getParent().getInstruction(mergeId)->getBlock();
delayed_[mergeBlock] = true;
}
for (const auto succ : block->getSuccessors())
if (succ != mergeBlock) visit(succ);
if (mergeBlock) {
delayed_[mergeBlock] = false;
visit(mergeBlock);
}
}
private:
std::function<void(Block*)> callback_;
// Whether a block has already been visited or is being delayed.
std::unordered_map<Block*, bool> visited_, delayed_;
};
}
void spv::inReadableOrder(Block* root, std::function<void(Block*)> callback) {
// Prerequisites for a merge block; must be completed prior to visiting the
// merge block.
std::unordered_map<Id, BlockSet> prereqs;
IdToBool visited; // Whether a block has already been visited.
std::deque<Block*> worklist; // DFS worklist
worklist.push_back(root);
while (!worklist.empty()) {
Block* current = worklist.front();
worklist.pop_front();
// Nodes may be pushed repeadetly (before they're first visited) if they
// have multiple predecessors. Skip the already-visited ones.
if (visited[current->getId()]) continue;
if (delay(prereqs[current->getId()], visited)) {
// Not every prerequisite has been visited -- push it off for later.
worklist.push_back(current);
continue;
}
callback(current);
visited[current->getId()] = true;
if (auto merge = current->getMergeInstruction()) {
Id mergeId = merge->getIdOperand(0);
auto& mergePrereqs = prereqs[mergeId];
// Delay visiting merge blocks until all branches are visited.
for (const auto succ : current->getSuccessors())
if (succ->getId() != mergeId) mergePrereqs.insert(succ->getId());
}
for (auto succ : current->getSuccessors()) {
if (!visited[succ->getId()]) worklist.push_back(succ);
}
}
ReadableOrderTraverser(callback).visit(root);
}

View File

@ -60,6 +60,7 @@
namespace spv {
class Block;
class Function;
class Module;
@ -108,6 +109,8 @@ public:
addImmediateOperand(word);
}
}
void setBlock(Block* b) { block = b; }
Block* getBlock() { return block; }
Op getOpCode() const { return opCode; }
int getNumOperands() const { return (int)operands.size(); }
Id getResultId() const { return resultId; }
@ -146,6 +149,7 @@ protected:
Op opCode;
std::vector<Id> operands;
std::string originalString; // could be optimized away; convenience for getting string operand
Block* block;
};
//
@ -165,8 +169,8 @@ public:
void addInstruction(std::unique_ptr<Instruction> inst);
void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
const std::vector<Block*> getPredecessors() const { return predecessors; }
const std::vector<Block*> getSuccessors() const { return successors; }
const std::vector<Block*>& getPredecessors() const { return predecessors; }
const std::vector<Block*>& getSuccessors() const { return successors; }
void setUnreachable() { unreachable = true; }
bool isUnreachable() const { return unreachable; }
// Returns the block's merge instruction, if one exists (otherwise null).
@ -370,12 +374,15 @@ __inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
{
instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
instructions.back()->setBlock(this);
parent.getParent().mapInstruction(instructions.back());
}
__inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
{
Instruction* raw_instruction = inst.get();
Instruction* raw_instruction = inst.get();
instructions.push_back(std::move(inst));
raw_instruction->setBlock(this);
if (raw_instruction->getResultId())
parent.getParent().mapInstruction(raw_instruction);
}

19
Test/baseResults/spv.always-discard.frag.out Executable file → Normal file
View File

@ -110,23 +110,4 @@ Linked fragment stage:
Branch 49
49: Label
Kill
69: Label
70: 6(float) Load 36(radius)
72: 46(bool) FOrdGreaterThanEqual 70 71
SelectionMerge 74 None
BranchConditional 72 73 74
73: Label
75: 6(float) Load 36(radius)
77: 6(float) ExtInst 1(GLSL.std.450) 26(Pow) 75 76
78: 6(float) FDiv 77 27
79: 6(float) ExtInst 1(GLSL.std.450) 4(FAbs) 78
80: 7(fvec4) Load 15(color)
81: 7(fvec4) CompositeConstruct 79 79 79 79
82: 7(fvec4) FSub 80 81
Store 15(color) 82
Branch 74
74: Label
83: 7(fvec4) Load 15(color)
Store 59(gl_FragColor) 83
Return
FunctionEnd

6
Test/baseResults/spv.do-while-continue-break.vert.out Executable file → Normal file
View File

@ -81,9 +81,6 @@ Linked vertex stage:
28: Label
Store 30(B) 19
Branch 10
32: Label
Store 33(C) 26
Branch 29
29: Label
34: 6(int) Load 8(i)
36: 14(bool) IEqual 34 35
@ -92,9 +89,6 @@ Linked vertex stage:
37: Label
Store 39(D) 40
Branch 11
41: Label
Store 42(E) 43
Branch 38
38: Label
Store 44(F) 45
Branch 10

6
Test/baseResults/spv.for-continue-break.vert.out Executable file → Normal file
View File

@ -70,9 +70,6 @@ Linked vertex stage:
27: 6(int) IAdd 26 18
Store 8(i) 27
Branch 10
28: Label
Store 29(C) 18
Branch 24
24: Label
30: 6(int) Load 8(i)
32: 6(int) SMod 30 31
@ -82,9 +79,6 @@ Linked vertex stage:
34: Label
Store 36(D) 18
Branch 11
37: Label
Store 38(E) 18
Branch 35
35: Label
Store 39(F) 40
41: 6(int) Load 8(i)

View File

@ -0,0 +1,47 @@
spv.merge-unreachable.frag
Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
Linked fragment stage:
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 25
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 9
ExecutionMode 4 OriginLowerLeft
Source GLSL 450
Name 4 "main"
Name 9 "v"
Decorate 9(v) Location 1
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypePointer Input 7(fvec4)
9(v): 8(ptr) Variable Input
11: 6(float) Constant 1036831949
12: 6(float) Constant 1045220557
13: 6(float) Constant 1050253722
14: 6(float) Constant 1053609165
15: 7(fvec4) ConstantComposite 11 12 13 14
16: TypeBool
17: TypeVector 16(bool) 4
4(main): 2 Function None 3
5: Label
10: 7(fvec4) Load 9(v)
18: 17(bvec4) FOrdEqual 10 15
19: 16(bool) All 18
SelectionMerge 21 None
BranchConditional 19 20 23
20: Label
Kill
23: Label
Return
21: Label
Return
FunctionEnd

View File

@ -106,6 +106,11 @@ Linked fragment stage:
Switch 65 68
case 1: 66
case 2: 67
68: Label
80: 6(float) Load 73(x)
81: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 80
Store 71(f) 81
Branch 69
66: Label
74: 6(float) Load 73(x)
75: 6(float) ExtInst 1(GLSL.std.450) 13(Sin) 74
@ -116,17 +121,19 @@ Linked fragment stage:
78: 6(float) ExtInst 1(GLSL.std.450) 14(Cos) 77
Store 71(f) 78
Branch 69
68: Label
80: 6(float) Load 73(x)
81: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 80
Store 71(f) 81
Branch 69
69: Label
83: 9(int) Load 60(c)
SelectionMerge 87 None
Switch 83 86
case 1: 84
case 2: 85
86: Label
97: 6(float) Load 73(x)
98: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 97
99: 6(float) Load 71(f)
100: 6(float) FAdd 99 98
Store 71(f) 100
Branch 87
84: Label
88: 6(float) Load 73(x)
89: 6(float) ExtInst 1(GLSL.std.450) 13(Sin) 88
@ -141,13 +148,6 @@ Linked fragment stage:
95: 6(float) FAdd 94 93
Store 71(f) 95
Branch 87
86: Label
97: 6(float) Load 73(x)
98: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 97
99: 6(float) Load 71(f)
100: 6(float) FAdd 99 98
Store 71(f) 100
Branch 87
87: Label
102: 9(int) Load 60(c)
SelectionMerge 105 None
@ -174,6 +174,13 @@ Linked fragment stage:
Switch 117 120
case 1: 118
case 2: 119
120: Label
148: 6(float) Load 73(x)
149: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 148
150: 6(float) Load 71(f)
151: 6(float) FAdd 150 149
Store 71(f) 151
Branch 121
118: Label
122: 6(float) Load 73(x)
123: 6(float) ExtInst 1(GLSL.std.450) 13(Sin) 122
@ -207,13 +214,6 @@ Linked fragment stage:
Branch 131
131: Label
Branch 121
120: Label
148: 6(float) Load 73(x)
149: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 148
150: 6(float) Load 71(f)
151: 6(float) FAdd 150 149
Store 71(f) 151
Branch 121
121: Label
Store 153(i) 154
Branch 155
@ -228,6 +228,13 @@ Linked fragment stage:
Switch 162 165
case 1: 163
case 2: 164
165: Label
196: 6(float) Load 73(x)
197: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 196
198: 6(float) Load 71(f)
199: 6(float) FAdd 198 197
Store 71(f) 199
Branch 166
163: Label
167: 6(float) Load 73(x)
168: 6(float) ExtInst 1(GLSL.std.450) 13(Sin) 167
@ -265,13 +272,6 @@ Linked fragment stage:
193: 6(float) FAdd 192 191
Store 71(f) 193
Branch 166
165: Label
196: 6(float) Load 73(x)
197: 6(float) ExtInst 1(GLSL.std.450) 15(Tan) 196
198: 6(float) Load 71(f)
199: 6(float) FAdd 198 197
Store 71(f) 199
Branch 166
166: Label
201: 6(float) Load 71(f)
203: 160(bool) FOrdLessThan 201 202
@ -331,10 +331,10 @@ Linked fragment stage:
SelectionMerge 254 None
Switch 251 253
case 0: 252
252: Label
Branch 254
253: Label
Branch 254
252: Label
Branch 254
254: Label
258: 9(int) Load 60(c)
SelectionMerge 260 None

6
Test/baseResults/spv.while-continue-break.vert.out Executable file → Normal file
View File

@ -60,9 +60,6 @@ Linked vertex stage:
23: Label
Store 25(B) 20
Branch 10
26: Label
Store 27(C) 20
Branch 24
24: Label
28: 6(int) Load 8(i)
30: 6(int) SMod 28 29
@ -72,9 +69,6 @@ Linked vertex stage:
32: Label
Store 25(B) 20
Branch 11
34: Label
Store 27(C) 20
Branch 33
33: Label
35: 6(int) Load 8(i)
36: 6(int) IAdd 35 18

View File

@ -0,0 +1,7 @@
#version 450
layout(location=1) in highp vec4 v;
void main (void)
{
if (v == vec4(0.1,0.2,0.3,0.4)) discard;
else return;
}

View File

@ -57,6 +57,7 @@ spv.loopsArtificial.frag
spv.matFun.vert
spv.matrix.frag
spv.matrix2.frag
spv.merge-unreachable.frag
spv.newTexture.frag
spv.nonSquare.vert
spv.Operations.frag