X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fnir%2Fnir_lower_vars_to_ssa.c;h=30870e6e35c41b239687d63fbdc70ee9774bba98;hb=025bdbac3e09ae9bac9eefb831e9446b9574d120;hp=3f37acaed33f7c752da946e6ac25821a1c6cb118;hpb=a331d7d1cdfdc971f707fb6b1f71edbad622c804;p=mesa.git diff --git a/src/compiler/nir/nir_lower_vars_to_ssa.c b/src/compiler/nir/nir_lower_vars_to_ssa.c index 3f37acaed33..30870e6e35c 100644 --- a/src/compiler/nir/nir_lower_vars_to_ssa.c +++ b/src/compiler/nir/nir_lower_vars_to_ssa.c @@ -56,11 +56,19 @@ struct deref_node { */ bool is_direct; + /* Set on a root node for a variable to indicate that variable is used by a + * cast or passed through some other sequence of instructions that are not + * derefs. + */ + bool has_complex_use; + struct deref_node *wildcard; struct deref_node *indirect; struct deref_node *children[0]; }; +#define UNDEF_NODE ((struct deref_node *)(uintptr_t)1) + struct lower_variables_state { nir_shader *shader; void *dead_ctx; @@ -145,12 +153,20 @@ get_deref_node_recur(nir_deref_instr *deref, if (deref->deref_type == nir_deref_type_var) return get_deref_node_for_var(deref->var, state); + if (deref->deref_type == nir_deref_type_cast) + return NULL; + struct deref_node *parent = get_deref_node_recur(nir_deref_instr_parent(deref), state); + if (parent == NULL) + return NULL; + + if (parent == UNDEF_NODE) + return UNDEF_NODE; switch (deref->deref_type) { case nir_deref_type_struct: - assert(glsl_type_is_struct(parent->type)); + assert(glsl_type_is_struct_or_ifc(parent->type)); assert(deref->strct.index < glsl_get_length(parent->type)); if (parent->children[deref->strct.index] == NULL) { @@ -162,15 +178,14 @@ get_deref_node_recur(nir_deref_instr *deref, return parent->children[deref->strct.index]; case nir_deref_type_array: { - nir_const_value *const_index = nir_src_as_const_value(deref->arr.index); - if (const_index) { - uint32_t index = const_index->u32[0]; + if (nir_src_is_const(deref->arr.index)) { + uint32_t index = nir_src_as_uint(deref->arr.index); /* This is possible if a loop unrolls and generates an * out-of-bounds offset. We need to handle this at least * somewhat gracefully. */ if (index >= glsl_get_length(parent->type)) - return NULL; + return UNDEF_NODE; if (parent->children[index] == NULL) { parent->children[index] = @@ -206,6 +221,12 @@ get_deref_node_recur(nir_deref_instr *deref, static struct deref_node * get_deref_node(nir_deref_instr *deref, struct lower_variables_state *state) { + /* This pass only works on local variables. Just ignore any derefs with + * a non-local mode. + */ + if (deref->mode != nir_var_function_temp) + return NULL; + struct deref_node *node = get_deref_node_recur(deref, state); if (!node) return NULL; @@ -214,7 +235,8 @@ get_deref_node(nir_deref_instr *deref, struct lower_variables_state *state) * already in the list and we only bother for deref nodes which are used * directly in a load or store. */ - if (node->is_direct && state->add_to_direct_deref_nodes && + if (node != UNDEF_NODE && node->is_direct && + state->add_to_direct_deref_nodes && node->direct_derefs_link.next == NULL) { nir_deref_path_init(&node->path, deref, state->dead_ctx); assert(deref->var != NULL); @@ -246,9 +268,7 @@ foreach_deref_node_worker(struct deref_node *node, nir_deref_instr **path, return; case nir_deref_type_array: { - nir_const_value *const_index = nir_src_as_const_value((*path)->arr.index); - assert(const_index); - uint32_t index = const_index->u32[0]; + uint32_t index = nir_src_as_uint((*path)->arr.index); if (node->children[index]) { foreach_deref_node_worker(node->children[index], @@ -312,11 +332,10 @@ path_may_be_aliased_node(struct deref_node *node, nir_deref_instr **path, } case nir_deref_type_array: { - nir_const_value *const_index = nir_src_as_const_value((*path)->arr.index); - if (!const_index) + if (!nir_src_is_const((*path)->arr.index)) return true; - uint32_t index = const_index->u32[0]; + uint32_t index = nir_src_as_uint((*path)->arr.index); /* If there is an indirect at this level, we're aliased. */ if (node->indirect) @@ -359,9 +378,28 @@ path_may_be_aliased(nir_deref_path *path, { assert(path->path[0]->deref_type == nir_deref_type_var); nir_variable *var = path->path[0]->var; + struct deref_node *var_node = get_deref_node_for_var(var, state); + + /* First see if this variable is ever used by anything other than a + * load/store. If there's even so much as a cast in the way, we have to + * assume aliasing and bail. + */ + if (var_node->has_complex_use) + return true; - return path_may_be_aliased_node(get_deref_node_for_var(var, state), - &path->path[1], state); + return path_may_be_aliased_node(var_node, &path->path[1], state); +} + +static void +register_complex_use(nir_deref_instr *deref, + struct lower_variables_state *state) +{ + assert(deref->deref_type == nir_deref_type_var); + struct deref_node *node = get_deref_node_for_var(deref->var, state); + if (node == NULL) + return; + + node->has_complex_use = true; } static void @@ -370,12 +408,11 @@ register_load_instr(nir_intrinsic_instr *load_instr, { nir_deref_instr *deref = nir_src_as_deref(load_instr->src[0]); struct deref_node *node = get_deref_node(deref, state); - if (node == NULL) + if (node == NULL || node == UNDEF_NODE) return; if (node->loads == NULL) - node->loads = _mesa_set_create(state->dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); + node->loads = _mesa_pointer_set_create(state->dead_ctx); _mesa_set_add(node->loads, load_instr); } @@ -386,12 +423,11 @@ register_store_instr(nir_intrinsic_instr *store_instr, { nir_deref_instr *deref = nir_src_as_deref(store_instr->src[0]); struct deref_node *node = get_deref_node(deref, state); - if (node == NULL) + if (node == NULL || node == UNDEF_NODE) return; if (node->stores == NULL) - node->stores = _mesa_set_create(state->dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); + node->stores = _mesa_pointer_set_create(state->dead_ctx); _mesa_set_add(node->stores, store_instr); } @@ -403,12 +439,11 @@ register_copy_instr(nir_intrinsic_instr *copy_instr, for (unsigned idx = 0; idx < 2; idx++) { nir_deref_instr *deref = nir_src_as_deref(copy_instr->src[idx]); struct deref_node *node = get_deref_node(deref, state); - if (node == NULL) + if (node == NULL || node == UNDEF_NODE) continue; if (node->copies == NULL) - node->copies = _mesa_set_create(state->dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); + node->copies = _mesa_pointer_set_create(state->dead_ctx); _mesa_set_add(node->copies, copy_instr); } @@ -420,26 +455,41 @@ register_variable_uses(nir_function_impl *impl, { nir_foreach_block(block, impl) { nir_foreach_instr_safe(instr, block) { - if (instr->type != nir_instr_type_intrinsic) - continue; + switch (instr->type) { + case nir_instr_type_deref: { + nir_deref_instr *deref = nir_instr_as_deref(instr); - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (deref->deref_type == nir_deref_type_var && + nir_deref_instr_has_complex_use(deref)) + register_complex_use(deref, state); - switch (intrin->intrinsic) { - case nir_intrinsic_load_deref: - register_load_instr(intrin, state); break; + } - case nir_intrinsic_store_deref: - register_store_instr(intrin, state); - break; + case nir_instr_type_intrinsic: { + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + + switch (intrin->intrinsic) { + case nir_intrinsic_load_deref: + register_load_instr(intrin, state); + break; + + case nir_intrinsic_store_deref: + register_store_instr(intrin, state); + break; - case nir_intrinsic_copy_deref: - register_copy_instr(intrin, state); + case nir_intrinsic_copy_deref: + register_copy_instr(intrin, state); + break; + + default: + continue; + } break; + } default: - continue; + break; } } } @@ -458,7 +508,6 @@ lower_copies_to_load_store(struct deref_node *node, nir_builder b; nir_builder_init(&b, state->impl); - struct set_entry *copy_entry; set_foreach(node->copies, copy_entry) { nir_intrinsic_instr *copy = (void *)copy_entry->key; @@ -506,8 +555,14 @@ rename_variables(struct lower_variables_state *state) switch (intrin->intrinsic) { case nir_intrinsic_load_deref: { nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + if (deref->mode != nir_var_function_temp) + continue; + struct deref_node *node = get_deref_node(deref, state); - if (node == NULL) { + if (node == NULL) + continue; + + if (node == UNDEF_NODE) { /* 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 @@ -530,10 +585,10 @@ rename_variables(struct lower_variables_state *state) continue; nir_alu_instr *mov = nir_alu_instr_create(state->shader, - nir_op_imov); + nir_op_mov); 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++) + for (unsigned i = intrin->num_components; i < NIR_MAX_VEC_COMPONENTS; i++) mov->src[0].swizzle[i] = 0; assert(intrin->dest.is_ssa); @@ -553,12 +608,17 @@ rename_variables(struct lower_variables_state *state) case nir_intrinsic_store_deref: { nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + if (deref->mode != nir_var_function_temp) + continue; + struct deref_node *node = get_deref_node(deref, state); + if (node == NULL) + continue; assert(intrin->src[1].is_ssa); nir_ssa_def *value = intrin->src[1].ssa; - if (node == NULL) { + if (node == UNDEF_NODE) { /* Probably an out-of-bounds array store. That should be a * no-op. */ nir_instr_remove(&intrin->instr); @@ -580,12 +640,12 @@ rename_variables(struct lower_variables_state *state) * intrin->num_components and value->num_components * may differ. */ - unsigned swiz[4]; - for (unsigned i = 0; i < 4; i++) + unsigned swiz[NIR_MAX_VEC_COMPONENTS]; + for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++) swiz[i] = i < intrin->num_components ? i : 0; new_def = nir_swizzle(&b, value, swiz, - intrin->num_components, false); + intrin->num_components); } else { nir_ssa_def *old_def = nir_phi_builder_value_get_block_def(node->pb_value, block); @@ -593,7 +653,7 @@ rename_variables(struct lower_variables_state *state) * written values with the existing contents of unwritten * channels, creating a new SSA value for the whole vector. */ - nir_ssa_def *srcs[4]; + nir_ssa_def *srcs[NIR_MAX_VEC_COMPONENTS]; for (unsigned i = 0; i < intrin->num_components; i++) { if (wrmask & (1 << i)) { srcs[i] = nir_channel(&b, value, i); @@ -654,9 +714,7 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl) state.dead_ctx = ralloc_context(state.shader); state.impl = impl; - state.deref_var_nodes = _mesa_hash_table_create(state.dead_ctx, - _mesa_hash_pointer, - _mesa_key_pointer_equal); + state.deref_var_nodes = _mesa_pointer_hash_table_create(state.dead_ctx); exec_list_make_empty(&state.direct_deref_nodes); /* Build the initial deref structures and direct_deref_nodes table */ @@ -676,12 +734,9 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl) nir_deref_path *path = &node->path; assert(path->path[0]->deref_type == nir_deref_type_var); - nir_variable *var = path->path[0]->var; - if (var->data.mode != nir_var_local) { - exec_node_remove(&node->direct_derefs_link); - continue; - } + /* We don't build deref nodes for non-local variables */ + assert(path->path[0]->var->data.mode == nir_var_function_temp); if (path_may_be_aliased(path, &state)) { exec_node_remove(&node->direct_derefs_link); @@ -694,8 +749,10 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl) foreach_deref_node_match(path, lower_copies_to_load_store, &state); } - if (!progress) + if (!progress) { + nir_metadata_preserve(impl, nir_metadata_all); return false; + } nir_metadata_require(impl, nir_metadata_dominance); @@ -709,7 +766,9 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl) state.phi_builder = nir_phi_builder_create(state.impl); - NIR_VLA(BITSET_WORD, store_blocks, BITSET_WORDS(state.impl->num_blocks)); + BITSET_WORD *store_blocks = + ralloc_array(state.dead_ctx, BITSET_WORD, + BITSET_WORDS(state.impl->num_blocks)); foreach_list_typed(struct deref_node, node, direct_derefs_link, &state.direct_deref_nodes) { if (!node->lower_to_ssa) @@ -718,10 +777,10 @@ 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->path.path[0]->var->constant_initializer == NULL); + assert(node->path.path[0]->var->constant_initializer == NULL && + node->path.path[0]->var->pointer_initializer == NULL); if (node->stores) { - struct set_entry *store_entry; set_foreach(node->stores, store_entry) { nir_intrinsic_instr *store = (nir_intrinsic_instr *)store_entry->key;