nir/vars_to_ssa: Remove an unnecessary deref_arry_type check
[mesa.git] / src / compiler / nir / nir_lower_vars_to_ssa.c
index 249c389233552ecc409966d71d23e0cedca91656..970eb05307a46cf6dc1a8205b97ee1cdff97d96a 100644 (file)
@@ -245,8 +245,12 @@ foreach_deref_node_worker(struct deref_node *node, nir_deref *deref,
 
       case nir_deref_type_struct: {
          nir_deref_struct *str = nir_deref_as_struct(deref->child);
-         return foreach_deref_node_worker(node->children[str->index],
-                                          deref->child, cb, state);
+         if (node->children[str->index] &&
+             !foreach_deref_node_worker(node->children[str->index],
+                                        deref->child, cb, state))
+            return false;
+
+         return true;
       }
 
       default:
@@ -294,15 +298,16 @@ deref_may_be_aliased_node(struct deref_node *node, nir_deref *deref,
       switch (deref->child->deref_type) {
       case nir_deref_type_array: {
          nir_deref_array *arr = nir_deref_as_array(deref->child);
-         if (arr->deref_array_type == nir_deref_array_type_indirect)
-            return true;
+
+         /* This is a child of one of the derefs in direct_deref_nodes,
+          * so we know it is direct.
+          */
+         assert(arr->deref_array_type == nir_deref_array_type_direct);
 
          /* If there is an indirect at this level, we're aliased. */
          if (node->indirect)
             return true;
 
-         assert(arr->deref_array_type == nir_deref_array_type_direct);
-
          if (node->children[arr->base_offset] &&
              deref_may_be_aliased_node(node->children[arr->base_offset],
                                        deref->child, state))
@@ -402,37 +407,35 @@ register_copy_instr(nir_intrinsic_instr *copy_instr,
    }
 }
 
-/* Registers all variable uses in the given block. */
-static bool
-register_variable_uses_block(nir_block *block, void *void_state)
+static void
+register_variable_uses(nir_function_impl *impl,
+                       struct lower_variables_state *state)
 {
-   struct lower_variables_state *state = void_state;
-
-   nir_foreach_instr_safe(block, instr) {
-      if (instr->type != nir_instr_type_intrinsic)
-         continue;
+   nir_foreach_block(block, impl) {
+      nir_foreach_instr_safe(instr, block) {
+         if (instr->type != nir_instr_type_intrinsic)
+            continue;
 
-      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
+         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
 
-      switch (intrin->intrinsic) {
-      case nir_intrinsic_load_var:
-         register_load_instr(intrin, state);
-         break;
+         switch (intrin->intrinsic) {
+         case nir_intrinsic_load_var:
+            register_load_instr(intrin, state);
+            break;
 
-      case nir_intrinsic_store_var:
-         register_store_instr(intrin, state);
-         break;
+         case nir_intrinsic_store_var:
+            register_store_instr(intrin, state);
+            break;
 
-      case nir_intrinsic_copy_var:
-         register_copy_instr(intrin, state);
-         break;
+         case nir_intrinsic_copy_var:
+            register_copy_instr(intrin, state);
+            break;
 
-      default:
-         continue;
+         default:
+            continue;
+         }
       }
    }
-
-   return true;
 }
 
 /* Walks over all of the copy instructions to or from the given deref_node
@@ -461,7 +464,7 @@ lower_copies_to_load_store(struct deref_node *node,
 
          struct set_entry *arg_entry = _mesa_set_search(arg_node->copies, copy);
          assert(arg_entry);
-         _mesa_set_remove(node->copies, arg_entry);
+         _mesa_set_remove(arg_node->copies, arg_entry);
       }
 
       nir_instr_remove(&copy->instr);
@@ -472,141 +475,140 @@ lower_copies_to_load_store(struct deref_node *node,
    return true;
 }
 
-/* Performs variable renaming by doing a DFS of the dominance tree
+/* Performs variable renaming
  *
  * This algorithm is very similar to the one outlined in "Efficiently
  * Computing Static Single Assignment Form and the Control Dependence
- * Graph" by Cytron et. al.  The primary difference is that we only put one
+ * Graph" by Cytron et al.  The primary difference is that we only put one
  * SSA def on the stack per block.
  */
 static bool
-rename_variables_block(nir_block *block, struct lower_variables_state *state)
+rename_variables(struct lower_variables_state *state)
 {
    nir_builder b;
    nir_builder_init(&b, state->impl);
 
-   nir_foreach_instr_safe(block, instr) {
-      if (instr->type != nir_instr_type_intrinsic)
-         continue;
-
-      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
-
-      switch (intrin->intrinsic) {
-      case nir_intrinsic_load_var: {
-         struct deref_node *node =
-            get_deref_node(intrin->variables[0], state);
-
-         if (node == NULL) {
-            /* If we hit this path then we are referencing an invalid
-             * value.  Most likely, we unrolled something and are
-             * reading past the end of some array.  In any case, this
-             * should result in an undefined value.
-             */
-            nir_ssa_undef_instr *undef =
-               nir_ssa_undef_instr_create(state->shader,
-                                          intrin->num_components,
-                                          intrin->dest.ssa.bit_size);
-
-            nir_instr_insert_before(&intrin->instr, &undef->instr);
-            nir_instr_remove(&intrin->instr);
-
-            nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
-                                     nir_src_for_ssa(&undef->def));
-            continue;
-         }
-
-         if (!node->lower_to_ssa)
+   nir_foreach_block(block, state->impl) {
+      nir_foreach_instr_safe(instr, block) {
+         if (instr->type != nir_instr_type_intrinsic)
             continue;
 
-         nir_alu_instr *mov = nir_alu_instr_create(state->shader,
-                                                   nir_op_imov);
-         mov->src[0].src = nir_src_for_ssa(
-            nir_phi_builder_value_get_block_def(node->pb_value, block));
-         for (unsigned i = intrin->num_components; i < 4; i++)
-            mov->src[0].swizzle[i] = 0;
-
-         assert(intrin->dest.is_ssa);
+         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
+
+         switch (intrin->intrinsic) {
+         case nir_intrinsic_load_var: {
+            struct deref_node *node =
+               get_deref_node(intrin->variables[0], state);
+
+            if (node == NULL) {
+               /* If we hit this path then we are referencing an invalid
+                * value.  Most likely, we unrolled something and are
+                * reading past the end of some array.  In any case, this
+                * should result in an undefined value.
+                */
+               nir_ssa_undef_instr *undef =
+                  nir_ssa_undef_instr_create(state->shader,
+                                             intrin->num_components,
+                                             intrin->dest.ssa.bit_size);
+
+               nir_instr_insert_before(&intrin->instr, &undef->instr);
+               nir_instr_remove(&intrin->instr);
+
+               nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
+                                        nir_src_for_ssa(&undef->def));
+               continue;
+            }
 
-         mov->dest.write_mask = (1 << intrin->num_components) - 1;
-         nir_ssa_dest_init(&mov->instr, &mov->dest.dest,
-                           intrin->num_components,
-                           intrin->dest.ssa.bit_size, NULL);
+            if (!node->lower_to_ssa)
+               continue;
 
-         nir_instr_insert_before(&intrin->instr, &mov->instr);
-         nir_instr_remove(&intrin->instr);
+            nir_alu_instr *mov = nir_alu_instr_create(state->shader,
+                                                      nir_op_imov);
+            mov->src[0].src = nir_src_for_ssa(
+               nir_phi_builder_value_get_block_def(node->pb_value, block));
+            for (unsigned i = intrin->num_components; i < 4; i++)
+               mov->src[0].swizzle[i] = 0;
 
-         nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
-                                  nir_src_for_ssa(&mov->dest.dest.ssa));
-         break;
-      }
+            assert(intrin->dest.is_ssa);
 
-      case nir_intrinsic_store_var: {
-         struct deref_node *node =
-            get_deref_node(intrin->variables[0], state);
+            mov->dest.write_mask = (1 << intrin->num_components) - 1;
+            nir_ssa_dest_init(&mov->instr, &mov->dest.dest,
+                              intrin->num_components,
+                              intrin->dest.ssa.bit_size, NULL);
 
-         if (node == NULL) {
-            /* Probably an out-of-bounds array store.  That should be a
-             * no-op. */
+            nir_instr_insert_before(&intrin->instr, &mov->instr);
             nir_instr_remove(&intrin->instr);
-            continue;
-         }
-
-         if (!node->lower_to_ssa)
-            continue;
-
-         assert(intrin->num_components ==
-                glsl_get_vector_elements(node->type));
 
-         assert(intrin->src[0].is_ssa);
+            nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
+                                     nir_src_for_ssa(&mov->dest.dest.ssa));
+            break;
+         }
 
-         nir_ssa_def *new_def;
-         b.cursor = nir_before_instr(&intrin->instr);
+         case nir_intrinsic_store_var: {
+            struct deref_node *node =
+               get_deref_node(intrin->variables[0], state);
 
-         unsigned wrmask = nir_intrinsic_write_mask(intrin);
-         if (wrmask == (1 << intrin->num_components) - 1) {
-            /* Whole variable store - just copy the source.  Note that
-             * intrin->num_components and intrin->src[0].ssa->num_components
-             * may differ.
-             */
-            unsigned swiz[4];
-            for (unsigned i = 0; i < 4; i++)
-               swiz[i] = i < intrin->num_components ? i : 0;
+            if (node == NULL) {
+               /* Probably an out-of-bounds array store.  That should be a
+                * no-op. */
+               nir_instr_remove(&intrin->instr);
+               continue;
+            }
 
-            new_def = nir_swizzle(&b, intrin->src[0].ssa, swiz,
-                                  intrin->num_components, false);
-         } else {
-            nir_ssa_def *old_def =
-               nir_phi_builder_value_get_block_def(node->pb_value, block);
-            /* For writemasked store_var intrinsics, we combine the newly
-             * written values with the existing contents of unwritten
-             * channels, creating a new SSA value for the whole vector.
-             */
-            nir_ssa_def *srcs[4];
-            for (unsigned i = 0; i < intrin->num_components; i++) {
-               if (wrmask & (1 << i)) {
-                  srcs[i] = nir_channel(&b, intrin->src[0].ssa, i);
-               } else {
-                  srcs[i] = nir_channel(&b, old_def, i);
+            if (!node->lower_to_ssa)
+               continue;
+
+            assert(intrin->num_components ==
+                   glsl_get_vector_elements(node->type));
+
+            assert(intrin->src[0].is_ssa);
+
+            nir_ssa_def *new_def;
+            b.cursor = nir_before_instr(&intrin->instr);
+
+            unsigned wrmask = nir_intrinsic_write_mask(intrin);
+            if (wrmask == (1 << intrin->num_components) - 1) {
+               /* Whole variable store - just copy the source.  Note that
+                * intrin->num_components and intrin->src[0].ssa->num_components
+                * may differ.
+                */
+               unsigned swiz[4];
+               for (unsigned i = 0; i < 4; i++)
+                  swiz[i] = i < intrin->num_components ? i : 0;
+
+               new_def = nir_swizzle(&b, intrin->src[0].ssa, swiz,
+                                     intrin->num_components, false);
+            } else {
+               nir_ssa_def *old_def =
+                  nir_phi_builder_value_get_block_def(node->pb_value, block);
+               /* For writemasked store_var intrinsics, we combine the newly
+                * written values with the existing contents of unwritten
+                * channels, creating a new SSA value for the whole vector.
+                */
+               nir_ssa_def *srcs[4];
+               for (unsigned i = 0; i < intrin->num_components; i++) {
+                  if (wrmask & (1 << i)) {
+                     srcs[i] = nir_channel(&b, intrin->src[0].ssa, i);
+                  } else {
+                     srcs[i] = nir_channel(&b, old_def, i);
+                  }
                }
+               new_def = nir_vec(&b, srcs, intrin->num_components);
             }
-            new_def = nir_vec(&b, srcs, intrin->num_components);
-         }
 
-         assert(new_def->num_components == intrin->num_components);
+            assert(new_def->num_components == intrin->num_components);
 
-         nir_phi_builder_value_set_block_def(node->pb_value, block, new_def);
-         nir_instr_remove(&intrin->instr);
-         break;
-      }
+            nir_phi_builder_value_set_block_def(node->pb_value, block, new_def);
+            nir_instr_remove(&intrin->instr);
+            break;
+         }
 
-      default:
-         break;
+         default:
+            break;
+         }
       }
    }
 
-   for (unsigned i = 0; i < block->num_dom_children; ++i)
-      rename_variables_block(block->dom_children[i], state);
-
    return true;
 }
 
@@ -622,14 +624,12 @@ rename_variables_block(nir_block *block, struct lower_variables_state *state)
  *     fully-direct references we see and store them in the
  *     direct_deref_nodes hash table.
  *
- *  2) Walk over the the list of fully-qualified direct derefs generated in
+ *  2) Walk over the list of fully-qualified direct derefs generated in
  *     the previous pass.  For each deref, we determine if it can ever be
  *     aliased, i.e. if there is an indirect reference anywhere that may
  *     refer to it.  If it cannot be aliased, we mark it for lowering to an
  *     SSA value.  At this point, we lower any var_copy instructions that
- *     use the given deref to load/store operations and, if the deref has a
- *     constant initializer, we go ahead and add a load_const value at the
- *     beginning of the function with the initialized value.
+ *     use the given deref to load/store operations.
  *
  *  3) Walk over the list of derefs we plan to lower to SSA values and
  *     insert phi nodes as needed.
@@ -653,7 +653,8 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)
 
    /* Build the initial deref structures and direct_deref_nodes table */
    state.add_to_direct_deref_nodes = true;
-   nir_foreach_block(impl, register_variable_uses_block, &state);
+
+   register_variable_uses(impl, &state);
 
    bool progress = false;
 
@@ -693,7 +694,7 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)
     * added load/store instructions are registered.  We need this
     * information for phi node insertion below.
     */
-   nir_foreach_block(impl, register_variable_uses_block, &state);
+   register_variable_uses(impl, &state);
 
    state.phi_builder = nir_phi_builder_create(state.impl);
 
@@ -706,6 +707,8 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)
       memset(store_blocks, 0,
              BITSET_WORDS(state.impl->num_blocks) * sizeof(*store_blocks));
 
+      assert(node->deref->var->constant_initializer == NULL);
+
       if (node->stores) {
          struct set_entry *store_entry;
          set_foreach(node->stores, store_entry) {
@@ -715,25 +718,14 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)
          }
       }
 
-      if (node->deref->var->constant_initializer)
-         BITSET_SET(store_blocks, 0);
-
       node->pb_value =
          nir_phi_builder_add_value(state.phi_builder,
                                    glsl_get_vector_elements(node->type),
-                                   glsl_get_bit_size(glsl_get_base_type(node->type)),
+                                   glsl_get_bit_size(node->type),
                                    store_blocks);
-
-      if (node->deref->var->constant_initializer) {
-         nir_load_const_instr *load =
-            nir_deref_get_const_initializer_load(state.shader, node->deref);
-         nir_instr_insert_before_cf_list(&impl->body, &load->instr);
-         nir_phi_builder_value_set_block_def(node->pb_value,
-                                             nir_start_block(impl), &load->def);
-      }
    }
 
-   rename_variables_block(nir_start_block(impl), &state);
+   rename_variables(&state);
 
    nir_phi_builder_finish(state.phi_builder);
 
@@ -745,11 +737,15 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)
    return progress;
 }
 
-void
+bool
 nir_lower_vars_to_ssa(nir_shader *shader)
 {
-   nir_foreach_function(shader, function) {
+   bool progress = false;
+
+   nir_foreach_function(function, shader) {
       if (function->impl)
-         nir_lower_vars_to_ssa_impl(function->impl);
+         progress |= nir_lower_vars_to_ssa_impl(function->impl);
    }
+
+   return progress;
 }