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:
Jason Ekstrand 2016-02-08 17:41:36 -08:00
parent b6c00bfb03
commit de6c9c5f2e

View file

@ -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, &param->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, &param->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));