static nir_register *
get_reg_for_deref(nir_deref_instr *deref, struct locals_to_regs_state *state)
{
   uint32_t hash = hash_deref(deref);

   assert(nir_deref_instr_get_variable(deref)->constant_initializer == NULL);

   struct hash_entry *entry =
      _mesa_hash_table_search_pre_hashed(state->regs_table, hash, deref);
   if (entry)
      return entry->data;

   unsigned array_size = 1;
   for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
      if (d->deref_type == nir_deref_type_array)
         array_size *= glsl_get_length(nir_deref_instr_parent(d)->type);
   }

   assert(glsl_type_is_vector_or_scalar(deref->type));

   nir_register *reg = nir_local_reg_create(state->builder.impl);
   reg->num_components = glsl_get_vector_elements(deref->type);
   reg->num_array_elems = array_size > 1 ? array_size : 0;
   reg->bit_size = glsl_get_bit_size(deref->type);

   _mesa_hash_table_insert_pre_hashed(state->regs_table, hash, deref, reg);

   return reg;
}
static bool
derefs_equal(const void *void_a, const void *void_b)
{
   for (const nir_deref_instr *a = void_a, *b = void_b; a || b;
        a = nir_deref_instr_parent(a), b = nir_deref_instr_parent(b)) {
      if (a->deref_type != b->deref_type)
         return false;

      switch (a->deref_type) {
      case nir_deref_type_var:
         return a->var == b->var;

      case nir_deref_type_array:
         continue; /* Do nothing */

      case nir_deref_type_struct:
         if (a->strct.index != b->strct.index)
            return false;
         continue;

      default:
         unreachable("Invalid deref type");
      }
   }

   unreachable("We should have hit a variable dereference");
}
static nir_src
get_deref_reg_src(nir_deref_instr *deref, struct locals_to_regs_state *state)
{
   nir_builder *b = &state->builder;

   nir_src src;

   src.is_ssa = false;
   src.reg.reg = get_reg_for_deref(deref, state);
   src.reg.base_offset = 0;
   src.reg.indirect = NULL;

   /* It is possible for a user to create a shader that has an array with a
    * single element and then proceed to access it indirectly.  Indirectly
    * accessing a non-array register is not allowed in NIR.  In order to
    * handle this case we just convert it to a direct reference.
    */
   if (src.reg.reg->num_array_elems == 0)
      return src;

   unsigned inner_array_size = 1;
   for (const nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
      if (d->deref_type != nir_deref_type_array)
         continue;

      if (nir_src_is_const(d->arr.index) && !src.reg.indirect) {
         src.reg.base_offset += nir_src_as_uint(d->arr.index) *
                                inner_array_size;
      } else {
         if (src.reg.indirect) {
            assert(src.reg.base_offset == 0);
         } else {
            src.reg.indirect = ralloc(b->shader, nir_src);
            *src.reg.indirect =
               nir_src_for_ssa(nir_imm_int(b, src.reg.base_offset));
            src.reg.base_offset = 0;
         }

         assert(src.reg.indirect->is_ssa);
         nir_ssa_def *index = nir_i2i(b, nir_ssa_for_src(b, d->arr.index, 1), 32);
         src.reg.indirect->ssa =
            nir_iadd(b, src.reg.indirect->ssa,
                        nir_imul(b, index, nir_imm_int(b, inner_array_size)));
      }

      inner_array_size *= glsl_get_length(nir_deref_instr_parent(d)->type);
   }

   return src;
}
/* The following two functions implement a hash and equality check for
 * variable dreferences.  When the hash or equality function encounters an
 * array, it ignores the offset and whether it is direct or indirect
 * entirely.
 */
static uint32_t
hash_deref(const void *void_deref)
{
   uint32_t hash = _mesa_fnv32_1a_offset_bias;

   for (const nir_deref_instr *deref = void_deref; deref;
        deref = nir_deref_instr_parent(deref)) {
      switch (deref->deref_type) {
      case nir_deref_type_var:
         return _mesa_fnv32_1a_accumulate(hash, deref->var);

      case nir_deref_type_array:
         continue; /* Do nothing */

      case nir_deref_type_struct:
         hash = _mesa_fnv32_1a_accumulate(hash, deref->strct.index);
         continue;

      default:
         unreachable("Invalid deref type");
      }
   }

   unreachable("We should have hit a variable dereference");
}
static bool
deref_has_indirect(nir_deref_instr *deref)
{
   while (deref->deref_type != nir_deref_type_var) {
      if (deref->deref_type == nir_deref_type_array &&
          nir_src_as_const_value(deref->arr.index) == NULL)
         return true;

      deref = nir_deref_instr_parent(deref);
   }

   return false;
}
示例#6
0
static unsigned
get_io_offset(nir_deref_instr *deref, bool is_vertex_input)
{
   unsigned offset = 0;

   for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
      if (d->deref_type == nir_deref_type_array) {
         if (!nir_src_is_const(d->arr.index))
            return -1;

         offset += glsl_count_attribute_slots(d->type, is_vertex_input) *
                   nir_src_as_uint(d->arr.index);
      }
      /* TODO: we can get the offset for structs here see nir_lower_io() */
   }

   return offset;
}