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

Bas Nieuwenhuizen bas at basnieuwenhuizen.nl
Sun Apr 8 20:26:02 UTC 2018


On Sun, Apr 8, 2018 at 6:06 PM, Rob Clark <robdclark at gmail.com> wrote:
> On Sun, Apr 8, 2018 at 11:15 AM, Bas Nieuwenhuizen
> <bas at basnieuwenhuizen.nl> wrote:
>> 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.
>
> so, even in cl 1.x, you could do things like 'somefxn(foo ? global_ptr
> : local_ptr)'.. depending on how much we inline all the things, that
> might not get CF'd away.

But something like
__constant int *ptr_value = ...;
store ptr in complex data structure.
__constant int* ptr2 = load from complex data structure.

Without explicitly annotating ptr2 it is unlikely that constant
folding would find that ptr2 is pointing to __constant address space.
Hence removing the modes loses valuable information that you cannot
get back by constant folding. However, if you have a pointer with
unknown mode, we could have a special mode (or mode_all?) and you can
use the uvec2 representation in that case?

>
> I think I'm leaning towards using fat ptrs for the vk case, since I
> guess that is a case where you could always expect
> nir_src_as_const_value() to work, to get the variable mode.  If for no
> other reason than I guess these deref's, if the var is not known,
> start w/ deref_cast, and it would be ugly for deref_cast to have to
> work differently for compute vs vk.  But maybe Jason already has some
> thoughts about it?

I'd like to avoid fat pointers alltogether on AMD since we would not
use it even for CL. a generic pointer is just a uint64_t for us, with
no bitfield in there for the address space.

I think we may need to think a bit more about representation however,
as e.g. for AMD a pointer is typically 64-bits (but we can do e.g.
32-bits for known workgroup pointers), the current deref instructions
return 32-bit, and you want something like a uvec2 as pointer
representation?

>
> BR,
> -R
>
>>>
>>> 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