On Sat, Dec 26, 2015 at 2:09 PM, Jason Ekstrand <ja...@jlekstrand.net> wrote: > This commit adds a new NIR pass that lowers all function calls away by > inlining the functions. > --- > > There are still two things missing here: > > 1) We really shouldn't do the inline recursively. We should keep a > hash-table of inlined versions or something.
I don't think we need anything so complicated. We're collapsing the DAG of functions, so we just need a simple DFS: we should inline the callees before inlining the caller. We could keep a record of the already-inlined functions, but if we visit an already-inlined function we wouldn't do anything so it would only save us the cost of walking over that function. > > 2) It doesn't properly handle things like samplers as parameters. Since > those can only be "in" parameters, I had thought about treating the > variable as a "proxy" and going through and rewriting all of the derefs > that use it. We could do the same thing for regular parameters when a > shadow isn't needed. > > Still, I thought it was worth sending out because it does work for most > cases. > > src/glsl/Makefile.sources | 1 + > src/glsl/nir/nir.h | 3 + > src/glsl/nir/nir_inline_functions.c | 138 > ++++++++++++++++++++++++++++++++++++ > 3 files changed, 142 insertions(+) > create mode 100644 src/glsl/nir/nir_inline_functions.c > > diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources > index fa3868c..c271afd 100644 > --- a/src/glsl/Makefile.sources > +++ b/src/glsl/Makefile.sources > @@ -35,6 +35,7 @@ NIR_FILES = \ > nir/nir_dominance.c \ > nir/nir_from_ssa.c \ > nir/nir_gs_count_vertices.c \ > + nir/nir_inline_functions.c \ > nir/nir_intrinsics.c \ > nir/nir_intrinsics.h \ > nir/nir_instr_set.c \ > diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h > index 2e29617..437f63a 100644 > --- a/src/glsl/nir/nir.h > +++ b/src/glsl/nir/nir.h > @@ -1938,6 +1938,9 @@ bool nir_split_var_copies(nir_shader *shader); > bool nir_lower_returns_impl(nir_function_impl *impl); > bool nir_lower_returns(nir_shader *shader); > > +bool nir_inline_functions_impl(nir_function_impl *impl); > +bool nir_inline_functions(nir_shader *shader); > + > void nir_lower_var_copy_instr(nir_intrinsic_instr *copy, void *mem_ctx); > void nir_lower_var_copies(nir_shader *shader); > > diff --git a/src/glsl/nir/nir_inline_functions.c > b/src/glsl/nir/nir_inline_functions.c > new file mode 100644 > index 0000000..e7e17ca > --- /dev/null > +++ b/src/glsl/nir/nir_inline_functions.c > @@ -0,0 +1,138 @@ > +/* > + * Copyright © 2015 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > DEALINGS > + * IN THE SOFTWARE. > + */ > + > +#include "nir.h" > +#include "nir_builder.h" > +#include "nir_control_flow.h" > + > +struct inline_functions_state { > + nir_function_impl *impl; > + nir_builder builder; > + bool progress; > +}; > + > +static bool > +inline_functions_block(nir_block *block, void *void_state) > +{ > + struct inline_functions_state *state = void_state; > + > + nir_builder *b = &state->builder; > + > + /* 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 > + * stashes the next thing in the iteration. That next thing will > + * properly get moved to the next block when it gets split, and we > + * continue iterating there. > + */ > + nir_foreach_instr_safe(block, instr) { > + if (instr->type != nir_instr_type_call) > + continue; > + > + state->progress = true; > + > + nir_call_instr *call = nir_instr_as_call(instr); > + assert(call->callee->impl); > + > + nir_function_impl *callee_copy = > + nir_function_impl_clone(call->callee->impl); > + > + exec_list_append(&state->impl->locals, &callee_copy->locals); > + exec_list_append(&state->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); > + for (unsigned i = 0; i < callee_copy->num_params; i++) { > + /* 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, > + callee_copy->params[i]), > + call->params[i]); > + } > + > + /* 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++) { > + /* Only out or inout parameters */ > + if (call->callee->params[i].param_type == nir_parameter_in) > + continue; > + > + nir_copy_deref_var(b, call->params[i], > + nir_deref_var_create(b->shader, > + callee_copy->params[i])); > + } > + if (!glsl_type_is_void(call->callee->return_type)) { > + 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; > +} > + > +bool > +nir_inline_functions_impl(nir_function_impl *impl) > +{ > + struct inline_functions_state state; > + > + state.progress = false; > + state.impl = impl; > + nir_builder_init(&state.builder, impl); > + > + nir_foreach_block(impl, inline_functions_block, &state); > + > + /* SSA and register indices are completely messed up now */ > + nir_index_ssa_defs(impl); > + nir_index_local_regs(impl); > + > + nir_metadata_preserve(impl, nir_metadata_none); > + > + return state.progress; > +} > + > +bool > +nir_inline_functions(nir_shader *shader) > +{ > + bool progress = false; > + > + nir_foreach_function(shader, function) { > + if (function->impl) > + progress = nir_inline_functions_impl(function->impl) || progress; > + } > + > + return progress; > +} > -- > 2.5.0.400.gff86faf > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev