[Mesa-dev] [PATCH 093/133] nir: Add a pass for lowering input/output loads/stores

Connor Abbott cwabbott0 at gmail.com
Sun Jan 4 20:29:11 PST 2015


I'd also like to rename or at least note that this is a scalar-only thing
for now... otherwise,

Reviewed-by: Connor Abbott <cwabbott0 at gmail.com>

On Tue, Dec 16, 2014 at 1:11 AM, Jason Ekstrand <jason at jlekstrand.net>
wrote:

> ---
>  src/glsl/Makefile.sources   |   1 +
>  src/glsl/nir/nir.h          |   2 +
>  src/glsl/nir/nir_lower_io.c | 388
> ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 391 insertions(+)
>  create mode 100644 src/glsl/nir/nir_lower_io.c
>
> diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
> index 6230f49..53c3e98 100644
> --- a/src/glsl/Makefile.sources
> +++ b/src/glsl/Makefile.sources
> @@ -23,6 +23,7 @@ NIR_FILES = \
>         $(GLSL_SRCDIR)/nir/nir_live_variables.c \
>         $(GLSL_SRCDIR)/nir/nir_lower_atomics.c \
>         $(GLSL_SRCDIR)/nir/nir_lower_locals_to_regs.c \
> +       $(GLSL_SRCDIR)/nir/nir_lower_io.c \
>         $(GLSL_SRCDIR)/nir/nir_lower_samplers.cpp \
>         $(GLSL_SRCDIR)/nir/nir_lower_system_values.c \
>         $(GLSL_SRCDIR)/nir/nir_lower_variables.c \
> diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h
> index 7d7aec7..ec9ce07 100644
> --- a/src/glsl/nir/nir.h
> +++ b/src/glsl/nir/nir.h
> @@ -1360,6 +1360,8 @@ void nir_split_var_copies(nir_shader *shader);
>
>  void nir_lower_locals_to_regs(nir_shader *shader);
>
> +void nir_lower_io(nir_shader *shader);
> +
>  void nir_lower_variables(nir_shader *shader);
>
>  void nir_lower_variables_scalar(nir_shader *shader, bool lower_globals,
> diff --git a/src/glsl/nir/nir_lower_io.c b/src/glsl/nir/nir_lower_io.c
> new file mode 100644
> index 0000000..a3b8186
> --- /dev/null
> +++ b/src/glsl/nir/nir_lower_io.c
> @@ -0,0 +1,388 @@
> +/*
> + * Copyright © 2014 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.
> + *
> + * Authors:
> + *    Connor Abbott (cwabbott0 at gmail.com)
> + *    Jason Ekstrand (jason at jlekstrand.net)
> + *
> + */
> +
> +/*
> + * This lowering pass converts references to input/output variables with
> + * loads/stores to actual input/output intrinsics.
> + */
> +
> +#include "nir.h"
> +
> +struct lower_io_state {
> +   void *mem_ctx;
> +};
> +
> +static unsigned
> +type_size(const struct glsl_type *type)
> +{
> +   unsigned int size, i;
> +
> +   switch (glsl_get_base_type(type)) {
> +   case GLSL_TYPE_UINT:
> +   case GLSL_TYPE_INT:
> +   case GLSL_TYPE_FLOAT:
> +   case GLSL_TYPE_BOOL:
> +      return glsl_get_components(type);
> +   case GLSL_TYPE_ARRAY:
> +      return type_size(glsl_get_array_element(type)) *
> glsl_get_length(type);
> +   case GLSL_TYPE_STRUCT:
> +      size = 0;
> +      for (i = 0; i < glsl_get_length(type); i++) {
> +         size += type_size(glsl_get_struct_field(type, i));
> +      }
> +      return size;
> +   case GLSL_TYPE_SAMPLER:
> +      return 0;
> +   case GLSL_TYPE_ATOMIC_UINT:
> +      return 0;
> +   case GLSL_TYPE_INTERFACE:
> +      return 0;
> +   case GLSL_TYPE_IMAGE:
> +      return 0;
> +   case GLSL_TYPE_VOID:
> +   case GLSL_TYPE_ERROR:
> +      unreachable("not reached");
> +   }
> +
> +   return 0;
> +}
> +
> +static void
> +assign_var_locations(struct hash_table *ht, unsigned *size)
> +{
> +   unsigned location = 0;
> +
> +   struct hash_entry *entry;
> +   hash_table_foreach(ht, entry) {
> +      nir_variable *var = (nir_variable *) entry->data;
> +
> +      /*
> +       * UBO's have their own address spaces, so don't count them towards
> the
> +       * number of global uniforms
> +       */
> +      if (var->data.mode == nir_var_uniform && var->interface_type !=
> NULL)
> +         continue;
> +
> +      var->data.driver_location = location;
> +      location += type_size(var->type);
> +   }
> +
> +   *size = location;
> +}
> +
> +static void
> +assign_var_locations_shader(nir_shader *shader)
> +{
> +   assign_var_locations(shader->inputs, &shader->num_inputs);
> +   assign_var_locations(shader->outputs, &shader->num_outputs);
> +   assign_var_locations(shader->uniforms, &shader->num_uniforms);
> +}
> +
> +static bool
> +deref_has_indirect(nir_deref_var *deref)
> +{
> +   for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) {
> +      if (tail->deref_type == nir_deref_type_array) {
> +         nir_deref_array *arr = nir_deref_as_array(tail);
> +         if (arr->deref_array_type == nir_deref_array_type_indirect)
> +            return true;
> +      }
> +   }
> +
> +   return false;
> +}
> +
> +static unsigned
> +get_io_offset(nir_deref_var *deref, nir_instr *instr, nir_src *indirect,
> +              struct lower_io_state *state)
> +{
> +   bool found_indirect = false;
> +   unsigned base_offset = 0;
> +
> +   nir_deref *tail = &deref->deref;
> +   while (tail->child != NULL) {
> +      const struct glsl_type *parent_type = tail->type;
> +      tail = tail->child;
> +
> +      if (tail->deref_type == nir_deref_type_array) {
> +         nir_deref_array *deref_array = nir_deref_as_array(tail);
> +         unsigned size = type_size(tail->type);
> +
> +         base_offset += size * deref_array->base_offset;
> +
> +         if (deref_array->deref_array_type ==
> nir_deref_array_type_indirect) {
> +            nir_load_const_instr *load_const =
> +               nir_load_const_instr_create(state->mem_ctx);
> +            load_const->num_components = 1;
> +            load_const->value.u[0] = size;
> +            load_const->dest.is_ssa = true;
> +            nir_ssa_def_init(&load_const->instr, &load_const->dest.ssa,
> +                             1, NULL);
> +            nir_instr_insert_before(instr, &load_const->instr);
> +
> +            nir_alu_instr *mul = nir_alu_instr_create(state->mem_ctx,
> +                                                      nir_op_imul);
> +            mul->src[0].src.is_ssa = true;
> +            mul->src[0].src.ssa = &load_const->dest.ssa;
> +            mul->src[1].src = nir_src_copy(deref_array->indirect,
> +                                           state->mem_ctx);
> +            mul->dest.write_mask = 1;
> +            mul->dest.dest.is_ssa = true;
> +            nir_ssa_def_init(&mul->instr, &mul->dest.dest.ssa, 1, NULL);
> +            nir_instr_insert_before(instr, &mul->instr);
> +
> +            if (found_indirect) {
> +               nir_alu_instr *add = nir_alu_instr_create(state->mem_ctx,
> +                                                         nir_op_iadd);
> +               add->src[0].src = *indirect;
> +               add->src[1].src.is_ssa = true;
> +               add->src[1].src.ssa = &mul->dest.dest.ssa;
> +               add->dest.write_mask = 1;
> +               add->dest.dest.is_ssa = true;
> +               nir_ssa_def_init(&add->instr, &add->dest.dest.ssa, 1,
> NULL);
> +               nir_instr_insert_before(instr, &add->instr);
> +
> +               indirect->is_ssa = true;
> +               indirect->ssa = &add->dest.dest.ssa;
> +            } else {
> +               indirect->is_ssa = true;
> +               indirect->ssa = &mul->dest.dest.ssa;
> +               found_indirect = true;
> +            }
> +         }
> +      } else if (tail->deref_type == nir_deref_type_struct) {
> +         nir_deref_struct *deref_struct = nir_deref_as_struct(tail);
> +
> +         for (unsigned i = 0; i < deref_struct->index; i++)
> +            base_offset += type_size(glsl_get_struct_field(parent_type,
> i));
> +      }
> +   }
> +
> +   return base_offset;
> +}
> +
> +static nir_intrinsic_op
> +get_load_op(nir_variable_mode mode, bool indirect, unsigned
> num_components)
> +{
> +   if (indirect) {
> +      switch (mode) {
> +      case nir_var_shader_in:
> +         switch (num_components) {
> +         case 1: return nir_intrinsic_load_input_vec1_indirect;
> +         case 2: return nir_intrinsic_load_input_vec2_indirect;
> +         case 3: return nir_intrinsic_load_input_vec3_indirect;
> +         case 4: return nir_intrinsic_load_input_vec4_indirect;
> +         default: unreachable("Invalid number of components"); break;
> +         }
> +         break;
> +
> +      case nir_var_uniform:
> +         switch (num_components) {
> +         case 1: return nir_intrinsic_load_uniform_vec1_indirect;
> +         case 2: return nir_intrinsic_load_uniform_vec2_indirect;
> +         case 3: return nir_intrinsic_load_uniform_vec3_indirect;
> +         case 4: return nir_intrinsic_load_uniform_vec4_indirect;
> +         default: unreachable("Invalid number of components"); break;
> +         }
> +         break;
> +
> +      default:
> +         unreachable("Invalid input type");
> +         break;
> +      }
> +   } else {
> +      switch (mode) {
> +      case nir_var_shader_in:
> +         switch (num_components) {
> +         case 1: return nir_intrinsic_load_input_vec1;
> +         case 2: return nir_intrinsic_load_input_vec2;
> +         case 3: return nir_intrinsic_load_input_vec3;
> +         case 4: return nir_intrinsic_load_input_vec4;
> +         default: unreachable("Invalid number of components"); break;
> +         }
> +         break;
> +
> +      case nir_var_uniform:
> +         switch (num_components) {
> +         case 1: return nir_intrinsic_load_uniform_vec1;
> +         case 2: return nir_intrinsic_load_uniform_vec2;
> +         case 3: return nir_intrinsic_load_uniform_vec3;
> +         case 4: return nir_intrinsic_load_uniform_vec4;
> +         default: unreachable("Invalid number of components"); break;
> +         }
> +         break;
> +
> +      default:
> +         unreachable("Invalid input type");
> +         break;
> +      }
> +   }
> +
> +   return nir_intrinsic_load_input_vec1;
> +}
> +
> +static bool
> +nir_lower_io_block(nir_block *block, void *void_state)
> +{
> +   struct lower_io_state *state = 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_load_var_vec1:
> +      case nir_intrinsic_load_var_vec2:
> +      case nir_intrinsic_load_var_vec3:
> +      case nir_intrinsic_load_var_vec4: {
> +         nir_variable_mode mode = intrin->variables[0]->var->data.mode;
> +         if (mode != nir_var_shader_in && mode != nir_var_uniform)
> +            continue;
> +
> +         bool has_indirect = deref_has_indirect(intrin->variables[0]);
> +         unsigned num_components =
> +            nir_intrinsic_infos[intrin->intrinsic].dest_components;
> +
> +         nir_intrinsic_op load_op = get_load_op(mode, has_indirect,
> +                                                num_components);
> +         nir_intrinsic_instr *load =
> nir_intrinsic_instr_create(state->mem_ctx,
> +                                                                load_op);
> +
> +         nir_src indirect;
> +         unsigned offset = get_io_offset(intrin->variables[0],
> +                                         &intrin->instr, &indirect,
> state);
> +         offset += intrin->variables[0]->var->data.driver_location;
> +
> +         load->const_index[0] = offset;
> +         load->const_index[1] = 1;
> +
> +         if (has_indirect)
> +            load->src[0] = indirect;
> +
> +         if (intrin->dest.is_ssa) {
> +            load->dest.is_ssa = true;
> +            nir_ssa_def_init(&load->instr, &load->dest.ssa,
> +                             num_components, NULL);
> +
> +            nir_src new_src = {
> +               .is_ssa = true,
> +               .ssa = &load->dest.ssa,
> +            };
> +
> +            nir_ssa_def_rewrite_uses(&intrin->dest.ssa, new_src,
> +                                     state->mem_ctx);
> +         } else {
> +            load->dest = nir_dest_copy(intrin->dest, state->mem_ctx);
> +         }
> +
> +         nir_instr_insert_before(&intrin->instr, &load->instr);
> +         nir_instr_remove(&intrin->instr);
> +         break;
> +      }
> +
> +      case nir_intrinsic_store_var_vec1:
> +      case nir_intrinsic_store_var_vec2:
> +      case nir_intrinsic_store_var_vec3:
> +      case nir_intrinsic_store_var_vec4: {
> +         if (intrin->variables[0]->var->data.mode != nir_var_shader_out)
> +            continue;
> +
> +         bool has_indirect = deref_has_indirect(intrin->variables[0]);
> +         unsigned num_components =
> +            nir_intrinsic_infos[intrin->intrinsic].src_components[0];
> +
> +         nir_intrinsic_op store_op;
> +         if (has_indirect) {
> +            switch (num_components) {
> +            case 1: store_op = nir_intrinsic_store_output_vec1_indirect;
> break;
> +            case 2: store_op = nir_intrinsic_store_output_vec2_indirect;
> break;
> +            case 3: store_op = nir_intrinsic_store_output_vec3_indirect;
> break;
> +            case 4: store_op = nir_intrinsic_store_output_vec4_indirect;
> break;
> +            default: unreachable("Invalid number of components"); break;
> +            }
> +         } else {
> +            switch (num_components) {
> +            case 1: store_op = nir_intrinsic_store_output_vec1; break;
> +            case 2: store_op = nir_intrinsic_store_output_vec2; break;
> +            case 3: store_op = nir_intrinsic_store_output_vec3; break;
> +            case 4: store_op = nir_intrinsic_store_output_vec4; break;
> +            default: unreachable("Invalid number of components"); break;
> +            }
> +         }
> +
> +         nir_intrinsic_instr *store =
> nir_intrinsic_instr_create(state->mem_ctx,
> +
>  store_op);
> +
> +         nir_src indirect;
> +         unsigned offset = get_io_offset(intrin->variables[0],
> +                                         &intrin->instr, &indirect,
> state);
> +         offset += intrin->variables[0]->var->data.driver_location;
> +
> +         store->const_index[0] = offset;
> +         store->const_index[1] = 1;
> +
> +         store->src[0] = nir_src_copy(intrin->src[0], state->mem_ctx);
> +
> +         if (has_indirect)
> +            store->src[1] = indirect;
> +
> +         nir_instr_insert_before(&intrin->instr, &store->instr);
> +         nir_instr_remove(&intrin->instr);
> +         break;
> +      }
> +
> +      default:
> +         break;
> +      }
> +   }
> +
> +   return true;
> +}
> +
> +static void
> +nir_lower_io_impl(nir_function_impl *impl)
> +{
> +   struct lower_io_state state;
> +
> +   state.mem_ctx = ralloc_parent(impl);
> +
> +   nir_foreach_block(impl, nir_lower_io_block, &state);
> +}
> +
> +void
> +nir_lower_io(nir_shader *shader)
> +{
> +   assign_var_locations_shader(shader);
> +
> +   nir_foreach_overload(shader, overload) {
> +      if (overload->impl)
> +         nir_lower_io_impl(overload->impl);
> +   }
> +}
> --
> 2.2.0
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20150104/022bd0eb/attachment-0001.html>


More information about the mesa-dev mailing list