static void
add_cf_node(nir_cf_node *cf, struct set *invariants)
{
   if (cf->type == nir_cf_node_if) {
      nir_if *if_stmt = nir_cf_node_as_if(cf);
      add_src(&if_stmt->condition, invariants);
   }

   if (cf->parent)
      add_cf_node(cf->parent, invariants);
}
Exemple #2
0
static bool
dead_cf_list(struct exec_list *list, bool *list_ends_in_jump)
{
   bool progress = false;
   *list_ends_in_jump = false;

   nir_cf_node *prev = NULL;

   foreach_list_typed(nir_cf_node, cur, node, list) {
      switch (cur->type) {
      case nir_cf_node_block: {
         nir_block *block = nir_cf_node_as_block(cur);
         if (dead_cf_block(block)) {
            /* We just deleted the if or loop after this block, so we may have
             * deleted the block before or after it -- which one is an
             * implementation detail. Therefore, to recover the place we were
             * at, we have to use the previous cf_node.
             */

            if (prev) {
               cur = nir_cf_node_next(prev);
            } else {
               cur = exec_node_data(nir_cf_node, exec_list_get_head(list),
                                    node);
            }

            block = nir_cf_node_as_block(cur);

            progress = true;
         }

         if (ends_in_jump(block)) {
            *list_ends_in_jump = true;

            if (!exec_node_is_tail_sentinel(cur->node.next)) {
               remove_after_cf_node(cur);
               return true;
            }
         }

         break;
      }

      case nir_cf_node_if: {
         nir_if *if_stmt = nir_cf_node_as_if(cur);
         bool then_ends_in_jump, else_ends_in_jump;
         progress |= dead_cf_list(&if_stmt->then_list, &then_ends_in_jump);
         progress |= dead_cf_list(&if_stmt->else_list, &else_ends_in_jump);

         if (then_ends_in_jump && else_ends_in_jump) {
            *list_ends_in_jump = true;
            nir_block *next = nir_cf_node_as_block(nir_cf_node_next(cur));
            if (!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;
      }

      case nir_cf_node_loop: {
         nir_loop *loop = nir_cf_node_as_loop(cur);
         bool dummy;
         progress |= dead_cf_list(&loop->body, &dummy);

         break;
      }

      default:
         unreachable("unknown cf node type");
      }

      prev = cur;
   }

   return progress;
}