From: Rob Clark <robcl...@freedesktop.org> Prior to running nir_lower_io_types (next patch), we need to eliminate indirect load_input/store_output. This can either be done via nir_lower_indirect_derefs (for hw which does not support indirect var access) or this pass (for hw which does). --- src/compiler/Makefile.sources | 1 + src/compiler/nir/nir.h | 2 + src/compiler/nir/nir_lower_indirect_io.c | 151 +++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 src/compiler/nir/nir_lower_indirect_io.c
diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index 99fd9fa..b1e3886 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -194,6 +194,7 @@ NIR_FILES = \ nir/nir_lower_locals_to_regs.c \ nir/nir_lower_idiv.c \ nir/nir_lower_indirect_derefs.c \ + nir/nir_lower_indirect_io.c \ nir/nir_lower_io.c \ nir/nir_lower_outputs_to_temporaries.c \ nir/nir_lower_passthrough_edgeflags.c \ diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index ed20dcd..297ca3b 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -2149,6 +2149,8 @@ void nir_lower_io(nir_shader *shader, nir_src *nir_get_io_offset_src(nir_intrinsic_instr *instr); nir_src *nir_get_io_vertex_index_src(nir_intrinsic_instr *instr); +void nir_lower_indirect_io(nir_shader *shader); + void nir_lower_vars_to_ssa(nir_shader *shader); bool nir_remove_dead_variables(nir_shader *shader); diff --git a/src/compiler/nir/nir_lower_indirect_io.c b/src/compiler/nir/nir_lower_indirect_io.c new file mode 100644 index 0000000..e24c3a5 --- /dev/null +++ b/src/compiler/nir/nir_lower_indirect_io.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2016 Red Hat + * + * 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" + +/* Lower indirect load_input/store_output to a direct copy to a local which + * is indirectly accessed. Use this (instead of nir_lower_indirect_derefs) + * if your hardware supports native indirect access, before running + * nir_lower_io_types. This ensures that all inputs/outputs can be lowered + * to non-struct/array/mat types regardless of indirect access. + * + * NOTE: you'll need a split_var_copies pass somewhere after this and before + * lower_var_copies. + */ + + +struct lower_indirect_io_state { + nir_shader *shader; + nir_function_impl *impl; +}; + +static bool +is_indirect(nir_deref *tail) +{ + while (tail != NULL) { + if (tail->deref_type == nir_deref_type_array) { + nir_deref_array *deref_array = nir_deref_as_array(tail); + if (deref_array->deref_array_type == nir_deref_array_type_indirect) + return true; + } + tail = tail->child; + } + return false; +} + +static bool +lower_indirect_io_block(nir_block *block, void *void_state) +{ + struct lower_indirect_io_state *state = void_state; + nir_cursor cursor; + + nir_foreach_instr_safe(block, instr) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + + if ((intr->intrinsic != nir_intrinsic_load_var) && + (intr->intrinsic != nir_intrinsic_store_var)) + continue; + + nir_variable *var = intr->variables[0]->var; + nir_variable_mode mode = var->data.mode; + + if ((mode != nir_var_shader_in) && (mode != nir_var_shader_out)) + continue; + + if (!is_indirect(&intr->variables[0]->deref)) + continue; + + /* for either input or output, convert existing var to local (which + * means we don't have to deal with any remaining load_var/store_var + * references to it), and create a new var to replace it as an input/ + * output: + */ + nir_variable *nvar = nir_variable_clone(var, state->shader); + + /* remove existing var from input/output list: */ + exec_node_remove(&var->node); + exec_node_self_link(&var->node); /* no delinit() :-( */ + + /* and add make into a local: */ + var->data.mode = nir_var_local; + var->data.location = 0; + var->data.driver_location = 0; + exec_list_push_tail(&state->impl->locals, &var->node); + + /* rename the (now global) variable to make nir_print's more clear: */ + ralloc_free(var->name); + var->name = ralloc_asprintf(var, "shadow_%s", nvar->name); + + nir_intrinsic_instr *copy = + nir_intrinsic_instr_create(state->shader, nir_intrinsic_copy_var); + + if (mode == nir_var_shader_in) { + /* insert new input plus copy_var at head of shader to copy into + * original var: + */ + exec_list_push_tail(&state->shader->inputs, &nvar->node); + cursor = nir_before_block(nir_start_block(state->impl)); + copy->variables[0] = nir_deref_var_create(copy, var); /* dst */ + copy->variables[1] = nir_deref_var_create(copy, nvar); /* src */ + nir_instr_insert(cursor, ©->instr); + } else if (mode == nir_var_shader_out) { + /* insert new output plus copy_var at tail of shader to copy from + * original var: + */ + exec_list_push_tail(&state->shader->outputs, &nvar->node); + cursor = nir_after_block(state->impl->end_block); + copy->variables[0] = nir_deref_var_create(copy, nvar); /* dst */ + copy->variables[1] = nir_deref_var_create(copy, var); /* src */ + nir_instr_insert(cursor, ©->instr); + } + } + + return true; +} + +static void +lower_indirect_io_impl(nir_function_impl *impl) +{ + struct lower_indirect_io_state state; + + state.shader = impl->function->shader; + state.impl = impl; + + nir_foreach_block(impl, lower_indirect_io_block, &state); + + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); +} + +void +nir_lower_indirect_io(nir_shader *shader) +{ + nir_foreach_function(shader, function) { + if (function->impl) + lower_indirect_io_impl(function->impl); + } +} -- 2.5.5 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev