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

Bas Nieuwenhuizen bas at basnieuwenhuizen.nl
Sun Apr 8 15:15:56 UTC 2018


On Sun, Apr 8, 2018 at 3:29 PM, Rob Clark <robdclark at gmail.com> wrote:
> On Sun, Apr 8, 2018 at 8:58 AM, Bas Nieuwenhuizen
> <bas at basnieuwenhuizen.nl> wrote:
>> On Sun, Apr 8, 2018 at 1:38 PM, Rob Clark <robdclark at gmail.com> wrote:
>>> On Tue, Apr 3, 2018 at 2: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;
>>>
>>> In fact, it seems like deref->mode is unused outside of nir_print and
>>> nir_validate.. for logical addressing we can get the mode from the
>>> deref_var->var at the start of the chain, and deref->mode has no
>>> meaning for physical addressing (where the mode comes from the
>>> pointer).
>>>
>>> So maybe just drop deref->mode?
>>
>> Isn't it still useful with logical addressing in case a var is not
>> immediately available? (think VK_KHR_variable_pointers)
>
> not sure, maybe this should just also use fat-pointers like physical
> addressing does??
>
>> Also I could see this being useful in physical addressing too to avoid
>> all passes working with derefs needing to do the constant folding?
>
> The problem is that you don't necessarily know the type at compile
> time (and in the case where you do, you need to do constant folding to
> figure it out)

So I have two considerations here

1) for vulkan you always know the mode, even when you don't know the var.
2)  In CL the mode can still get annotated in the source program (CL C
non-generic pointers) in cases in which we cannot reasonably figure it
out with just constant folding. In those cases the mode is extra
information that you really lose.

>
> The plan was, in lower_io, to lower load/store_deref with a ptr src to:
>
>   if (fatptr.y == nir_var_global_mem)
>      result = load_global fatptr.x
>   else if (fatptr.y == nir_var_shared)
>      result = load_shared fatptr.x
>   else if ...
>
> And then let constant-folding and DCE hopefully clean that up.
>
> (I think for __constant address space, I'm leaning towards turning
> this into a ubo.. we could turn it in to normal uniform, but adreno
> has uniforms similar to how (iirc) radeon works where they are just
> special read-only 32b registers, so I can't easily do byte addressing
> without generating shifts/masks..)
>
> BR,
> -R
>
>> - Bas
>>
>>
>>>
>>> BR,
>>> -R
>>>
>>>> +   /** 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);
>>>> +
>>>> +      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
>>> _______________________________________________
>>> 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