Rework inReadableOrder() as a recursive descent.
authorDejan Mircevski <deki@google.com>
Tue, 19 Jan 2016 15:01:27 +0000 (10:01 -0500)
committerDejan Mircevski <deki@google.com>
Tue, 19 Jan 2016 15:14:50 +0000 (10:14 -0500)
Add a test for unreachable merge block.

Update test results with the new order: mainly delaying merge blocks and
removing unreachable ones.

SPIRV/InReadableOrder.cpp
SPIRV/spvIR.h
Test/baseResults/spv.always-discard.frag.out [changed mode: 0755->0644]
Test/baseResults/spv.do-while-continue-break.vert.out [changed mode: 0755->0644]
Test/baseResults/spv.for-continue-break.vert.out [changed mode: 0755->0644]
Test/baseResults/spv.merge-unreachable.frag.out [new file with mode: 0644]
Test/baseResults/spv.switch.frag.out
Test/baseResults/spv.while-continue-break.vert.out [changed mode: 0755->0644]
Test/spv.merge-unreachable.frag [new file with mode: 0644]
Test/test-spirv-list

index b24d3ef..de506f4 100644 (file)
 #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);
 }
index a854384..307711b 100755 (executable)
@@ -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);
 }
old mode 100755 (executable)
new mode 100644 (file)
index a639515..73e34bd
@@ -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
old mode 100755 (executable)
new mode 100644 (file)
index c483861..44a1730
@@ -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
old mode 100755 (executable)
new mode 100644 (file)
index 92976eb..c759fc6
@@ -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)
diff --git a/Test/baseResults/spv.merge-unreachable.frag.out b/Test/baseResults/spv.merge-unreachable.frag.out
new file mode 100644 (file)
index 0000000..6542976
--- /dev/null
@@ -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
index 0d43083..918c1d6 100755 (executable)
@@ -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
old mode 100755 (executable)
new mode 100644 (file)
index 5d6094f..b2ccbaa
@@ -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
diff --git a/Test/spv.merge-unreachable.frag b/Test/spv.merge-unreachable.frag
new file mode 100644 (file)
index 0000000..12f57cd
--- /dev/null
@@ -0,0 +1,7 @@
+#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
index 13ff7c0..d066124 100644 (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