From 06f3c98b9da35b5f5c02bd30599fbde57a19520e Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 10 Apr 2015 15:39:34 -0700 Subject: [PATCH] nir/locals_to_regs: Initialize registers with constant initializers Reviewed-by: Connor Abbott --- 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 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); } -- 2.30.2