[Mesa-dev] [PATCH 11/12] nir/locals_to_regs: Initialize registers with constant initializers

Jason Ekstrand jason at jlekstrand.net
Fri Apr 10 17:48:54 PDT 2015


---
 src/glsl/nir/nir_lower_locals_to_regs.c | 103 ++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/src/glsl/nir/nir_lower_locals_to_regs.c b/src/glsl/nir/nir_lower_locals_to_regs.c
index 6ad8ab0..48459f7 100644
--- a/src/glsl/nir/nir_lower_locals_to_regs.c
+++ b/src/glsl/nir/nir_lower_locals_to_regs.c
@@ -26,6 +26,7 @@
  */
 
 #include "nir.h"
+#include "nir_array.h"
 
 struct locals_to_regs_state {
    nir_shader *shader;
@@ -33,6 +34,12 @@ struct locals_to_regs_state {
 
    /* A hash table mapping derefs to registers */
    struct hash_table *regs_table;
+
+   /* A growing array of derefs that we have encountered.  There is exactly
+    * one element of this array per element in the hash table.  This is
+    * used to make adding register initialization code deterministic.
+    */
+   nir_array derefs_array;
 };
 
 /* The following two functions implement a hash and equality check for
@@ -112,6 +119,7 @@ get_reg_for_deref(nir_deref_var *deref, struct locals_to_regs_state *state)
    reg->num_array_elems = array_size > 1 ? array_size : 0;
 
    _mesa_hash_table_insert_pre_hashed(state->regs_table, hash, deref, reg);
+   nir_array_add(&state->derefs_array, nir_deref_var *, deref);
 
    return reg;
 }
@@ -250,6 +258,82 @@ lower_locals_to_regs_block(nir_block *block, void *void_state)
    return true;
 }
 
+static nir_block *
+compute_reg_usedef_lca(nir_register *reg)
+{
+   struct set_entry *entry;
+   nir_block *lca = NULL;
+
+   set_foreach(reg->defs, entry)
+      lca = nir_dominance_lca(lca, ((nir_instr *)entry->key)->block);
+
+   set_foreach(reg->uses, entry)
+      lca = nir_dominance_lca(lca, ((nir_instr *)entry->key)->block);
+
+   set_foreach(reg->if_uses, entry) {
+      nir_if *if_stmt = (nir_if *)entry->key;
+      nir_cf_node *prev_node = nir_cf_node_prev(&if_stmt->cf_node);
+      assert(prev_node->type == nir_cf_node_block);
+      lca = nir_dominance_lca(lca, nir_cf_node_as_block(prev_node));
+   }
+
+   return lca;
+}
+
+static void
+insert_constant_initializer(nir_deref_var *deref_head, nir_deref *deref_tail,
+                            nir_block *block,
+                            struct locals_to_regs_state *state)
+{
+   if (deref_tail->child) {
+      switch (deref_tail->child->deref_type) {
+      case nir_deref_type_array: {
+         unsigned array_elems = glsl_get_length(deref_tail->type);
+
+         nir_deref_array arr_deref;
+         arr_deref.deref = *deref_tail->child;
+         arr_deref.deref_array_type = nir_deref_array_type_direct;
+
+         nir_deref *old_child = deref_tail->child;
+         deref_tail->child = &arr_deref.deref;
+         for (unsigned i = 0; i < array_elems; i++) {
+            arr_deref.base_offset = i;
+            insert_constant_initializer(deref_head, &arr_deref.deref,
+                                        block, state);
+         }
+         deref_tail->child = old_child;
+         return;
+      }
+
+      case nir_deref_type_struct:
+         insert_constant_initializer(deref_head, deref_tail->child,
+                                     block, state);
+         return;
+
+      default:
+         unreachable("Invalid deref child type");
+      }
+   }
+
+   assert(deref_tail->child == NULL);
+
+   nir_load_const_instr *load =
+      nir_deref_get_const_initializer_load(state->shader, deref_head);
+   nir_instr_insert_before_block(block, &load->instr);
+
+   nir_src reg_src = get_deref_reg_src(deref_head, &load->instr, state);
+
+   nir_alu_instr *mov = nir_alu_instr_create(state->shader, nir_op_imov);
+   mov->src[0].src = nir_src_for_ssa(&load->def);
+   mov->dest.write_mask = (1 << load->def.num_components) - 1;
+   mov->dest.dest.is_ssa = false;
+   mov->dest.dest.reg.reg = reg_src.reg.reg;
+   mov->dest.dest.reg.base_offset = reg_src.reg.base_offset;
+   mov->dest.dest.reg.indirect = reg_src.reg.indirect;
+
+   nir_instr_insert_after(&load->instr, &mov->instr);
+}
+
 static void
 nir_lower_locals_to_regs_impl(nir_function_impl *impl)
 {
@@ -258,12 +342,31 @@ nir_lower_locals_to_regs_impl(nir_function_impl *impl)
    state.shader = impl->overload->function->shader;
    state.impl = impl;
    state.regs_table = _mesa_hash_table_create(NULL, hash_deref, derefs_equal);
+   nir_array_init(&state.derefs_array, NULL);
+
+   nir_metadata_require(impl, nir_metadata_dominance);
 
    nir_foreach_block(impl, lower_locals_to_regs_block, &state);
 
+   nir_array_foreach(&state.derefs_array, nir_deref_var *, deref_ptr) {
+      nir_deref_var *deref = *deref_ptr;
+      struct hash_entry *deref_entry =
+         _mesa_hash_table_search(state.regs_table, deref);
+      assert(deref_entry && deref_entry->key == deref);
+      nir_register *reg = (nir_register *)deref_entry->data;
+
+      if (deref->var->constant_initializer == NULL)
+         continue;
+
+      nir_block *usedef_lca = compute_reg_usedef_lca(reg);
+
+      insert_constant_initializer(deref, &deref->deref, usedef_lca, &state);
+   }
+
    nir_metadata_preserve(impl, nir_metadata_block_index |
                                nir_metadata_dominance);
 
+   nir_array_fini(&state.derefs_array);
    _mesa_hash_table_destroy(state.regs_table, NULL);
 }
 
-- 
2.3.5



More information about the mesa-dev mailing list