X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fnir%2Fnir_inline_functions.c;h=06c90d939564860ca44ccbcd7f64a9efcfe33d0b;hb=68ae66542a1537bc0a533cae870b2523523d8b6e;hp=4a08dcc96e0cab90df10a8c7b1be2fd0e66683ef;hpb=f710f3ca377a4583b1fc5081cc28ee1d4aba71cb;p=mesa.git diff --git a/src/compiler/nir/nir_inline_functions.c b/src/compiler/nir/nir_inline_functions.c index 4a08dcc96e0..06c90d93956 100644 --- a/src/compiler/nir/nir_inline_functions.c +++ b/src/compiler/nir/nir_inline_functions.c @@ -24,122 +24,15 @@ #include "nir.h" #include "nir_builder.h" #include "nir_control_flow.h" - -struct inline_functions_state { - struct set *inlined; - nir_builder builder; - bool progress; -}; +#include "nir_vla.h" 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) +inline_functions_block(nir_block *block, nir_builder *b, + struct set *inlined) { - struct inline_functions_state *state = void_state; - - nir_builder *b = &state->builder; - + bool progress = false; /* This is tricky. We're iterating over instructions in a block but, as * we go, the block and its instruction list are being split into * pieces. However, this *should* be safe since foreach_safe always @@ -147,82 +40,69 @@ inline_functions_block(nir_block *block, void *void_state) * properly get moved to the next block when it gets split, and we * continue iterating there. */ - nir_foreach_instr_safe(block, instr) { + nir_foreach_instr_safe(instr, block) { if (instr->type != nir_instr_type_call) continue; - state->progress = true; + progress = true; nir_call_instr *call = nir_instr_as_call(instr); assert(call->callee->impl); - inline_function_impl(call->callee->impl, state->inlined); + inline_function_impl(call->callee->impl, inlined); 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); - /* 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. */ + 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); + } - /* 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]; - - 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(block, callee_copy) { + 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); } } - 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); 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); } - return true; + return progress; } static bool @@ -231,15 +111,15 @@ inline_function_impl(nir_function_impl *impl, struct set *inlined) if (_mesa_set_search(inlined, impl)) return false; /* Already inlined */ - struct inline_functions_state state; - - state.inlined = inlined; - state.progress = false; - nir_builder_init(&state.builder, impl); + nir_builder b; + nir_builder_init(&b, impl); - nir_foreach_block(impl, inline_functions_block, &state); + bool progress = false; + nir_foreach_block_safe(block, impl) { + progress |= inline_functions_block(block, &b, inlined); + } - if (state.progress) { + if (progress) { /* SSA and register indices are completely messed up now */ nir_index_ssa_defs(impl); nir_index_local_regs(impl); @@ -249,7 +129,7 @@ inline_function_impl(nir_function_impl *impl, struct set *inlined) _mesa_set_add(inlined, impl); - return state.progress; + return progress; } bool @@ -259,7 +139,7 @@ nir_inline_functions(nir_shader *shader) _mesa_key_pointer_equal); bool progress = false; - nir_foreach_function(shader, function) { + nir_foreach_function(function, shader) { if (function->impl) progress = inline_function_impl(function->impl, inlined) || progress; }