i965: Safely iterate the predecessors of the end block.
authorKenneth Graunke <kenneth@whitecape.org>
Thu, 25 Aug 2016 04:33:16 +0000 (21:33 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Fri, 26 Aug 2016 02:18:24 +0000 (19:18 -0700)
We want to insert code in each of the predecessors of the end block.
This code includes a nir_if, which would split the block, altering
the set.  To avoid that, I emitted a dead constant at the end of each
block before splitting it, so that the set of predecessors remained
unchanged.  This was admittedly ugly.

Connor suggested instead saving a copy of the set, so we can iterate
it safely.  This is also a little ugly, but a much better plan.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Connor Abbott <cwabbott0@gmail.com>
src/mesa/drivers/dri/i965/brw_nir_tcs_workarounds.c

index 6524b7dcb21a3424962d91e5223116ae2763ded3..3f94f631f73d312cb960cfd0442650a75c40ae8d 100644 (file)
@@ -102,14 +102,7 @@ store_output(nir_builder *b, nir_ssa_def *value, int offset, unsigned comps)
 static void
 emit_quads_workaround(nir_builder *b, nir_block *block)
 {
-   /* We're going to insert a new if-statement in a predecessor of the end
-    * block.  This would normally create a new block (after the if) which
-    * would then become the predecessor of the end block, causing our set
-    * walking to get screwed up.  To avoid this, just emit a constant at
-    * the end of our current block, and insert the if before that.
-    */
    b->cursor = nir_after_block_before_jump(block);
-   b->cursor = nir_before_instr(nir_imm_int(b, 0)->parent_instr);
 
    nir_ssa_def *inner = load_output(b, 2, 0);
    nir_ssa_def *outer = load_output(b, 4, 1);
@@ -139,10 +132,22 @@ brw_nir_apply_tcs_quads_workaround(nir_shader *nir)
    nir_builder b;
    nir_builder_init(&b, impl);
 
+   /* emit_quads_workaround() inserts an if statement into each block,
+    * which splits it in two.  This changes the set of predecessors of
+    * the end block.  We want to process the original set, so to be safe,
+    * save it off to an array first.
+    */
+   const unsigned num_end_preds = impl->end_block->predecessors->entries;
+   nir_block *end_preds[num_end_preds];
+   unsigned i = 0;
    struct set_entry *entry;
+
    set_foreach(impl->end_block->predecessors, entry) {
-      nir_block *pred = (nir_block *) entry->key;
-      emit_quads_workaround(&b, pred);
+      end_preds[i++] = (nir_block *) entry->key;
+   }
+
+   for (i = 0; i < num_end_preds; i++) {
+      emit_quads_workaround(&b, end_preds[i]);
    }
 
    nir_metadata_preserve(impl, 0);