[Mesa-dev] [PATCH v3 002/104] nir: Add a deref instruction type

Bas Nieuwenhuizen bas at basnieuwenhuizen.nl
Sun Apr 8 21:26:57 UTC 2018


On Sun, Apr 8, 2018 at 10:43 PM, Bas Nieuwenhuizen
<bas at basnieuwenhuizen.nl> wrote:
> On Sun, Apr 8, 2018 at 10:23 PM, Bas Nieuwenhuizen
> <bas at basnieuwenhuizen.nl> wrote:
>> On Tue, Apr 3, 2018 at 8:32 PM, Jason Ekstrand <jason at jlekstrand.net> wrote:
>>> This commit adds a new instruction type to NIR for handling derefs.
>>> Nothing uses it yet but this adds the data structure as well as all of
>>> the code to validate, print, clone, and [de]serialize them.
>>> ---
>>>  src/compiler/nir/nir.c                    | 50 +++++++++++++++++++
>>>  src/compiler/nir/nir.h                    | 58 ++++++++++++++++++++-
>>>  src/compiler/nir/nir_clone.c              | 42 ++++++++++++++++
>>>  src/compiler/nir/nir_instr_set.c          | 78 +++++++++++++++++++++++++++++
>>>  src/compiler/nir/nir_opt_copy_propagate.c | 62 +++++++++++++++++++----
>>>  src/compiler/nir/nir_opt_dce.c            |  7 +++
>>>  src/compiler/nir/nir_print.c              | 56 +++++++++++++++++++++
>>>  src/compiler/nir/nir_serialize.c          | 81 ++++++++++++++++++++++++++++++
>>>  src/compiler/nir/nir_validate.c           | 83 +++++++++++++++++++++++++++++++
>>>  9 files changed, 506 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c
>>> index 8364197..a538f22 100644
>>> --- a/src/compiler/nir/nir.c
>>> +++ b/src/compiler/nir/nir.c
>>> @@ -470,6 +470,26 @@ nir_alu_instr_create(nir_shader *shader, nir_op op)
>>>     return instr;
>>>  }
>>>
>>> +nir_deref_instr *
>>> +nir_deref_instr_create(nir_shader *shader, nir_deref_type deref_type)
>>> +{
>>> +   nir_deref_instr *instr =
>>> +      rzalloc_size(shader, sizeof(nir_deref_instr));
>>> +
>>> +   instr_init(&instr->instr, nir_instr_type_deref);
>>> +
>>> +   instr->deref_type = deref_type;
>>> +   if (deref_type != nir_deref_type_var)
>>> +      src_init(&instr->parent);
>>> +
>>> +   if (deref_type == nir_deref_type_array)
>>> +      src_init(&instr->arr.index);
>>> +
>>> +   dest_init(&instr->dest);
>>> +
>>> +   return instr;
>>> +}
>>> +
>>>  nir_jump_instr *
>>>  nir_jump_instr_create(nir_shader *shader, nir_jump_type type)
>>>  {
>>> @@ -1199,6 +1219,12 @@ visit_alu_dest(nir_alu_instr *instr, nir_foreach_dest_cb cb, void *state)
>>>  }
>>>
>>>  static bool
>>> +visit_deref_dest(nir_deref_instr *instr, nir_foreach_dest_cb cb, void *state)
>>> +{
>>> +   return cb(&instr->dest, state);
>>> +}
>>> +
>>> +static bool
>>>  visit_intrinsic_dest(nir_intrinsic_instr *instr, nir_foreach_dest_cb cb,
>>>                       void *state)
>>>  {
>>> @@ -1239,6 +1265,8 @@ nir_foreach_dest(nir_instr *instr, nir_foreach_dest_cb cb, void *state)
>>>     switch (instr->type) {
>>>     case nir_instr_type_alu:
>>>        return visit_alu_dest(nir_instr_as_alu(instr), cb, state);
>>> +   case nir_instr_type_deref:
>>> +      return visit_deref_dest(nir_instr_as_deref(instr), cb, state);
>>>     case nir_instr_type_intrinsic:
>>>        return visit_intrinsic_dest(nir_instr_as_intrinsic(instr), cb, state);
>>>     case nir_instr_type_tex:
>>> @@ -1284,6 +1312,7 @@ nir_foreach_ssa_def(nir_instr *instr, nir_foreach_ssa_def_cb cb, void *state)
>>>  {
>>>     switch (instr->type) {
>>>     case nir_instr_type_alu:
>>> +   case nir_instr_type_deref:
>>>     case nir_instr_type_tex:
>>>     case nir_instr_type_intrinsic:
>>>     case nir_instr_type_phi:
>>> @@ -1350,6 +1379,23 @@ visit_alu_src(nir_alu_instr *instr, nir_foreach_src_cb cb, void *state)
>>>  }
>>>
>>>  static bool
>>> +visit_deref_instr_src(nir_deref_instr *instr,
>>> +                      nir_foreach_src_cb cb, void *state)
>>> +{
>>> +   if (instr->deref_type != nir_deref_type_var) {
>>> +      if (!visit_src(&instr->parent, cb, state))
>>> +         return false;
>>> +   }
>>> +
>>> +   if (instr->deref_type == nir_deref_type_array) {
>>> +      if (!visit_src(&instr->arr.index, cb, state))
>>> +         return false;
>>> +   }
>>> +
>>> +   return true;
>>> +}
>>> +
>>> +static bool
>>>  visit_tex_src(nir_tex_instr *instr, nir_foreach_src_cb cb, void *state)
>>>  {
>>>     for (unsigned i = 0; i < instr->num_srcs; i++) {
>>> @@ -1437,6 +1483,10 @@ nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state)
>>>        if (!visit_alu_src(nir_instr_as_alu(instr), cb, state))
>>>           return false;
>>>        break;
>>> +   case nir_instr_type_deref:
>>> +      if (!visit_deref_instr_src(nir_instr_as_deref(instr), cb, state))
>>> +         return false;
>>> +      break;
>>>     case nir_instr_type_intrinsic:
>>>        if (!visit_intrinsic_src(nir_instr_as_intrinsic(instr), cb, state))
>>>           return false;
>>> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
>>> index cc7c401..db7dc91 100644
>>> --- a/src/compiler/nir/nir.h
>>> +++ b/src/compiler/nir/nir.h
>>> @@ -427,6 +427,7 @@ typedef struct nir_register {
>>>
>>>  typedef enum {
>>>     nir_instr_type_alu,
>>> +   nir_instr_type_deref,
>>>     nir_instr_type_call,
>>>     nir_instr_type_tex,
>>>     nir_instr_type_intrinsic,
>>> @@ -894,7 +895,9 @@ bool nir_alu_srcs_equal(const nir_alu_instr *alu1, const nir_alu_instr *alu2,
>>>  typedef enum {
>>>     nir_deref_type_var,
>>>     nir_deref_type_array,
>>> -   nir_deref_type_struct
>>> +   nir_deref_type_array_wildcard,
>>> +   nir_deref_type_struct,
>>> +   nir_deref_type_cast,
>>>  } nir_deref_type;
>>>
>>>  typedef struct nir_deref {
>>> @@ -956,6 +959,56 @@ nir_deref_tail(nir_deref *deref)
>>>  typedef struct {
>>>     nir_instr instr;
>>>
>>> +   /** The type of this deref instruction */
>>> +   nir_deref_type deref_type;
>>> +
>>> +   /** The mode of the underlying variable */
>>> +   nir_variable_mode mode;
>>> +
>>> +   /** The dereferenced type of the resulting pointer value */
>>> +   const struct glsl_type *type;
>>> +
>>> +   union {
>>> +      /** Variable being dereferenced if deref_type is a deref_var */
>>> +      nir_variable *var;
>>> +
>>> +      /** Parent deref if deref_type is not deref_var */
>>> +      nir_src parent;
>>> +   };
>>> +
>>> +   /** Additional deref parameters */
>>> +   union {
>>> +      struct {
>>> +         nir_src index;
>>> +      } arr;
>>> +
>>> +      struct {
>>> +         unsigned index;
>>> +      } strct;
>>> +   };
>>> +
>>> +   /** Destination to store the resulting "pointer" */
>>> +   nir_dest dest;
>>> +} nir_deref_instr;
>>> +
>>> +NIR_DEFINE_CAST(nir_instr_as_deref, nir_instr, nir_deref_instr, instr,
>>> +                type, nir_instr_type_deref)
>>> +
>>> +static inline nir_deref_instr *
>>> +nir_src_as_deref(nir_src src)
>>> +{
>>> +   if (!src.is_ssa)
>>> +      return NULL;
>>> +
>>> +   if (src.ssa->parent_instr->type != nir_instr_type_deref)
>>> +      return NULL;
>>> +
>>> +   return nir_instr_as_deref(src.ssa->parent_instr);
>>> +}
>>> +
>>> +typedef struct {
>>> +   nir_instr instr;
>>> +
>>>     unsigned num_params;
>>>     nir_deref_var **params;
>>>     nir_deref_var *return_deref;
>>> @@ -2044,6 +2097,9 @@ void nir_metadata_preserve(nir_function_impl *impl, nir_metadata preserved);
>>>  /** creates an instruction with default swizzle/writemask/etc. with NULL registers */
>>>  nir_alu_instr *nir_alu_instr_create(nir_shader *shader, nir_op op);
>>>
>>> +nir_deref_instr *nir_deref_instr_create(nir_shader *shader,
>>> +                                        nir_deref_type deref_type);
>>> +
>>>  nir_jump_instr *nir_jump_instr_create(nir_shader *shader, nir_jump_type type);
>>>
>>>  nir_load_const_instr *nir_load_const_instr_create(nir_shader *shader,
>>> diff --git a/src/compiler/nir/nir_clone.c b/src/compiler/nir/nir_clone.c
>>> index bcfdaa7..20eaaff 100644
>>> --- a/src/compiler/nir/nir_clone.c
>>> +++ b/src/compiler/nir/nir_clone.c
>>> @@ -346,6 +346,46 @@ clone_alu(clone_state *state, const nir_alu_instr *alu)
>>>     return nalu;
>>>  }
>>>
>>> +static nir_deref_instr *
>>> +clone_deref_instr(clone_state *state, const nir_deref_instr *deref)
>>> +{
>>> +   nir_deref_instr *nderef =
>>> +      nir_deref_instr_create(state->ns, deref->deref_type);
>>> +
>>> +   __clone_dst(state, &nderef->instr, &nderef->dest, &deref->dest);
>>> +
>>> +   nderef->mode = deref->mode;
>>> +   nderef->type = deref->type;
>>> +
>>> +   if (deref->deref_type == nir_deref_type_var) {
>>> +      nderef->var = remap_var(state, deref->var);
>>> +      return nderef;
>>> +   }
>>> +
>>> +   __clone_src(state, &nderef->instr, &nderef->parent, &deref->parent);
>>> +
>>> +   switch (deref->deref_type) {
>>> +   case nir_deref_type_struct:
>>> +      nderef->strct.index = deref->strct.index;
>>> +      break;
>>> +
>>> +   case nir_deref_type_array:
>>> +      __clone_src(state, &nderef->instr,
>>> +                  &nderef->arr.index, &deref->arr.index);
>>> +      break;
>>> +
>>> +   case nir_deref_type_array_wildcard:
>>> +   case nir_deref_type_cast:
>>> +      /* Nothing to do */
>>> +      break;
>>> +
>>> +   default:
>>> +      unreachable("Invalid instruction deref type");
>>> +   }
>>> +
>>> +   return nderef;
>>> +}
>>> +
>>>  static nir_intrinsic_instr *
>>>  clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr)
>>>  {
>>> @@ -502,6 +542,8 @@ clone_instr(clone_state *state, const nir_instr *instr)
>>>     switch (instr->type) {
>>>     case nir_instr_type_alu:
>>>        return &clone_alu(state, nir_instr_as_alu(instr))->instr;
>>> +   case nir_instr_type_deref:
>>> +      return &clone_deref_instr(state, nir_instr_as_deref(instr))->instr;
>>>     case nir_instr_type_intrinsic:
>>>        return &clone_intrinsic(state, nir_instr_as_intrinsic(instr))->instr;
>>>     case nir_instr_type_load_const:
>>> diff --git a/src/compiler/nir/nir_instr_set.c b/src/compiler/nir/nir_instr_set.c
>>> index 9cb9ed4..939ddcc 100644
>>> --- a/src/compiler/nir/nir_instr_set.c
>>> +++ b/src/compiler/nir/nir_instr_set.c
>>> @@ -79,6 +79,40 @@ hash_alu(uint32_t hash, const nir_alu_instr *instr)
>>>  }
>>>
>>>  static uint32_t
>>> +hash_deref(uint32_t hash, const nir_deref_instr *instr)
>>> +{
>>> +   hash = HASH(hash, instr->deref_type);
>>> +   hash = HASH(hash, instr->mode);
>>> +   hash = HASH(hash, instr->type);
>>> +
>>> +   if (instr->deref_type == nir_deref_type_var)
>>> +      return HASH(hash, instr->var);
>>> +
>>> +   hash = hash_src(hash, &instr->parent);
>>> +
>>> +   switch (instr->deref_type) {
>>> +   case nir_deref_type_struct:
>>> +      hash = HASH(hash, instr->strct.index);
>>> +      break;
>>> +
>>> +   case nir_deref_type_array:
>>> +      hash = hash_src(hash, &instr->arr.index);
>>> +      break;
>>> +
>>> +   case nir_deref_type_var:
>>> +   case nir_deref_type_array_wildcard:
>>> +   case nir_deref_type_cast:
>>> +      /* Nothing to do */
>>> +      break;
>>> +
>>> +   default:
>>> +      unreachable("Invalid instruction deref type");
>>> +   }
>>> +
>>> +   return hash;
>>> +}
>>> +
>>> +static uint32_t
>>>  hash_load_const(uint32_t hash, const nir_load_const_instr *instr)
>>>  {
>>>     hash = HASH(hash, instr->def.num_components);
>>> @@ -182,6 +216,9 @@ hash_instr(const void *data)
>>>     case nir_instr_type_alu:
>>>        hash = hash_alu(hash, nir_instr_as_alu(instr));
>>>        break;
>>> +   case nir_instr_type_deref:
>>> +      hash = hash_deref(hash, nir_instr_as_deref(instr));
>>> +      break;
>>>     case nir_instr_type_load_const:
>>>        hash = hash_load_const(hash, nir_instr_as_load_const(instr));
>>>        break;
>>> @@ -289,6 +326,43 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2)
>>>        }
>>>        return true;
>>>     }
>>> +   case nir_instr_type_deref: {
>>> +      nir_deref_instr *deref1 = nir_instr_as_deref(instr1);
>>> +      nir_deref_instr *deref2 = nir_instr_as_deref(instr2);
>>> +
>>> +      if (deref1->deref_type != deref2->deref_type ||
>>> +          deref1->mode != deref2->mode ||
>>> +          deref1->type != deref2->type)
>>> +         return false;
>>> +
>>> +      if (deref1->deref_type == nir_deref_type_var)
>>> +         return deref1->var == deref2->var;
>>> +
>>> +      if (!nir_srcs_equal(deref1->parent, deref2->parent))
>>> +         return false;
>>> +
>>> +      switch (deref1->deref_type) {
>>> +      case nir_deref_type_struct:
>>> +         if (deref1->strct.index != deref2->strct.index)
>>> +            return false;
>>> +         break;
>>> +
>>> +      case nir_deref_type_array:
>>> +         if (!nir_srcs_equal(deref1->arr.index, deref2->arr.index))
>>> +            return false;
>>> +         break;
>>> +
>>> +      case nir_deref_type_var:
>>> +      case nir_deref_type_array_wildcard:
>>> +      case nir_deref_type_cast:
>>> +         /* Nothing to do */
>>> +         break;
>>> +
>>> +      default:
>>> +         unreachable("Invalid instruction deref type");
>>> +      }
>>> +      break;
>>> +   }
>>>     case nir_instr_type_tex: {
>>>        nir_tex_instr *tex1 = nir_instr_as_tex(instr1);
>>>        nir_tex_instr *tex2 = nir_instr_as_tex(instr2);
>>> @@ -430,6 +504,7 @@ instr_can_rewrite(nir_instr *instr)
>>>
>>>     switch (instr->type) {
>>>     case nir_instr_type_alu:
>>> +   case nir_instr_type_deref:
>>>     case nir_instr_type_load_const:
>>>     case nir_instr_type_phi:
>>>        return true;
>>> @@ -468,6 +543,9 @@ nir_instr_get_dest_ssa_def(nir_instr *instr)
>>>     case nir_instr_type_alu:
>>>        assert(nir_instr_as_alu(instr)->dest.dest.is_ssa);
>>>        return &nir_instr_as_alu(instr)->dest.dest.ssa;
>>> +   case nir_instr_type_deref:
>>> +      assert(nir_instr_as_deref(instr)->dest.is_ssa);
>>> +      return &nir_instr_as_deref(instr)->dest.ssa;
>>>     case nir_instr_type_load_const:
>>>        return &nir_instr_as_load_const(instr)->def;
>>>     case nir_instr_type_phi:
>>> diff --git a/src/compiler/nir/nir_opt_copy_propagate.c b/src/compiler/nir/nir_opt_copy_propagate.c
>>> index c4001fa..594727c 100644
>>> --- a/src/compiler/nir/nir_opt_copy_propagate.c
>>> +++ b/src/compiler/nir/nir_opt_copy_propagate.c
>>> @@ -99,6 +99,22 @@ is_swizzleless_move(nir_alu_instr *instr)
>>>  }
>>>
>>>  static bool
>>> +is_trivial_deref_cast(nir_deref_instr *cast)
>>> +{
>>> +   nir_deref_instr *parent = nir_src_as_deref(cast->parent);
>>> +   if (!parent)
>>> +      return false;
>>> +
>>> +   if (cast->deref_type != nir_deref_type_cast)
>>> +      return false;
>>> +
>>> +   return cast->mode == parent->mode &&
>>> +          cast->type == parent->type &&
>>> +          cast->dest.ssa.num_components == parent->dest.ssa.num_components &&
>>> +          cast->dest.ssa.bit_size == parent->dest.ssa.bit_size;
>>> +}
>>> +
>>> +static bool
>>>  copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if,
>>>                unsigned num_components)
>>>  {
>>> @@ -109,23 +125,31 @@ copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if,
>>>     }
>>>
>>>     nir_instr *src_instr = src->ssa->parent_instr;
>>> -   if (src_instr->type != nir_instr_type_alu)
>>> -      return false;
>>> +   nir_ssa_def *copy_def;
>>> +   if (src_instr->type == nir_instr_type_alu) {
>>> +      nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
>>> +      if (!is_swizzleless_move(alu_instr))
>>> +         return false;
>>>
>>> -   nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
>>> -   if (!is_swizzleless_move(alu_instr))
>>> -      return false;
>>> +      if (alu_instr->src[0].src.ssa->num_components != num_components)
>>> +         return false;
>>>
>>> -   if (alu_instr->src[0].src.ssa->num_components != num_components)
>>> +      copy_def= alu_instr->src[0].src.ssa;
>>> +   } else if (src_instr->type == nir_instr_type_deref) {
>>> +      nir_deref_instr *deref_instr = nir_instr_as_deref(src_instr);
>>> +      if (!is_trivial_deref_cast(deref_instr))
>>> +         return false;
>>> +
>>> +      copy_def = deref_instr->parent.ssa;
>>> +   } else {
>>>        return false;
>>> +   }
>>>
>>>     if (parent_instr) {
>>> -      nir_instr_rewrite_src(parent_instr, src,
>>> -                            nir_src_for_ssa(alu_instr->src[0].src.ssa));
>>> +      nir_instr_rewrite_src(parent_instr, src, nir_src_for_ssa(copy_def));
>>>     } else {
>>>        assert(src == &parent_if->condition);
>>> -      nir_if_rewrite_condition(parent_if,
>>> -                               nir_src_for_ssa(alu_instr->src[0].src.ssa));
>>> +      nir_if_rewrite_condition(parent_if, nir_src_for_ssa(copy_def));
>>>     }
>>>
>>>     return true;
>>> @@ -234,6 +258,24 @@ copy_prop_instr(nir_instr *instr)
>>>        return progress;
>>>     }
>>>
>>> +   case nir_instr_type_deref: {
>>> +      nir_deref_instr *deref = nir_instr_as_deref(instr);
>>> +
>>> +      if (deref->deref_type != nir_deref_type_var) {
>>> +         assert(deref->dest.is_ssa);
>>> +         const unsigned comps = deref->dest.ssa.num_components;
>>> +         while (copy_prop_src(&deref->parent, instr, NULL, comps))
>>> +            progress = true;
>>> +      }
>>> +
>>> +      if (deref->deref_type == nir_deref_type_array) {
>>> +         while (copy_prop_src(&deref->arr.index, instr, NULL, 1))
>>> +            progress = true;
>>> +      }
>>> +
>>> +      return progress;
>>> +   }
>>> +
>>>     case nir_instr_type_tex: {
>>>        nir_tex_instr *tex = nir_instr_as_tex(instr);
>>>        for (unsigned i = 0; i < tex->num_srcs; i++) {
>>> diff --git a/src/compiler/nir/nir_opt_dce.c b/src/compiler/nir/nir_opt_dce.c
>>> index 570e430..c9b3388 100644
>>> --- a/src/compiler/nir/nir_opt_dce.c
>>> +++ b/src/compiler/nir/nir_opt_dce.c
>>> @@ -52,6 +52,7 @@ static void
>>>  init_instr(nir_instr *instr, nir_instr_worklist *worklist)
>>>  {
>>>     nir_alu_instr *alu_instr;
>>> +   nir_deref_instr *deref_instr;
>>>     nir_intrinsic_instr *intrin_instr;
>>>     nir_tex_instr *tex_instr;
>>>
>>> @@ -73,6 +74,12 @@ init_instr(nir_instr *instr, nir_instr_worklist *worklist)
>>>           mark_and_push(worklist, instr);
>>>        break;
>>>
>>> +   case nir_instr_type_deref:
>>> +      deref_instr = nir_instr_as_deref(instr);
>>> +      if (!deref_instr->dest.is_ssa)
>>> +         mark_and_push(worklist, instr);
>>> +      break;
>>> +
>>>     case nir_instr_type_intrinsic:
>>>        intrin_instr = nir_instr_as_intrinsic(instr);
>>>        if (nir_intrinsic_infos[intrin_instr->intrinsic].flags &
>>> diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c
>>> index 21f1309..64fdfb2 100644
>>> --- a/src/compiler/nir/nir_print.c
>>> +++ b/src/compiler/nir/nir_print.c
>>> @@ -488,6 +488,58 @@ print_var_decl(nir_variable *var, print_state *state)
>>>  }
>>>
>>>  static void
>>> +print_deref_instr(nir_deref_instr *instr, print_state *state)
>>> +{
>>> +   FILE *fp = state->fp;
>>> +
>>> +   print_dest(&instr->dest, state);
>>> +
>>> +   if (instr->deref_type == nir_deref_type_var) {
>>> +      fprintf(fp, " = deref %s", get_var_name(instr->var, state));
>>> +      return;
>>> +   } else if (instr->deref_type == nir_deref_type_cast) {
>>> +      fprintf(fp, " = deref (%s) (%s *)&",
>>> +              get_variable_mode_str(instr->mode),
>>> +              glsl_get_type_name(instr->type));
>>> +      print_src(&instr->parent, state);
>>> +      return;
>>> +   }
>>> +
>>> +   fprintf(fp, " = deref (%s) &", get_variable_mode_str(instr->mode));
>>> +   print_src(&instr->parent, state);
>>> +
>>> +   assert(instr->parent.is_ssa);
>>> +   nir_deref_instr *parent =
>>> +      nir_instr_as_deref(instr->parent.ssa->parent_instr);
>>> +
>>> +   switch (instr->deref_type) {
>>> +   case nir_deref_type_struct:
>>> +      fprintf(fp, "->%s",
>>> +              glsl_get_struct_elem_name(parent->type, instr->strct.index));
>>> +      break;
>>> +
>>> +   case nir_deref_type_array: {
>>> +      nir_const_value *const_index = nir_src_as_const_value(instr->arr.index);
>>> +      if (const_index) {
>>> +         fprintf(fp, "[%u]", const_index->u32[0]);
>>> +      } else {
>>> +         fprintf(fp, "[");
>>> +         print_src(&instr->arr.index, state);
>>> +         fprintf(fp, "]");
>>> +      }
>>> +      break;
>>> +   }
>>> +
>>> +   case nir_deref_type_array_wildcard:
>>> +      fprintf(fp, "[*]");
>>> +      break;
>>> +
>>> +   default:
>>> +      unreachable("Invalid deref instruction type");
>>> +   }
>>> +}
>>> +
>>> +static void
>>>  print_var(nir_variable *var, print_state *state)
>>>  {
>>>     FILE *fp = state->fp;
>>> @@ -924,6 +976,10 @@ print_instr(const nir_instr *instr, print_state *state, unsigned tabs)
>>>        print_alu_instr(nir_instr_as_alu(instr), state);
>>>        break;
>>>
>>> +   case nir_instr_type_deref:
>>> +      print_deref_instr(nir_instr_as_deref(instr), state);
>>> +      break;
>>> +
>>>     case nir_instr_type_call:
>>>        print_call_instr(nir_instr_as_call(instr), state);
>>>        break;
>>> diff --git a/src/compiler/nir/nir_serialize.c b/src/compiler/nir/nir_serialize.c
>>> index 00df49c..834a65b 100644
>>> --- a/src/compiler/nir/nir_serialize.c
>>> +++ b/src/compiler/nir/nir_serialize.c
>>> @@ -479,6 +479,81 @@ read_alu(read_ctx *ctx)
>>>  }
>>>
>>>  static void
>>> +write_deref(write_ctx *ctx, const nir_deref_instr *deref)
>>> +{
>>> +   blob_write_uint32(ctx->blob, deref->deref_type);
>>> +
>>> +   blob_write_uint32(ctx->blob, deref->mode);
>>> +   encode_type_to_blob(ctx->blob, deref->type);
>>> +
>>> +   write_dest(ctx, &deref->dest);
>>> +
>>> +   if (deref->deref_type == nir_deref_type_var) {
>>> +      write_object(ctx, deref->var);
>>> +      return;
>>> +   }
>>> +
>>> +   write_src(ctx, &deref->parent);
>>> +
>>> +   switch (deref->deref_type) {
>>> +   case nir_deref_type_struct:
>>> +      blob_write_uint32(ctx->blob, deref->strct.index);
>>> +      break;
>>> +
>>> +   case nir_deref_type_array:
>>> +      write_src(ctx, &deref->arr.index);
>>> +      break;
>>> +
>>> +   case nir_deref_type_array_wildcard:
>>> +   case nir_deref_type_cast:
>>> +      /* Nothing to do */
>>> +      break;
>>> +
>>> +   default:
>>> +      unreachable("Invalid deref type");
>>> +   }
>>> +}
>>> +
>>> +static nir_deref_instr *
>>> +read_deref(read_ctx *ctx)
>>> +{
>>> +   nir_deref_type deref_type = blob_read_uint32(ctx->blob);
>>> +   nir_deref_instr *deref = nir_deref_instr_create(ctx->nir, deref_type);
>>> +
>>> +   deref->mode = blob_read_uint32(ctx->blob);
>>> +   deref->type = decode_type_from_blob(ctx->blob);
>>> +
>>> +   read_dest(ctx, &deref->dest, &deref->instr);
>>> +
>>> +   if (deref_type == nir_deref_type_var) {
>>> +      deref->var = read_object(ctx);
>>> +      return deref;
>>> +   }
>>> +
>>> +   read_src(ctx, &deref->parent, &deref->instr);
>>> +
>>> +   switch (deref->deref_type) {
>>> +   case nir_deref_type_struct:
>>> +      deref->strct.index = blob_read_uint32(ctx->blob);
>>> +      break;
>>> +
>>> +   case nir_deref_type_array:
>>> +      read_src(ctx, &deref->arr.index, &deref->instr);
>>> +      break;
>>> +
>>> +   case nir_deref_type_array_wildcard:
>>> +   case nir_deref_type_cast:
>>> +      /* Nothing to do */
>>> +      break;
>>> +
>>> +   default:
>>> +      unreachable("Invalid deref type");
>>> +   }
>>> +
>>> +   return deref;
>>> +}
>>> +
>>> +static void
>>>  write_intrinsic(write_ctx *ctx, const nir_intrinsic_instr *intrin)
>>>  {
>>>     blob_write_uint32(ctx->blob, intrin->intrinsic);
>>> @@ -803,6 +878,9 @@ write_instr(write_ctx *ctx, const nir_instr *instr)
>>>     case nir_instr_type_alu:
>>>        write_alu(ctx, nir_instr_as_alu(instr));
>>>        break;
>>> +   case nir_instr_type_deref:
>>> +      write_deref(ctx, nir_instr_as_deref(instr));
>>> +      break;
>>>     case nir_instr_type_intrinsic:
>>>        write_intrinsic(ctx, nir_instr_as_intrinsic(instr));
>>>        break;
>>> @@ -840,6 +918,9 @@ read_instr(read_ctx *ctx, nir_block *block)
>>>     case nir_instr_type_alu:
>>>        instr = &read_alu(ctx)->instr;
>>>        break;
>>> +   case nir_instr_type_deref:
>>> +      instr = &read_deref(ctx)->instr;
>>> +      break;
>>>     case nir_instr_type_intrinsic:
>>>        instr = &read_intrinsic(ctx)->instr;
>>>        break;
>>> diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c
>>> index d05b982..527abde 100644
>>> --- a/src/compiler/nir/nir_validate.c
>>> +++ b/src/compiler/nir/nir_validate.c
>>> @@ -471,6 +471,85 @@ validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *s
>>>  }
>>>
>>>  static void
>>> +validate_deref_instr(nir_deref_instr *instr, validate_state *state)
>>> +{
>>> +   if (instr->deref_type == nir_deref_type_var) {
>>> +      /* Variable dereferences are stupid simple. */
>>> +      validate_assert(state, instr->mode == instr->var->data.mode);
>>> +      validate_assert(state, instr->type == instr->var->type);
>>> +      validate_var_use(instr->var, state);
>>> +   } else if (instr->deref_type == nir_deref_type_cast) {
>>> +      /* For cast, we simply have to trust the instruction.  It's up to
>>> +       * lowering passes and front/back-ends to make them sane.
>>> +       */
>>> +      validate_src(&instr->parent, state, 0, 0);
>>> +
>>> +      /* We just validate that the type and mode are there */
>>> +      validate_assert(state, instr->mode);
>>> +      validate_assert(state, instr->type);
>>> +   } else {
>>> +      /* We require the parent to be SSA.  This may be lifted in the future */
>>> +      validate_assert(state, instr->parent.is_ssa);
>>> +
>>> +      /* The parent pointer value must have the same number of components
>>> +       * as the destination.
>>> +       */
>>> +      validate_src(&instr->parent, state, nir_dest_bit_size(instr->dest),
>>> +                   nir_dest_num_components(instr->dest));
>>> +
>>> +      nir_instr *parent_instr = instr->parent.ssa->parent_instr;
>>> +
>>> +      /* The parent must come from another deref instruction */
>>> +      validate_assert(state, parent_instr->type == nir_instr_type_deref);
>>
>> why no phi or select here? Those don't change anything about the
>> pointer, so I'd not expect a cast?
>
> nvm, I see it is useful to convey the type and mode of the resulting
> pointer in those kinds of situations.

Thinking some more, this is not really ideal. We can't really
distinguish between a cast that does something, and a cast that just
is there because the direct source was not a deref even though the
value was ultimately generated by deref (e.g. phi, select, a
store->load pair).

I get that since nir does not have types for SSA values we need an
extra instruction for the second case, but do we really want to
conflate those two cases?

this results in ambiguity if we have e.g.

deref_cast(load(...), __generic/mode_all)

Does the load return a pointer to generic already, or can it be a
__private pointer that gets converted to __generic or similar?

Also, do we want validation rules like if a phi/select has a deref as
arg, then all args have to be derefs and they have to have the same
type+mode?

>>
>>> +
>>> +      nir_deref_instr *parent = nir_instr_as_deref(parent_instr);
>>> +
>>> +      validate_assert(state, instr->mode == parent->mode);
>>> +
>>> +      switch (instr->deref_type) {
>>> +      case nir_deref_type_struct:
>>> +         validate_assert(state, glsl_type_is_struct(parent->type));
>>> +         validate_assert(state,
>>> +            instr->strct.index < glsl_get_length(parent->type));
>>> +         validate_assert(state, instr->type ==
>>> +            glsl_get_struct_field(parent->type, instr->strct.index));
>>> +         break;
>>> +
>>> +      case nir_deref_type_array:
>>> +      case nir_deref_type_array_wildcard:
>>> +         if (instr->mode == nir_var_shared) {
>>> +            /* Shared variables have a bit more relaxed rules because we need
>>> +             * to be able to handle array derefs on vectors.  Fortunately,
>>> +             * nir_lower_io handles these just fine.
>>> +             */
>>> +            validate_assert(state, glsl_type_is_array(parent->type) ||
>>> +                                   glsl_type_is_matrix(parent->type) ||
>>> +                                   glsl_type_is_vector(parent->type));
>>> +         } else {
>>> +            /* Most of NIR cannot handle array derefs on vectors */
>>> +            validate_assert(state, glsl_type_is_array(parent->type) ||
>>> +                                   glsl_type_is_matrix(parent->type));
>>> +         }
>>> +         validate_assert(state,
>>> +            instr->type == glsl_get_array_element(parent->type));
>>> +
>>> +         if (instr->deref_type == nir_deref_type_array)
>>> +            validate_src(&instr->arr.index, state, 32, 1);
>>> +         break;
>>> +
>>> +      default:
>>> +         unreachable("Invalid deref instruction type");
>>> +      }
>>> +   }
>>> +
>>> +   /* We intentionally don't validate the size of the destination because we
>>> +    * want to let other compiler components such as SPIR-V decide how big
>>> +    * pointers should be.
>>> +    */
>>> +   validate_dest(&instr->dest, state, 0, 0);
>>> +}
>>> +
>>> +static void
>>>  validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state)
>>>  {
>>>     unsigned dest_bit_size = 0;
>>> @@ -624,6 +703,10 @@ validate_instr(nir_instr *instr, validate_state *state)
>>>        validate_alu_instr(nir_instr_as_alu(instr), state);
>>>        break;
>>>
>>> +   case nir_instr_type_deref:
>>> +      validate_deref_instr(nir_instr_as_deref(instr), state);
>>> +      break;
>>> +
>>>     case nir_instr_type_call:
>>>        validate_call_instr(nir_instr_as_call(instr), state);
>>>        break;
>>> --
>>> 2.5.0.400.gff86faf
>>>
>>> _______________________________________________
>>> mesa-dev mailing list
>>> mesa-dev at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list