Add a test for unreachable merge block.
Update test results with the new order: mainly delaying merge blocks and
removing unreachable ones.
#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) {}
-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());
+ // 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 (auto succ : current->getSuccessors()) {
- if (!visited[succ->getId()]) worklist.push_back(succ);
+ 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) {
+ ReadableOrderTraverser(callback).visit(root);
}
namespace spv {
+class Block;
class Function;
class Module;
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; }
Op opCode;
std::vector<Id> operands;
std::string originalString; // could be optimized away; convenience for getting string operand
+ Block* block;
};
//
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).
__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);
}
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
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
37: Label
Store 39(D) 40
Branch 11
- 41: Label
- Store 42(E) 43
- Branch 38
38: Label
Store 44(F) 45
Branch 10
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
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)
--- /dev/null
+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
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
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
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
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
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
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
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
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
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
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
--- /dev/null
+#version 450\r
+layout(location=1) in highp vec4 v;\r
+void main (void)\r
+{\r
+ if (v == vec4(0.1,0.2,0.3,0.4)) discard;\r
+ else return;\r
+}\r
spv.matFun.vert
spv.matrix.frag
spv.matrix2.frag
+spv.merge-unreachable.frag
spv.newTexture.frag
spv.nonSquare.vert
spv.Operations.frag