nir/lower_scratch: Ensure we don't lower vars with unsupported usage.

Need to avoid lowering temps when they are used by other instructions,
like the rt instructions (some of the shader call parameters get
converted to temp variables and we will lower them later with
the explicit io lowering pass as we need to guarantee they will
end up in scratch).

Reviewed-by: Rhys Perry <pendingchaos02@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12162>
This commit is contained in:
Bas Nieuwenhuizen 2021-07-26 15:23:29 +02:00 committed by Marge Bot
parent 04bd2a1245
commit fa6cd6e00d
1 changed files with 73 additions and 7 deletions

View File

@ -75,12 +75,34 @@ lower_load_store(nir_builder *b,
nir_deref_instr_remove_if_unused(deref);
}
static bool only_used_for_load_store(nir_deref_instr *deref)
{
nir_foreach_use(src, &deref->dest.ssa) {
if (!src->parent_instr)
return false;
if (src->parent_instr->type == nir_instr_type_deref) {
if (!only_used_for_load_store(nir_instr_as_deref(src->parent_instr)))
return false;
} else if (src->parent_instr->type != nir_instr_type_intrinsic) {
return false;
} else {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(src->parent_instr);
if (intrin->intrinsic != nir_intrinsic_load_deref &&
intrin->intrinsic != nir_intrinsic_store_deref)
return false;
}
}
return true;
}
bool
nir_lower_vars_to_scratch(nir_shader *shader,
nir_variable_mode modes,
int size_threshold,
glsl_type_size_align_func size_align)
{
struct set *set = _mesa_pointer_set_create(NULL);
/* First, we walk the instructions and flag any variables we want to lower
* by removing them from their respective list and setting the mode to 0.
*/
@ -103,6 +125,8 @@ nir_lower_vars_to_scratch(nir_shader *shader,
continue;
nir_variable *var = nir_deref_instr_get_variable(deref);
if (!var)
continue;
/* We set var->mode to 0 to indicate that a variable will be moved
* to scratch. Don't assign a scratch location twice.
@ -115,17 +139,49 @@ nir_lower_vars_to_scratch(nir_shader *shader,
if (var_size <= size_threshold)
continue;
/* Remove it from its list */
exec_node_remove(&var->node);
/* Invalid mode used to flag "moving to scratch" */
var->data.mode = 0;
var->data.location = ALIGN_POT(shader->scratch_size, var_align);
shader->scratch_size = var->data.location + var_size;
_mesa_set_add(set, var);
}
}
}
if (set->entries == 0) {
_mesa_set_destroy(set, NULL);
return false;
}
nir_foreach_function(function, shader) {
nir_foreach_block(block, function->impl) {
nir_foreach_instr(instr, block) {
if (instr->type != nir_instr_type_deref)
continue;
nir_deref_instr *deref = nir_instr_as_deref(instr);
if (deref->deref_type != nir_deref_type_var)
continue;
struct set_entry *entry = _mesa_set_search(set, deref->var);
if (!entry)
continue;
if (!only_used_for_load_store(deref))
_mesa_set_remove(set, entry);
}
}
}
set_foreach(set, entry) {
nir_variable* var = (void*)entry->key;
/* Remove it from its list */
exec_node_remove(&var->node);
/* Invalid mode used to flag "moving to scratch" */
var->data.mode = 0;
/* We don't allocate space here as iteration in this loop is
* non-deterministic due to the nir_variable pointers. */
var->data.location = INT_MAX;
}
bool progress = false;
nir_foreach_function(function, shader) {
if (!function->impl)
@ -150,6 +206,14 @@ nir_lower_vars_to_scratch(nir_shader *shader,
if (!var || var->data.mode)
continue;
if (var->data.location == INT_MAX) {
unsigned var_size, var_align;
size_align(var->type, &var_size, &var_align);
var->data.location = ALIGN_POT(shader->scratch_size, var_align);
shader->scratch_size = var->data.location + var_size;
}
lower_load_store(&build, intrin, size_align);
impl_progress = true;
}
@ -164,5 +228,7 @@ nir_lower_vars_to_scratch(nir_shader *shader,
}
}
_mesa_set_destroy(set, NULL);
return progress;
}