X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fnir%2Fnir_remove_dead_variables.c;h=5037b862263ff4b1b0c711194d75fbfbc5471f23;hb=43d22c8f2011b780467df97e58981522edccfa21;hp=ad69de85b97f2b7aa70858b1e636711dc79c368d;hpb=7f6a0cb29c89a03441be744680a2145445be3a3c;p=mesa.git diff --git a/src/compiler/nir/nir_remove_dead_variables.c b/src/compiler/nir/nir_remove_dead_variables.c index ad69de85b97..5037b862263 100644 --- a/src/compiler/nir/nir_remove_dead_variables.c +++ b/src/compiler/nir/nir_remove_dead_variables.c @@ -27,91 +27,139 @@ #include "nir.h" -static void -add_var_use_intrinsic(nir_intrinsic_instr *instr, struct set *live) +static bool +deref_used_for_not_store(nir_deref_instr *deref) { - unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables; - for (unsigned i = 0; i < num_vars; i++) { - nir_variable *var = instr->variables[i]->var; - _mesa_set_add(live, var); - } -} + nir_foreach_use(src, &deref->dest.ssa) { + switch (src->parent_instr->type) { + case nir_instr_type_deref: + if (deref_used_for_not_store(nir_instr_as_deref(src->parent_instr))) + return true; + break; -static void -add_var_use_call(nir_call_instr *instr, struct set *live) -{ - if (instr->return_deref != NULL) { - nir_variable *var = instr->return_deref->var; - _mesa_set_add(live, var); - } + case nir_instr_type_intrinsic: { + nir_intrinsic_instr *intrin = + nir_instr_as_intrinsic(src->parent_instr); + /* The first source of copy and store intrinsics is the deref to + * write. Don't record those. + */ + if ((intrin->intrinsic != nir_intrinsic_store_deref && + intrin->intrinsic != nir_intrinsic_copy_deref) || + src != &intrin->src[0]) + return true; + break; + } - for (unsigned i = 0; i < instr->num_params; i++) { - nir_variable *var = instr->params[i]->var; - _mesa_set_add(live, var); + default: + /* If it's used by any other instruction type (most likely a texture + * or call instruction), consider it used. + */ + return true; + } } + + return false; } static void -add_var_use_tex(nir_tex_instr *instr, struct set *live) +add_var_use_deref(nir_deref_instr *deref, struct set *live) { - if (instr->texture != NULL) { - nir_variable *var = instr->texture->var; - _mesa_set_add(live, var); - } - - if (instr->sampler != NULL) { - nir_variable *var = instr->sampler->var; - _mesa_set_add(live, var); - } + if (deref->deref_type != nir_deref_type_var) + return; + + /* If it's not a local that never escapes the shader, then any access at + * all means we need to keep it alive. + */ + assert(deref->mode == deref->var->data.mode); + if (!(deref->mode & (nir_var_function_temp | nir_var_shader_temp | nir_var_mem_shared)) || + deref_used_for_not_store(deref)) + _mesa_set_add(live, deref->var); } -static bool -add_var_use_block(nir_block *block, void *state) +static void +add_var_use_shader(nir_shader *shader, struct set *live, nir_variable_mode modes) { - struct set *live = state; - - nir_foreach_instr(block, instr) { - switch(instr->type) { - case nir_instr_type_intrinsic: - add_var_use_intrinsic(nir_instr_as_intrinsic(instr), live); - break; - - case nir_instr_type_call: - add_var_use_call(nir_instr_as_call(instr), live); - break; - - case nir_instr_type_tex: - add_var_use_tex(nir_instr_as_tex(instr), live); - break; - - default: - break; + nir_foreach_function(function, shader) { + if (function->impl) { + nir_foreach_block(block, function->impl) { + nir_foreach_instr(instr, block) { + if (instr->type == nir_instr_type_deref) + add_var_use_deref(nir_instr_as_deref(instr), live); + } + } } } - - return true; } static void -add_var_use_shader(nir_shader *shader, struct set *live) +remove_dead_var_writes(nir_shader *shader, struct set *live) { - nir_foreach_function(shader, function) { - if (function->impl) { - nir_foreach_block(function->impl, add_var_use_block, live); + nir_foreach_function(function, shader) { + if (!function->impl) + continue; + + nir_foreach_block(block, function->impl) { + nir_foreach_instr_safe(instr, block) { + switch (instr->type) { + case nir_instr_type_deref: { + nir_deref_instr *deref = nir_instr_as_deref(instr); + if (deref->deref_type == nir_deref_type_cast && + !nir_deref_instr_parent(deref)) + continue; + + nir_variable_mode parent_mode; + if (deref->deref_type == nir_deref_type_var) + parent_mode = deref->var->data.mode; + else + parent_mode = nir_deref_instr_parent(deref)->mode; + + /* If the parent mode is 0, then it references a dead variable. + * Flag this deref as dead and remove it. + */ + if (parent_mode == 0) { + deref->mode = 0; + nir_instr_remove(&deref->instr); + } + break; + } + + case nir_instr_type_intrinsic: { + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_copy_deref && + intrin->intrinsic != nir_intrinsic_store_deref) + break; + + if (nir_src_as_deref(intrin->src[0])->mode == 0) + nir_instr_remove(instr); + break; + } + + default: + break; /* Nothing to do */ + } + } } } } static bool -remove_dead_vars(struct exec_list *var_list, struct set *live) +remove_dead_vars(struct exec_list *var_list, nir_variable_mode modes, + struct set *live, bool (*can_remove_var)(nir_variable *var)) { bool progress = false; - foreach_list_typed_safe(nir_variable, var, node, var_list) { + nir_foreach_variable_in_list_safe(var, var_list) { + if (!(var->data.mode & modes)) + continue; + + if (can_remove_var && !can_remove_var(var)) + continue; + struct set_entry *entry = _mesa_set_search(live, var); if (entry == NULL) { + /* Mark this variable as used by setting the mode to 0 */ + var->data.mode = 0; exec_node_remove(&var->node); - ralloc_free(var); progress = true; } } @@ -120,42 +168,43 @@ remove_dead_vars(struct exec_list *var_list, struct set *live) } bool -nir_remove_dead_variables(nir_shader *shader, nir_variable_mode mode) +nir_remove_dead_variables(nir_shader *shader, nir_variable_mode modes, + bool (*can_remove_var)(nir_variable *var)) { bool progress = false; - struct set *live = - _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); - - add_var_use_shader(shader, live); - - if (mode == nir_var_uniform || mode == nir_var_all) - progress = remove_dead_vars(&shader->uniforms, live) || progress; - - if (mode == nir_var_shader_in || mode == nir_var_all) - progress = remove_dead_vars(&shader->inputs, live) || progress; - - if (mode == nir_var_shader_out || mode == nir_var_all) - progress = remove_dead_vars(&shader->outputs, live) || progress; + struct set *live = _mesa_pointer_set_create(NULL); - if (mode == nir_var_global || mode == nir_var_all) - progress = remove_dead_vars(&shader->globals, live) || progress; + add_var_use_shader(shader, live, modes); - if (mode == nir_var_system_value || mode == nir_var_all) - progress = remove_dead_vars(&shader->system_values, live) || progress; + if (modes & ~nir_var_function_temp) { + progress = remove_dead_vars(&shader->variables, modes, + live, can_remove_var) || progress; + } - if (mode == nir_var_local || mode == nir_var_all) { - nir_foreach_function(shader, function) { + if (modes & nir_var_function_temp) { + nir_foreach_function(function, shader) { if (function->impl) { - if (remove_dead_vars(&function->impl->locals, live)) { - nir_metadata_preserve(function->impl, nir_metadata_block_index | - nir_metadata_dominance | - nir_metadata_live_ssa_defs); + if (remove_dead_vars(&function->impl->locals, + nir_var_function_temp, + live, can_remove_var)) progress = true; - } } } } + nir_foreach_function(function, shader) { + if (!function->impl) + continue; + + if (progress) { + remove_dead_var_writes(shader, live); + nir_metadata_preserve(function->impl, nir_metadata_block_index | + nir_metadata_dominance); + } else { + nir_metadata_preserve(function->impl, nir_metadata_all); + } + } + _mesa_set_destroy(live, NULL); return progress; }