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; }