summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2015-04-10 15:39:34 -0700
committerJason Ekstrand <[email protected]>2015-04-22 18:10:41 -0700
commit06f3c98b9da35b5f5c02bd30599fbde57a19520e (patch)
tree33dcabf55a892c40b52357110414bca89ea23029 /src/glsl
parent4e9b3765947f2c98d618082cd449db2e319bd887 (diff)
nir/locals_to_regs: Initialize registers with constant initializers
Reviewed-by: Connor Abbott <[email protected]>
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/nir/nir_lower_locals_to_regs.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/glsl/nir/nir_lower_locals_to_regs.c b/src/glsl/nir/nir_lower_locals_to_regs.c
index 6ad8ab0c8e6..48459f735ab 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);
}