mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 16:08:04 +02:00
nir/inline_functions: Don't shadown variables when it isn't needed
Previously, in order to get things working, we just always shadowed variables. Now, we rewrite derefs whenever it's safe to do so and only shadow if we have an in or out variable that we write or read to respectively.
This commit is contained in:
parent
b6c00bfb03
commit
de6c9c5f2e
1 changed files with 131 additions and 23 deletions
|
|
@ -33,6 +33,106 @@ struct inline_functions_state {
|
|||
|
||||
static bool inline_function_impl(nir_function_impl *impl, struct set *inlined);
|
||||
|
||||
static bool
|
||||
rewrite_param_derefs_block(nir_block *block, void *void_state)
|
||||
{
|
||||
nir_call_instr *call = void_state;
|
||||
|
||||
nir_foreach_instr_safe(block, instr) {
|
||||
if (instr->type != nir_instr_type_intrinsic)
|
||||
continue;
|
||||
|
||||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
|
||||
for (unsigned i = 0;
|
||||
i < nir_intrinsic_infos[intrin->intrinsic].num_variables; i++) {
|
||||
if (intrin->variables[i]->var->data.mode != nir_var_param)
|
||||
continue;
|
||||
|
||||
int param_idx = intrin->variables[i]->var->data.location;
|
||||
|
||||
nir_deref_var *call_deref;
|
||||
if (param_idx >= 0) {
|
||||
assert(param_idx < call->callee->num_params);
|
||||
call_deref = call->params[param_idx];
|
||||
} else {
|
||||
call_deref = call->return_deref;
|
||||
}
|
||||
assert(call_deref);
|
||||
|
||||
nir_deref_var *new_deref = nir_deref_as_var(nir_copy_deref(intrin, &call_deref->deref));
|
||||
nir_deref *new_tail = nir_deref_tail(&new_deref->deref);
|
||||
new_tail->child = intrin->variables[i]->deref.child;
|
||||
ralloc_steal(new_tail, new_tail->child);
|
||||
intrin->variables[i] = new_deref;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
lower_param_to_local(nir_variable *param, nir_function_impl *impl, bool write)
|
||||
{
|
||||
if (param->data.mode != nir_var_param)
|
||||
return;
|
||||
|
||||
nir_parameter_type param_type;
|
||||
if (param->data.location >= 0) {
|
||||
assert(param->data.location < impl->num_params);
|
||||
param_type = impl->function->params[param->data.location].param_type;
|
||||
} else {
|
||||
/* Return variable */
|
||||
param_type = nir_parameter_out;
|
||||
}
|
||||
|
||||
if ((write && param_type == nir_parameter_in) ||
|
||||
(!write && param_type == nir_parameter_out)) {
|
||||
/* In this case, we need a shadow copy. Turn it into a local */
|
||||
param->data.mode = nir_var_local;
|
||||
exec_list_push_tail(&impl->locals, ¶m->node);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
lower_params_to_locals_block(nir_block *block, void *void_state)
|
||||
{
|
||||
nir_function_impl *impl = void_state;
|
||||
|
||||
nir_foreach_instr_safe(block, instr) {
|
||||
if (instr->type != nir_instr_type_intrinsic)
|
||||
continue;
|
||||
|
||||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_store_var:
|
||||
lower_param_to_local(intrin->variables[0]->var, impl, true);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_copy_var:
|
||||
lower_param_to_local(intrin->variables[0]->var, impl, true);
|
||||
lower_param_to_local(intrin->variables[1]->var, impl, false);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_load_var:
|
||||
/* All other intrinsics which access variables (image_load_store)
|
||||
* do so in a read-only fasion.
|
||||
*/
|
||||
for (unsigned i = 0;
|
||||
i < nir_intrinsic_infos[intrin->intrinsic].num_variables; i++) {
|
||||
lower_param_to_local(intrin->variables[i]->var, impl, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
inline_functions_block(nir_block *block, void *void_state)
|
||||
{
|
||||
|
|
@ -60,29 +160,40 @@ inline_functions_block(nir_block *block, void *void_state)
|
|||
|
||||
nir_function_impl *callee_copy =
|
||||
nir_function_impl_clone(call->callee->impl);
|
||||
callee_copy->function = call->callee;
|
||||
|
||||
/* Add copies of all in parameters */
|
||||
assert(call->num_params == callee_copy->num_params);
|
||||
|
||||
exec_list_append(&b->impl->locals, &callee_copy->locals);
|
||||
exec_list_append(&b->impl->registers, &callee_copy->registers);
|
||||
|
||||
b->cursor = nir_before_instr(&call->instr);
|
||||
|
||||
/* Add copies of all in parameters */
|
||||
assert(call->num_params == callee_copy->num_params);
|
||||
/* We now need to tie the two functions together using the
|
||||
* parameters. There are two ways we do this: One is to turn the
|
||||
* parameter into a local variable and do a shadow-copy. The other
|
||||
* is to treat the parameter as a "proxy" and rewrite derefs to use
|
||||
* the actual variable that comes from the call instruction. We
|
||||
* implement both schemes. The first is needed in the case where we
|
||||
* have an in parameter that we write or similar. The second case is
|
||||
* needed for handling things such as images and uniforms properly.
|
||||
*/
|
||||
|
||||
/* Figure out when we need to lower to a shadow local */
|
||||
nir_foreach_block(callee_copy, lower_params_to_locals_block, callee_copy);
|
||||
for (unsigned i = 0; i < callee_copy->num_params; i++) {
|
||||
nir_variable *param = callee_copy->params[i];
|
||||
|
||||
/* Turn it into a local variable */
|
||||
param->data.mode = nir_var_local;
|
||||
exec_list_push_head(&b->impl->locals, ¶m->node);
|
||||
|
||||
/* Only in or inout parameters */
|
||||
if (call->callee->params[i].param_type == nir_parameter_out)
|
||||
continue;
|
||||
|
||||
nir_copy_deref_var(b, nir_deref_var_create(b->shader, param),
|
||||
call->params[i]);
|
||||
if (param->data.mode == nir_var_local &&
|
||||
call->callee->params[i].param_type != nir_parameter_out) {
|
||||
nir_copy_deref_var(b, nir_deref_var_create(b->shader, param),
|
||||
call->params[i]);
|
||||
}
|
||||
}
|
||||
|
||||
nir_foreach_block(callee_copy, rewrite_param_derefs_block, call);
|
||||
|
||||
/* Pluck the body out of the function and place it here */
|
||||
nir_cf_list body;
|
||||
nir_cf_list_extract(&body, &callee_copy->body);
|
||||
|
|
@ -93,19 +204,16 @@ inline_functions_block(nir_block *block, void *void_state)
|
|||
/* Add copies of all out parameters and the return */
|
||||
assert(call->num_params == callee_copy->num_params);
|
||||
for (unsigned i = 0; i < callee_copy->num_params; i++) {
|
||||
/* Only out or inout parameters */
|
||||
if (call->callee->params[i].param_type == nir_parameter_in)
|
||||
continue;
|
||||
nir_variable *param = callee_copy->params[i];
|
||||
|
||||
nir_copy_deref_var(b, call->params[i],
|
||||
nir_deref_var_create(b->shader,
|
||||
callee_copy->params[i]));
|
||||
if (param->data.mode == nir_var_local &&
|
||||
call->callee->params[i].param_type != nir_parameter_in) {
|
||||
nir_copy_deref_var(b, call->params[i],
|
||||
nir_deref_var_create(b->shader, param));
|
||||
}
|
||||
}
|
||||
if (!glsl_type_is_void(call->callee->return_type)) {
|
||||
/* Turn it into a local variable */
|
||||
callee_copy->return_var->data.mode = nir_var_local;
|
||||
exec_list_push_head(&b->impl->locals, &callee_copy->return_var->node);
|
||||
|
||||
if (!glsl_type_is_void(call->callee->return_type) &&
|
||||
callee_copy->return_var->data.mode == nir_var_local) {
|
||||
nir_copy_deref_var(b, call->return_deref,
|
||||
nir_deref_var_create(b->shader,
|
||||
callee_copy->return_var));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue