ir3: emit descriptor prefetch in block dominated by its sources

Descriptor prefetches may be generated for instructions in control flow.
This means we cannot simply emit prefetches at the end of the preamble
because that may not be dominated by all their sources. This commit uses
the helpers introduced by e7ac1094f6 ("ir3: rematerialize preamble defs
in block dominated by sources") to find the correct block to insert
prefetches.

Fixes NIR validation errors in Dying Light 2.

Signed-off-by: Job Noorman <jnoorman@igalia.com>
Fixes: 4e2a0a5ad0 ("ir3: Add descriptor prefetching optimization on a7xx")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36885>
(cherry picked from commit 24cdb0b636)
This commit is contained in:
Job Noorman 2025-08-20 16:48:55 +02:00 committed by Eric Engestrom
parent ac602c97c9
commit b6e59297f7
2 changed files with 44 additions and 11 deletions

View file

@ -6474,7 +6474,7 @@
"description": "ir3: emit descriptor prefetch in block dominated by its sources",
"nominated": true,
"nomination_type": 2,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": "4e2a0a5ad097ef2cbbcf38f7a4f508061a5f9c0c",
"notes": null

View file

@ -391,18 +391,15 @@ struct find_insert_block_state {
};
static bool
find_dominated_src(nir_src *src, void *data)
find_dominated_block(nir_block *block, struct find_insert_block_state *state)
{
struct find_insert_block_state *state = data;
nir_block *src_block = src->ssa->parent_instr->block;
if (!state->insert_block) {
state->insert_block = src_block;
state->insert_block = block;
return true;
} else if (nir_block_dominates(state->insert_block, src_block)) {
state->insert_block = src_block;
} else if (nir_block_dominates(state->insert_block, block)) {
state->insert_block = block;
return true;
} else if (nir_block_dominates(src_block, state->insert_block)) {
} else if (nir_block_dominates(block, state->insert_block)) {
return true;
} else {
state->insert_block = NULL;
@ -410,6 +407,14 @@ find_dominated_src(nir_src *src, void *data)
}
}
static bool
find_dominated_src(nir_src *src, void *data)
{
struct find_insert_block_state *state = data;
nir_block *src_block = src->ssa->parent_instr->block;
return find_dominated_block(src_block, state);
}
/* Find the block where instr can be inserted. This is the block that is
* dominated by all its sources. If instr doesn't have any sources, return dflt.
*/
@ -427,6 +432,22 @@ find_insert_block(nir_instr *instr, nir_block *dflt)
return NULL;
}
static nir_block *
find_insert_block_for_defs(nir_def *defs[], unsigned n)
{
struct find_insert_block_state state = {
.insert_block = NULL,
};
for (unsigned i = 0; i < n; i++) {
if (!find_dominated_block(defs[i]->parent_instr->block, &state)) {
return NULL;
}
}
return state.insert_block;
}
static bool
dominates(const nir_instr *old_instr, const nir_instr *new_instr)
{
@ -598,6 +619,20 @@ static bool
emit_descriptor_prefetch(nir_builder *b, nir_instr *instr, nir_def **descs,
struct prefetch_state *state)
{
nir_block *insert_block = descs[0]->parent_instr->block;
if (descs[1]) {
insert_block = find_insert_block_for_defs(descs, 2);
/* Since the preamble control flow was reconstructed from the original
* one, and the two descriptor defs were used by the same instruction, we
* must be able to find a legal place to insert the prefetch.
*/
assert(insert_block);
}
b->cursor = nir_after_block(insert_block);
if (instr->type == nir_instr_type_tex) {
nir_tex_instr *tex = nir_instr_as_tex(instr);
int sampler_index =
@ -771,8 +806,6 @@ ir3_nir_opt_prefetch_descriptors(nir_shader *nir, struct ir3_shader_variant *v)
preamble_defs);
}
/* ir3_rematerialize_def_for_preamble may have moved the cursor. */
b.cursor = nir_after_impl(preamble);
progress |= emit_descriptor_prefetch(&b, instr, preamble_descs, &state);
if (state.sampler.num_prefetches == MAX_PREFETCHES &&