From e65c1473ded8e278b2253b7939af7a2fbfc72714 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 6 Feb 2025 15:19:54 -0800 Subject: [PATCH] nir: Eliminate dead writes to shared memory at the end of the program If the program writes to shared variables after all reads, in the last block of the program, no one will ever read the value we write. We can just eliminate these dead writes. (Thanks to Faith Ekstrand for improving the ends_program() conditions.) Reviewed-by: Faith Ekstrand Part-of: --- src/compiler/nir/nir_opt_dead_write_vars.c | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/compiler/nir/nir_opt_dead_write_vars.c b/src/compiler/nir/nir_opt_dead_write_vars.c index 5f8f6373cac..d86485c6eb5 100644 --- a/src/compiler/nir/nir_opt_dead_write_vars.c +++ b/src/compiler/nir/nir_opt_dead_write_vars.c @@ -108,6 +108,26 @@ update_unused_writes(struct util_dynarray *unused_writes, return progress; } +static bool +ends_program(nir_block *block) +{ + /* Avoid back-edges */ + if (block->cf_node.parent->type == nir_cf_node_loop) + return false; + + if (block->successors[0] == NULL) { + /* This is the end block */ + assert(block->successors[1] == NULL); + return true; + } + + if (block->successors[1] != NULL) + return false; + + return exec_list_is_empty(&block->successors[0]->instr_list) && + ends_program(block->successors[0]); +} + static bool remove_dead_write_vars_local(void *mem_ctx, nir_shader *shader, nir_block *block) { @@ -220,7 +240,19 @@ remove_dead_write_vars_local(void *mem_ctx, nir_shader *shader, nir_block *block /* All unused writes at the end of the block are kept, since we can't be * sure they'll be overwritten or not with local analysis only. + * + * However, if the next block is the end of the program, then we can + * eliminate any shared writes, since no one will ever read it again. */ + if (ends_program(block)) { + util_dynarray_foreach_reverse(&unused_writes, struct write_entry, entry) { + if (nir_deref_mode_may_be(entry->dst, nir_var_mem_shared) && + nir_deref_mode_is(entry->dst, nir_var_mem_shared)) { + nir_instr_remove(&entry->intrin->instr); + progress = true; + } + } + } return progress; }