nir: Move nir_lower_mediump_outputs from ir3
[mesa.git] / src / compiler / nir / nir_opt_dead_cf.c
index e796e6e85e344be7f0a1b05024ec1451792127e2..a798da5d5881d9d9c6db1a86a999721d75131120 100644 (file)
@@ -160,11 +160,21 @@ def_only_used_in_cf_node(nir_ssa_def *def, void *_node)
          return false;
    }
 
+   /* Same check for if-condition uses */
+   nir_foreach_if_use(use, def) {
+      nir_block *use_block =
+         nir_cf_node_as_block(nir_cf_node_prev(&use->parent_if->cf_node));
+
+      if (use_block->index <= before->index ||
+          use_block->index >= after->index)
+         return false;
+   }
+
    return true;
 }
 
 /*
- * Test if a loop node or if node is dead. Such nodes are dead if:
+ * Test if a loop node is dead. Such nodes are dead if:
  *
  * 1) It has no side effects (i.e. intrinsics which could possibly affect the
  * state of the program aside from producing an SSA value, indicated by a lack
@@ -182,7 +192,7 @@ def_only_used_in_cf_node(nir_ssa_def *def, void *_node)
 static bool
 node_is_dead(nir_cf_node *node)
 {
-   assert(node->type == nir_cf_node_loop || node->type == nir_cf_node_if);
+   assert(node->type == nir_cf_node_loop);
 
    nir_block *after = nir_cf_node_as_block(nir_cf_node_next(node));
 
@@ -206,7 +216,7 @@ node_is_dead(nir_cf_node *node)
 
       nir_foreach_instr(instr, block) {
          if (instr->type == nir_instr_type_call)
-            return true;
+            return false;
 
          /* Return instructions can cause us to skip over other side-effecting
           * instructions after the loop, so consider them to have side effects
@@ -239,11 +249,6 @@ dead_cf_block(nir_block *block)
 {
    nir_if *following_if = nir_block_get_following_if(block);
    if (following_if) {
-      if (node_is_dead(&following_if->cf_node)) {
-         nir_cf_node_remove(&following_if->cf_node);
-         return true;
-      }
-
       if (!nir_src_is_const(following_if->condition))
          return false;
 
@@ -329,6 +334,13 @@ dead_cf_list(struct exec_list *list, bool *list_ends_in_jump)
          bool dummy;
          progress |= dead_cf_list(&loop->body, &dummy);
 
+         nir_block *next = nir_cf_node_as_block(nir_cf_node_next(cur));
+         if (next->predecessors->entries == 0 &&
+             (!exec_list_is_empty(&next->instr_list) ||
+             !exec_node_is_tail_sentinel(next->cf_node.node.next))) {
+            remove_after_cf_node(cur);
+            return true;
+         }
          break;
       }
 
@@ -350,11 +362,22 @@ opt_dead_cf_impl(nir_function_impl *impl)
 
    if (progress) {
       nir_metadata_preserve(impl, nir_metadata_none);
-    } else {
+
+      /* The CF manipulation code called by this pass is smart enough to keep
+       * from breaking any SSA use/def chains by replacing any uses of removed
+       * instructions with SSA undefs.  However, it's not quite smart enough
+       * to always preserve the dominance properties.  In particular, if you
+       * remove the one break from a loop, stuff in the loop may still be used
+       * outside the loop even though there's no path between the two.  We can
+       * easily fix these issues by calling nir_repair_ssa which will ensure
+       * that the dominance properties hold.
+       */
+      nir_repair_ssa_impl(impl);
+   } else {
 #ifndef NDEBUG
       impl->valid_metadata &= ~nir_metadata_not_properly_reset;
 #endif
-    }
+   }
 
    return progress;
 }