nir/algebraic: trivially enable existing 32-bit patterns for all bit sizes
[mesa.git] / src / compiler / nir / nir_control_flow.c
index 05cc9e95a1e3ac462e21380ec444b1388e58cd1e..71a9806507218861f41de1e360ed9e98b872b9ba 100644 (file)
  */
 /*@{*/
 
-static bool
-block_ends_in_jump(nir_block *block)
-{
-   return !exec_list_is_empty(&block->instr_list) &&
-          nir_block_last_instr(block)->type == nir_instr_type_jump;
-}
-
 static inline void
 block_add_pred(nir_block *block, nir_block *pred)
 {
@@ -114,20 +107,15 @@ link_non_block_to_block(nir_cf_node *node, nir_block *block)
 
       nir_if *if_stmt = nir_cf_node_as_if(node);
 
-      nir_cf_node *last_then = nir_if_last_then_node(if_stmt);
-      assert(last_then->type == nir_cf_node_block);
-      nir_block *last_then_block = nir_cf_node_as_block(last_then);
+      nir_block *last_then_block = nir_if_last_then_block(if_stmt);
+      nir_block *last_else_block = nir_if_last_else_block(if_stmt);
 
-      nir_cf_node *last_else = nir_if_last_else_node(if_stmt);
-      assert(last_else->type == nir_cf_node_block);
-      nir_block *last_else_block = nir_cf_node_as_block(last_else);
-
-      if (!block_ends_in_jump(last_then_block)) {
+      if (!nir_block_ends_in_jump(last_then_block)) {
          unlink_block_successors(last_then_block);
          link_blocks(last_then_block, block, NULL);
       }
 
-      if (!block_ends_in_jump(last_else_block)) {
+      if (!nir_block_ends_in_jump(last_else_block)) {
          unlink_block_successors(last_else_block);
          link_blocks(last_else_block, block, NULL);
       }
@@ -147,30 +135,21 @@ link_block_to_non_block(nir_block *block, nir_cf_node *node)
 
       nir_if *if_stmt = nir_cf_node_as_if(node);
 
-      nir_cf_node *first_then = nir_if_first_then_node(if_stmt);
-      assert(first_then->type == nir_cf_node_block);
-      nir_block *first_then_block = nir_cf_node_as_block(first_then);
-
-      nir_cf_node *first_else = nir_if_first_else_node(if_stmt);
-      assert(first_else->type == nir_cf_node_block);
-      nir_block *first_else_block = nir_cf_node_as_block(first_else);
+      nir_block *first_then_block = nir_if_first_then_block(if_stmt);
+      nir_block *first_else_block = nir_if_first_else_block(if_stmt);
 
       unlink_block_successors(block);
       link_blocks(block, first_then_block, first_else_block);
-   } else {
+   } else if (node->type == nir_cf_node_loop) {
       /*
        * For similar reasons as the corresponding case in
        * link_non_block_to_block(), don't worry about if the loop header has
        * any predecessors that need to be unlinked.
        */
 
-      assert(node->type == nir_cf_node_loop);
-
       nir_loop *loop = nir_cf_node_as_loop(node);
 
-      nir_cf_node *loop_header = nir_loop_first_cf_node(loop);
-      assert(loop_header->type == nir_cf_node_block);
-      nir_block *loop_header_block = nir_cf_node_as_block(loop_header);
+      nir_block *loop_header_block = nir_loop_first_block(loop);
 
       unlink_block_successors(block);
       link_blocks(block, loop_header_block, NULL);
@@ -210,15 +189,13 @@ split_block_beginning(nir_block *block)
    new_block->cf_node.parent = block->cf_node.parent;
    exec_node_insert_node_before(&block->cf_node.node, &new_block->cf_node.node);
 
-   struct set_entry *entry;
    set_foreach(block->predecessors, entry) {
       nir_block *pred = (nir_block *) entry->key;
       replace_successor(pred, block, new_block);
    }
 
    /* Any phi nodes must stay part of the new block, or else their
-    * sourcse will be messed up. This will reverse the order of the phi's, but
-    * order shouldn't matter.
+    * sources will be messed up.
     */
    nir_foreach_instr_safe(instr, block) {
       if (instr->type != nir_instr_type_phi)
@@ -226,7 +203,7 @@ split_block_beginning(nir_block *block)
 
       exec_node_remove(&instr->node);
       instr->block = new_block;
-      exec_list_push_head(&new_block->instr_list, &instr->node);
+      exec_list_push_tail(&new_block->instr_list, &instr->node);
    }
 
    return new_block;
@@ -312,21 +289,17 @@ block_add_normal_succs(nir_block *block)
       nir_cf_node *parent = block->cf_node.parent;
       if (parent->type == nir_cf_node_if) {
          nir_cf_node *next = nir_cf_node_next(parent);
-         assert(next->type == nir_cf_node_block);
          nir_block *next_block = nir_cf_node_as_block(next);
 
          link_blocks(block, next_block, NULL);
       } else if (parent->type == nir_cf_node_loop) {
          nir_loop *loop = nir_cf_node_as_loop(parent);
 
-         nir_cf_node *head = nir_loop_first_cf_node(loop);
-         assert(head->type == nir_cf_node_block);
-         nir_block *head_block = nir_cf_node_as_block(head);
+         nir_block *head_block = nir_loop_first_block(loop);
 
          link_blocks(block, head_block, NULL);
          insert_phi_undef(head_block, block);
       } else {
-         assert(parent->type == nir_cf_node_function);
          nir_function_impl *impl = nir_cf_node_as_function(parent);
          link_blocks(block, impl->end_block, NULL);
       }
@@ -335,22 +308,14 @@ block_add_normal_succs(nir_block *block)
       if (next->type == nir_cf_node_if) {
          nir_if *next_if = nir_cf_node_as_if(next);
 
-         nir_cf_node *first_then = nir_if_first_then_node(next_if);
-         assert(first_then->type == nir_cf_node_block);
-         nir_block *first_then_block = nir_cf_node_as_block(first_then);
-
-         nir_cf_node *first_else = nir_if_first_else_node(next_if);
-         assert(first_else->type == nir_cf_node_block);
-         nir_block *first_else_block = nir_cf_node_as_block(first_else);
+         nir_block *first_then_block = nir_if_first_then_block(next_if);
+         nir_block *first_else_block = nir_if_first_else_block(next_if);
 
          link_blocks(block, first_then_block, first_else_block);
-      } else {
-         assert(next->type == nir_cf_node_loop);
+      } else if (next->type == nir_cf_node_loop) {
          nir_loop *next_loop = nir_cf_node_as_loop(next);
 
-         nir_cf_node *first = nir_loop_first_cf_node(next_loop);
-         assert(first->type == nir_cf_node_block);
-         nir_block *first_block = nir_cf_node_as_block(first);
+         nir_block *first_block = nir_loop_first_block(next_loop);
 
          link_blocks(block, first_block, NULL);
          insert_phi_undef(first_block, block);
@@ -365,7 +330,7 @@ split_block_end(nir_block *block)
    new_block->cf_node.parent = block->cf_node.parent;
    exec_node_insert_after(&block->cf_node.node, &new_block->cf_node.node);
 
-   if (block_ends_in_jump(block)) {
+   if (nir_block_ends_in_jump(block)) {
       /* Figure out what successor block would've had if it didn't have a jump
        * instruction, and make new_block have that successor.
        */
@@ -470,6 +435,23 @@ nearest_loop(nir_cf_node *node)
    return nir_cf_node_as_loop(node);
 }
 
+static void
+remove_phi_src(nir_block *block, nir_block *pred)
+{
+   nir_foreach_instr(instr, block) {
+      if (instr->type != nir_instr_type_phi)
+         break;
+
+      nir_phi_instr *phi = nir_instr_as_phi(instr);
+      nir_foreach_phi_src_safe(src, phi) {
+         if (src->pred == pred) {
+            list_del(&src->src.use_link);
+            exec_node_remove(&src->node);
+         }
+      }
+   }
+}
+
 /*
  * update the CFG after a jump instruction has been added to the end of a block
  */
@@ -480,46 +462,45 @@ nir_handle_add_jump(nir_block *block)
    nir_instr *instr = nir_block_last_instr(block);
    nir_jump_instr *jump_instr = nir_instr_as_jump(instr);
 
+   if (block->successors[0])
+      remove_phi_src(block->successors[0], block);
+   if (block->successors[1])
+      remove_phi_src(block->successors[1], block);
    unlink_block_successors(block);
 
    nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
    nir_metadata_preserve(impl, nir_metadata_none);
 
-   if (jump_instr->type == nir_jump_break ||
-       jump_instr->type == nir_jump_continue) {
+   switch (jump_instr->type) {
+   case nir_jump_return:
+      link_blocks(block, impl->end_block, NULL);
+      break;
+
+   case nir_jump_break: {
       nir_loop *loop = nearest_loop(&block->cf_node);
+      nir_cf_node *after = nir_cf_node_next(&loop->cf_node);
+      nir_block *after_block = nir_cf_node_as_block(after);
+      link_blocks(block, after_block, NULL);
+      break;
+   }
 
-      if (jump_instr->type == nir_jump_continue) {
-         nir_cf_node *first_node = nir_loop_first_cf_node(loop);
-         assert(first_node->type == nir_cf_node_block);
-         nir_block *first_block = nir_cf_node_as_block(first_node);
-         link_blocks(block, first_block, NULL);
-      } else {
-         nir_cf_node *after = nir_cf_node_next(&loop->cf_node);
-         assert(after->type == nir_cf_node_block);
-         nir_block *after_block = nir_cf_node_as_block(after);
-         link_blocks(block, after_block, NULL);
-      }
-   } else {
-      assert(jump_instr->type == nir_jump_return);
-      link_blocks(block, impl->end_block, NULL);
+   case nir_jump_continue: {
+      nir_loop *loop = nearest_loop(&block->cf_node);
+      nir_block *first_block = nir_loop_first_block(loop);
+      link_blocks(block, first_block, NULL);
+      break;
    }
-}
 
-static void
-remove_phi_src(nir_block *block, nir_block *pred)
-{
-   nir_foreach_instr(instr, block) {
-      if (instr->type != nir_instr_type_phi)
-         break;
+   case nir_jump_goto:
+      link_blocks(block, jump_instr->target, NULL);
+      break;
 
-      nir_phi_instr *phi = nir_instr_as_phi(instr);
-      nir_foreach_phi_src_safe(src, phi) {
-         if (src->pred == pred) {
-            list_del(&src->src.use_link);
-            exec_node_remove(&src->node);
-         }
-      }
+   case nir_jump_goto_if:
+      link_blocks(block, jump_instr->else_target, jump_instr->target);
+      break;
+
+   default:
+      unreachable("Invalid jump type");
    }
 }
 
@@ -530,8 +511,6 @@ remove_phi_src(nir_block *block, nir_block *pred)
 static void
 unlink_jump(nir_block *block, nir_jump_type type, bool add_normal_successors)
 {
-   nir_block *next = block->successors[0];
-
    if (block->successors[0])
       remove_phi_src(block->successors[0], block);
    if (block->successors[1])
@@ -584,7 +563,7 @@ stitch_blocks(nir_block *before, nir_block *after)
     * TODO: special case when before is empty and after isn't?
     */
 
-   if (block_ends_in_jump(before)) {
+   if (nir_block_ends_in_jump(before)) {
       assert(exec_list_is_empty(&after->instr_list));
       if (after->successors[0])
          remove_phi_src(after->successors[0], after);
@@ -619,7 +598,7 @@ nir_cf_node_insert(nir_cursor cursor, nir_cf_node *node)
        * already been setup with the correct successors, so we need to set
        * up jumps here as the block is being inserted.
        */
-      if (block_ends_in_jump(block))
+      if (nir_block_ends_in_jump(block))
          nir_handle_add_jump(block);
 
       stitch_blocks(block, after);
@@ -653,8 +632,10 @@ cleanup_cf_node(nir_cf_node *node, nir_function_impl *impl)
       /* We need to walk the instructions and clean up defs/uses */
       nir_foreach_instr_safe(instr, block) {
          if (instr->type == nir_instr_type_jump) {
-            nir_jump_type jump_type = nir_instr_as_jump(instr)->type;
-            unlink_jump(block, jump_type, false);
+            nir_jump_instr *jump = nir_instr_as_jump(instr);
+            unlink_jump(block, jump->type, false);
+            if (jump->type == nir_jump_goto_if)
+               nir_instr_rewrite_src(instr, &jump->condition, NIR_SRC_INIT);
          } else {
             nir_foreach_ssa_def(instr, replace_ssa_def_uses, impl);
             nir_instr_remove(instr);