nir: Free instructions more often

Soon we'll be allocating instructions out of a per-shader pool, which
means that if we don't free too many instructions during the main
optimization loop, the final nir_sweep() call will create holes which
can't be filled. By freeing instructions more aggressively, we can
allocate more instructions from the freelist which will reduce the final
memory usage.

Modified from Connor Abbott's original patch to rebase on top of
refactored DCE and so that the use-after-free in nir_algebraic_impl() is
fixed.

Co-authored-by: Rhys Perry <pendingchaos02@gmail.com>
Reviewed-by: Jason Ekstrand <jason.ekstrand@collabora.com>
Reviewed-by: Emma Anholt <emma@anholt.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12910>
This commit is contained in:
Connor Abbott
2019-03-19 14:16:41 +01:00
committed by Marge Bot
parent 8f159a8576
commit 9d9b891f94
3 changed files with 33 additions and 22 deletions

View File

@@ -685,14 +685,15 @@ nir_algebraic_update_automaton(nir_instr *new_instr,
nir_instr_worklist_destroy(automaton_worklist);
}
nir_ssa_def *
static nir_ssa_def *
nir_replace_instr(nir_builder *build, nir_alu_instr *instr,
struct hash_table *range_ht,
struct util_dynarray *states,
const nir_algebraic_table *table,
const nir_search_expression *search,
const nir_search_value *replace,
nir_instr_worklist *algebraic_worklist)
nir_instr_worklist *algebraic_worklist,
struct exec_list *dead_instrs)
{
uint8_t swizzle[NIR_MAX_VEC_COMPONENTS] = { 0 };
@@ -803,7 +804,10 @@ nir_replace_instr(nir_builder *build, nir_alu_instr *instr,
* that the instr may be in the worklist still, so we can't free it
* directly.
*/
assert(instr->instr.pass_flags == 0);
instr->instr.pass_flags = 1;
nir_instr_remove(&instr->instr);
exec_list_push_tail(dead_instrs, &instr->instr.node);
return ssa_val;
}
@@ -865,7 +869,8 @@ nir_algebraic_instr(nir_builder *build, nir_instr *instr,
const bool *condition_flags,
const nir_algebraic_table *table,
struct util_dynarray *states,
nir_instr_worklist *worklist)
nir_instr_worklist *worklist,
struct exec_list *dead_instrs)
{
if (instr->type != nir_instr_type_alu)
@@ -891,7 +896,7 @@ nir_algebraic_instr(nir_builder *build, nir_instr *instr,
!(table->values[xform->search].expression.inexact && ignore_inexact) &&
nir_replace_instr(build, alu, range_ht, states, table,
&table->values[xform->search].expression,
&table->values[xform->replace].value, worklist)) {
&table->values[xform->replace].value, worklist, dead_instrs)) {
_mesa_hash_table_clear(range_ht, NULL);
return true;
}
@@ -938,25 +943,31 @@ nir_algebraic_impl(nir_function_impl *impl,
*/
nir_foreach_block_reverse(block, impl) {
nir_foreach_instr_reverse(instr, block) {
instr->pass_flags = 0;
if (instr->type == nir_instr_type_alu)
nir_instr_worklist_push_tail(worklist, instr);
}
}
struct exec_list dead_instrs;
exec_list_make_empty(&dead_instrs);
nir_instr *instr;
while ((instr = nir_instr_worklist_pop_head(worklist))) {
/* The worklist can have an instr pushed to it multiple times if it was
* the src of multiple instrs that also got optimized, so make sure that
* we don't try to re-optimize an instr we already handled.
*/
if (exec_node_is_tail_sentinel(&instr->node))
if (instr->pass_flags)
continue;
progress |= nir_algebraic_instr(&build, instr,
range_ht, condition_flags,
table, &states, worklist);
table, &states, worklist, &dead_instrs);
}
nir_instr_free_list(&dead_instrs);
nir_instr_worklist_destroy(worklist);
ralloc_free(range_ht);
util_dynarray_fini(&states);