mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 11:18:08 +02:00
nir: Perform 'weak' global value numbering in all GCM passes
Full global value numbering (GVN) can be pretty aggressive, moving values far away from their original locations, even out of loops, and can extend their live ranges a lot. So we've left it disabled. This patch introduces a weaker form of GVN: we only allow coalescing identical values when they appear on either side of the same if/else construct. For now, we also only allow ALU instructions. This allows nir_opt_gcm to clean up identical instructions appearing on both sides of if/then/else control flow. But it avoids aggressively combining every other occurrence of a value in the program. This can still have surprisingly large cascading effects, as simple constructs are cleaned up, leading to more opportunities to do the same clean up, up a chain of nested ifs. It also enables greater use of the select peephole as ifs are cleaned up. shader-db and fossil-db results show a reduction in spills/fills on Icelake, so it doesn't seem to be hurting register pressure. Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19823>
This commit is contained in:
parent
e930bff19e
commit
d5d03a7273
1 changed files with 32 additions and 9 deletions
|
|
@ -791,6 +791,20 @@ gcm_place_instr(nir_instr *instr, struct gcm_state *state)
|
|||
block_info->last_instr = instr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are ALU instructions a and b both contained in the same if/else block?
|
||||
*/
|
||||
static bool
|
||||
weak_gvn(const nir_instr *a, const nir_instr *b)
|
||||
{
|
||||
if (a->type != nir_instr_type_alu)
|
||||
return false;
|
||||
|
||||
const struct nir_cf_node *ap = a->block->cf_node.parent;
|
||||
const struct nir_cf_node *bp = b->block->cf_node.parent;
|
||||
return ap && ap == bp && ap->type == nir_cf_node_if;
|
||||
}
|
||||
|
||||
static bool
|
||||
opt_gcm_impl(nir_shader *shader, nir_function_impl *impl, bool value_number)
|
||||
{
|
||||
|
|
@ -820,17 +834,26 @@ opt_gcm_impl(nir_shader *shader, nir_function_impl *impl, bool value_number)
|
|||
state.instr_infos =
|
||||
rzalloc_array(NULL, struct gcm_instr_info, state.num_instrs);
|
||||
|
||||
if (value_number) {
|
||||
struct set *gvn_set = nir_instr_set_create(NULL);
|
||||
foreach_list_typed_safe(nir_instr, instr, node, &state.instrs) {
|
||||
if (instr->pass_flags & GCM_INSTR_PINNED)
|
||||
continue;
|
||||
/* Perform (at least some) Global Value Numbering (GVN).
|
||||
*
|
||||
* We perform full GVN when `value_number' is true. This can be too
|
||||
* aggressive, moving values far away and extending their live ranges,
|
||||
* so we don't always want to do it.
|
||||
*
|
||||
* Otherwise, we perform 'weaker' GVN: if identical ALU instructions appear
|
||||
* on both sides of the same if/else block, we allow them to be moved.
|
||||
* This cleans up a lot of mess without being -too- aggressive.
|
||||
*/
|
||||
struct set *gvn_set = nir_instr_set_create(NULL);
|
||||
foreach_list_typed_safe(nir_instr, instr, node, &state.instrs) {
|
||||
if (instr->pass_flags & GCM_INSTR_PINNED)
|
||||
continue;
|
||||
|
||||
if (nir_instr_set_add_or_rewrite(gvn_set, instr, NULL))
|
||||
state.progress = true;
|
||||
}
|
||||
nir_instr_set_destroy(gvn_set);
|
||||
if (nir_instr_set_add_or_rewrite(gvn_set, instr,
|
||||
value_number ? NULL : weak_gvn))
|
||||
state.progress = true;
|
||||
}
|
||||
nir_instr_set_destroy(gvn_set);
|
||||
|
||||
foreach_list_typed(nir_instr, instr, node, &state.instrs)
|
||||
gcm_schedule_early_instr(instr, &state);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue