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 <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33452>
This commit is contained in:
Kenneth Graunke 2025-02-06 15:19:54 -08:00 committed by Marge Bot
parent 9af11bf306
commit e65c1473de

View file

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