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

Jason Ekstrand jason at jlekstrand.net
Tue Jan 6 17:06:29 PST 2015


On Sun, Jan 4, 2015 at 8:29 PM, Connor Abbott <cwabbott0 at gmail.com> wrote:

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

Sure, I'll add a note to the comment at the top of the file.


>
> 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/20150106/fde95cc8/attachment-0001.html>


More information about the mesa-dev mailing list