diff options
author | Jason Ekstrand <[email protected]> | 2018-03-22 16:41:18 -0700 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2018-06-22 20:15:58 -0700 |
commit | c11833ab24dcba26de1b0a5805e35a5d6761514e (patch) | |
tree | 724a419f448204358d7dd732d51b724dea80bc17 /src/compiler/nir/nir_inline_functions.c | |
parent | 58799b6a5b3e281365bce91fac2e54903fbd2c41 (diff) |
nir,spirv: Rework function calls
This commit completely reworks function calls in NIR. Instead of having
a set of variables for the parameters and return value, nir_call_instr
now has simply has a number of sources which get mapped to load_param
intrinsics inside the functions. It's up to the client API to build an
ABI on top of that. In SPIR-V, out parameters are handled by passing
the result of a deref through as an SSA value and storing to it.
This virtue of this approach can be seen by how much it allows us to
delete from core NIR. In particular, nir_inline_functions gets halved
and goes from a fairly difficult pass to understand in detail to almost
trivial. It also simplifies spirv_to_nir somewhat because NIR functions
never were a good fit for SPIR-V.
Unfortunately, there is no good way to do this without a mega-commit.
Core NIR and SPIR-V have to be changed at the same time. This also
requires changes to anv and radv because nir_inline_functions couldn't
handle deref instructions before this change and can't work without them
after this change.
Acked-by: Rob Clark <[email protected]>
Acked-by: Bas Nieuwenhuizen <[email protected]>
Acked-by: Dave Airlie <[email protected]>
Reviewed-by: Kenneth Graunke <[email protected]>
Diffstat (limited to 'src/compiler/nir/nir_inline_functions.c')
-rw-r--r-- | src/compiler/nir/nir_inline_functions.c | 193 |
1 files changed, 29 insertions, 164 deletions
diff --git a/src/compiler/nir/nir_inline_functions.c b/src/compiler/nir/nir_inline_functions.c index b91e7bc86da..06c90d93956 100644 --- a/src/compiler/nir/nir_inline_functions.c +++ b/src/compiler/nir/nir_inline_functions.c @@ -24,126 +24,10 @@ #include "nir.h" #include "nir_builder.h" #include "nir_control_flow.h" +#include "nir_vla.h" static bool inline_function_impl(nir_function_impl *impl, struct set *inlined); -static void -convert_deref_to_param_deref(nir_instr *instr, nir_deref_var **deref, - nir_call_instr *call) -{ - /* This isn't a parameter, just return the deref */ - if ((*deref)->var->data.mode != nir_var_param) - return; - - int param_idx = (*deref)->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); - - /* Now we make a new deref by concatenating the deref in the call's - * parameter with the deref we were given. - */ - nir_deref_var *new_deref = nir_deref_var_clone(call_deref, instr); - nir_deref *new_tail = nir_deref_tail(&new_deref->deref); - new_tail->child = (*deref)->deref.child; - ralloc_steal(new_tail, new_tail->child); - *deref = new_deref; -} - -static void -rewrite_param_derefs(nir_instr *instr, nir_call_instr *call) -{ - switch (instr->type) { - case nir_instr_type_intrinsic: { - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - for (unsigned i = 0; - i < nir_intrinsic_infos[intrin->intrinsic].num_variables; i++) { - convert_deref_to_param_deref(instr, &intrin->variables[i], call); - } - break; - } - - case nir_instr_type_tex: { - nir_tex_instr *tex = nir_instr_as_tex(instr); - if (tex->texture) - convert_deref_to_param_deref(&tex->instr, &tex->texture, call); - if (tex->sampler) - convert_deref_to_param_deref(&tex->instr, &tex->sampler, call); - break; - } - - default: - break; /* Nothing else has derefs */ - } -} - -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, nir_function_impl *impl) -{ - nir_foreach_instr(instr, block) { - 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, nir_builder *b, struct set *inlined) @@ -171,42 +55,43 @@ inline_functions_block(nir_block *block, nir_builder *b, 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); - /* 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. + /* Rewrite all of the uses of the callee's parameters to use the call + * instructions sources. In order to ensure that the "load" happens + * here and not later (for register sources), we make sure to convert it + * to an SSA value first. */ - - /* Figure out when we need to lower to a shadow local */ - nir_foreach_block(block, callee_copy) { - lower_params_to_locals_block(block, callee_copy); - } - - for (unsigned i = 0; i < callee_copy->num_params; i++) { - nir_variable *param = callee_copy->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]); - } + const unsigned num_params = call->num_params; + NIR_VLA(nir_ssa_def *, params, num_params); + for (unsigned i = 0; i < num_params; i++) { + params[i] = nir_ssa_for_src(b, call->params[i], + call->callee->params[i].num_components); } nir_foreach_block(block, callee_copy) { - nir_foreach_instr(instr, block) - rewrite_param_derefs(instr, call); + nir_foreach_instr_safe(instr, block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *load = nir_instr_as_intrinsic(instr); + if (load->intrinsic != nir_intrinsic_load_param) + continue; + + unsigned param_idx = nir_intrinsic_param_idx(load); + assert(param_idx < num_params); + assert(load->dest.is_ssa); + nir_ssa_def_rewrite_uses(&load->dest.ssa, + nir_src_for_ssa(params[param_idx])); + + /* Remove any left-over load_param intrinsics because they're soon + * to be in another function and therefore no longer valid. + */ + nir_instr_remove(&load->instr); + } } /* Pluck the body out of the function and place it here */ @@ -214,26 +99,6 @@ inline_functions_block(nir_block *block, nir_builder *b, nir_cf_list_extract(&body, &callee_copy->body); nir_cf_reinsert(&body, b->cursor); - b->cursor = nir_before_instr(&call->instr); - - /* 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++) { - nir_variable *param = 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) && - 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)); - } - nir_instr_remove(&call->instr); } |