<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Mar 23, 2018 at 2:15 PM, Karol Herbst <span dir="ltr"><<a href="mailto:kherbst@redhat.com" target="_blank">kherbst@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Fri, Mar 23, 2018 at 10:07 PM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br>
> +list<br>
><br>
> On Fri, Mar 23, 2018 at 1:45 PM, Karol Herbst <<a href="mailto:kherbst@redhat.com">kherbst@redhat.com</a>> wrote:<br>
>><br>
>> On Fri, Mar 23, 2018 at 9:30 PM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
>> wrote:<br>
>> > As I've been rewriting core NIR deref handling, I've been thinking about<br>
>> > this problem quite a bit.  One objective I have is to actually make UBO<br>
>> > and<br>
>> > SSBO access go through derefs instead of just being an offset and index<br>
>> > so<br>
>> > that the compiler can better reason about them.  In particular, I want<br>
>> > to be<br>
>> > able to start doing load/store elimination on SSBOs, SLM, and whatever<br>
>> > CL<br>
>> > has which would be great for everyone's compute performance (GL, Vulkan,<br>
>> > CL,<br>
>> > etc.).<br>
>> ><br>
>> > I would be lying if I said I had a full plan but I do have part of a<br>
>> > plan.<br>
>> > In my patch which adds the deref instructions, I add a new "cast" deref<br>
>> > type<br>
>> > which takes an arbitrary value as it's source and kicks out a deref with<br>
>> > a<br>
>> > type.  Whenever we discover that the source of the cast is actually<br>
>> > another<br>
>> > deref which is compatible (same type etc.), copy propagation gets rid of<br>
>> > the<br>
>> > cast for you.  The idea is that, instead of doing a load_raw(raw_ptr),<br>
>> > you<br>
>> > would do a load((type *)raw_ptr).<br>
>> ><br>
>> > Right now, most of the core NIR optimizations will throw a fit if they<br>
>> > ever<br>
>> > see a cast.  This is intentional because it requires us to manually go<br>
>> > through and handle casts.  This would mean that, at the moment, you<br>
>> > would<br>
>> > have to lower to load_raw intrinsics almost immediately after coming out<br>
>> > of<br>
>> > SPIR-V.<br>
>> ><br>
>><br>
>> Well it gets more fun with OpenCL 2.0 where you can have generic<br>
>> pointer where you only know the type at creation type. You can also<br>
>> declare generic pointers as function inputs in a way, that you never<br>
>> actually know from where you have to load if you only have that one<br>
>> function. So the actual load operation depends on when you create the<br>
>> initial pointer variable (you can cast from X to generic, but not the<br>
>> other way around).<br>
>><br>
>> Which in the end means you can end up with load(generic_ptr) and only<br>
>> following the chain up to it's creation (with function inlining in<br>
>> mind) you know the actual memory target.<br>
><br>
><br>
> Yup.  And there will always be crazy cases where you can't actually follow<br>
> it and you have to emit a pile of code to load different ways depending on<br>
> some bits somewhere that tell you how to load it.  I'm well aware of the<br>
> insanity. :-)  This is part of the reason why I'm glad I'm not trying to<br>
> write an OpenCL 2.0 driver.<br>
><br>
> This insanity is exactly why I'm suggesting the pointer casting.  Sure, you<br>
> may not know the data type until the actual load.  In that case, you end up<br>
> with the cast being right before the load.  If you don't know the storage<br>
> class, maybe you have to switch and do multiple casts based on some bits.<br>
> Alternatively, if you don't know the storage class, we can just let the<br>
> deref mode be 0 for "I don't know". or maybe multiple bits for "these are<br>
> the things it might be".  In any case, I think we can handle it.<br>
><br>
<br>
</div></div>there shouldn't be a situation where we don't know, except when you<br>
don't inline all functions. I think Rob had the idea of fat pointers<br>
where a pointer is a vec2 and the 2nd component contains the actual<br>
pointer type and you end up with a switch over the type to get the<br>
correct storage class. And if the compiler inlines all functions, it<br>
should be able to optimize that switch away.<br><div class="HOEnZb"><div class="h5"></div></div></blockquote><div><br></div><div>Right.  Today, we live in a world where all functions are inlined.  Sadly, I fear that world may come to and end one of these days. :(<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
> It's insane but we need some sort of structure to be able to reason about<br>
> the insanity.  Immediately lowering everything to load_raw is a good way to<br>
> get a driver off the ground.  What it's not so good for is making an<br>
> optimizing compiler that can reason about these crazy pointers and actually<br>
> optimize them.  Lest I sound too negative, I'm 100% fine with taking a short<br>
> path to getting something working now so long as it doesn't cloud up our<br>
> ability to do better in the future.<br>
><br>
>><br>
>> And I think the issue here is not that it is some kind of raw pointer<br>
>> in the patch, but more like an unbound/physical pointer, which doesn't<br>
>> relate to any variable. It is just a value like any other int/long as<br>
>> well.<br>
>><br>
>> > On Fri, Mar 23, 2018 at 12:33 PM, Karol Herbst <<a href="mailto:kherbst@redhat.com">kherbst@redhat.com</a>><br>
>> > wrote:<br>
>> >><br>
>> >> From: Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>><br>
>> >><br>
>> >> An attempt to add physical pointer support to vtn.  I'm not totally<br>
>> >> happy about the handling of logical pointers vs physical pointers.<br>
>> >> So this is really more of an RFS (request for suggestions)<br>
>> >><br>
>> >> v2: treat vec3 types as vec4 when dereferencing<br>
>> >><br>
>> >> Signed-off-by: Karol Herbst <<a href="mailto:kherbst@redhat.com">kherbst@redhat.com</a>><br>
>> >> ---<br>
>> >>  src/compiler/spirv/spirv_to_<wbr>nir.c  |  87 ++++++++---<br>
>> >>  src/compiler/spirv/vtn_<wbr>private.h   |  20 ++-<br>
>> >>  src/compiler/spirv/vtn_<wbr>variables.c | 300<br>
>> >> ++++++++++++++++++++++++++++++<wbr>++-----<br>
>> >>  3 files changed, 347 insertions(+), 60 deletions(-)<br>
>> >><br>
>> >> diff --git a/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
>> >> b/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
>> >> index 334bcab9a82..d58a68f80ef 100644<br>
>> >> --- a/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
>> >> +++ b/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
>> >> @@ -572,6 +572,7 @@ vtn_types_compatible(struct vtn_builder *b,<br>
>> >>               vtn_types_compatible(b, t1->array_element,<br>
>> >> t2->array_element);<br>
>> >><br>
>> >>     case vtn_base_type_pointer:<br>
>> >> +   case vtn_base_type_raw_pointer:<br>
>> >>        return vtn_types_compatible(b, t1->deref, t2->deref);<br>
>> >><br>
>> >>     case vtn_base_type_struct:<br>
>> >> @@ -609,6 +610,7 @@ vtn_type_copy(struct vtn_builder *b, struct<br>
>> >> vtn_type<br>
>> >> *src)<br>
>> >>     case vtn_base_type_matrix:<br>
>> >>     case vtn_base_type_array:<br>
>> >>     case vtn_base_type_pointer:<br>
>> >> +   case vtn_base_type_raw_pointer:<br>
>> >>     case vtn_base_type_image:<br>
>> >>     case vtn_base_type_sampler:<br>
>> >>     case vtn_base_type_sampled_image:<br>
>> >> @@ -939,6 +941,14 @@ vtn_type_layout_std430(struct vtn_builder *b,<br>
>> >> struct<br>
>> >> vtn_type *type,<br>
>> >>        return type;<br>
>> >>     }<br>
>> >><br>
>> >> +   case vtn_base_type_raw_pointer: {<br>
>> >> +      uint32_t comp_size = b->ptr_size / 8;<br>
>> >> +      vtn_assert(comp_size);<br>
>> >> +      *size_out = comp_size;<br>
>> >> +      *align_out = comp_size;<br>
>> >> +      return type;<br>
>> >> +   }<br>
>> >> +<br>
>> >>     case vtn_base_type_vector: {<br>
>> >>        uint32_t comp_size = glsl_get_bit_size(type->type) / 8;<br>
>> >>        assert(type->length > 0 && type->length <= 4);<br>
>> >> @@ -1003,6 +1013,7 @@ vtn_handle_type(struct vtn_builder *b, SpvOp<br>
>> >> opcode,<br>
>> >>        val->type->base_type = vtn_base_type_scalar;<br>
>> >>        val->type->type = glsl_bool_type();<br>
>> >>        val->type->length = 1;<br>
>> >> +      val->type->stride = 4;<br>
>> >>        break;<br>
>> >>     case SpvOpTypeInt: {<br>
>> >>        int bit_size = w[2];<br>
>> >> @@ -1025,6 +1036,7 @@ vtn_handle_type(struct vtn_builder *b, SpvOp<br>
>> >> opcode,<br>
>> >>           vtn_fail("Invalid int bit size");<br>
>> >>        }<br>
>> >>        val->type->length = 1;<br>
>> >> +      val->type->stride = bit_size / 8;<br>
>> >>        break;<br>
>> >>     }<br>
>> >><br>
>> >> @@ -1045,6 +1057,7 @@ vtn_handle_type(struct vtn_builder *b, SpvOp<br>
>> >> opcode,<br>
>> >>           vtn_fail("Invalid float bit size");<br>
>> >>        }<br>
>> >>        val->type->length = 1;<br>
>> >> +      val->type->stride = bit_size / 8;<br>
>> >>        break;<br>
>> >>     }<br>
>> >><br>
>> >> @@ -1061,6 +1074,10 @@ vtn_handle_type(struct vtn_builder *b, SpvOp<br>
>> >> opcode,<br>
>> >>        val->type->type =<br>
>> >> glsl_vector_type(glsl_get_<wbr>base_type(base->type),<br>
>> >> elems);<br>
>> >>        val->type->length = elems;<br>
>> >>        val->type->stride = glsl_get_bit_size(base->type) / 8;<br>
>> >> +      /* special case: vec3 is aligned to vec4 */<br>
>> >> +      if (elems == 3)<br>
>> >> +         elems = 4;<br>
>> >> +      val->type->stride *= elems;<br>
>> >>        val->type->array_element = base;<br>
>> >>        break;<br>
>> >>     }<br>
>> >> @@ -1138,7 +1155,11 @@ vtn_handle_type(struct vtn_builder *b, SpvOp<br>
>> >> opcode,<br>
>> >><br>
>> >>        const char *name = val->name ? val->name : "struct";<br>
>> >><br>
>> >> -      val->type->type = glsl_struct_type(fields, num_fields, name,<br>
>> >> false);<br>
>> >> +      val->type->type = glsl_struct_type(fields, num_fields, name,<br>
>> >> +                                         val->type->packed);<br>
>> >> +      // TODO stride for a struct only matters for kernel shaders,<br>
>> >> where<br>
>> >> +      // cl_size is the right thing.. but still a bit ugly to<br>
>> >> hard-code.<br>
>> >> +      val->type->stride = glsl_get_cl_size(val->type-><wbr>type);<br>
>> >>        break;<br>
>> >>     }<br>
>> >><br>
>> >> @@ -1167,25 +1188,47 @@ vtn_handle_type(struct vtn_builder *b, SpvOp<br>
>> >> opcode,<br>
>> >>        val->type->storage_class = storage_class;<br>
>> >>        val->type->deref = deref_type;<br>
>> >><br>
>> >> -      if (storage_class == SpvStorageClassUniform ||<br>
>> >> -          storage_class == SpvStorageClassStorageBuffer) {<br>
>> >> -         /* These can actually be stored to nir_variables and used as<br>
>> >> SSA<br>
>> >> -          * values so they need a real glsl_type.<br>
>> >> -          */<br>
>> >> -         val->type->type = glsl_vector_type(GLSL_TYPE_<wbr>UINT, 2);<br>
>> >> -      }<br>
>> >> -<br>
>> >> -      if (storage_class == SpvStorageClassWorkgroup &&<br>
>> >> -          b->options->lower_workgroup_<wbr>access_to_offsets) {<br>
>> >> +      // XXX handling the "fake" glsl pointers vs "raw" pointers in<br>
>> >> kernel<br>
>> >> +      // is a bit ugly..  need to understand how "pointers" are used<br>
>> >> in<br>
>> >> vk<br>
>> >> +      // and figure out something better<br>
>> >> +      if (storage_class == SpvStorageClassFunction ||<br>
>> >> +          storage_class == SpvStorageClassUniformConstant ||<br>
>> >> +          storage_class == SpvStorageClassWorkgroup ||<br>
>> >> +          !b->kernel_mode) {<br>
>> >> +         if (storage_class == SpvStorageClassUniform ||<br>
>> >> +             storage_class == SpvStorageClassStorageBuffer) {<br>
>> >> +            /* These can actually be stored to nir_variables and used<br>
>> >> as<br>
>> >> SSA<br>
>> >> +             * values so they need a real glsl_type.<br>
>> >> +             */<br>
>> >> +            val->type->type = glsl_vector_type(GLSL_TYPE_<wbr>UINT, 2);<br>
>> >> +         } else if (storage_class == SpvStorageClassWorkgroup &&<br>
>> >> +                    b->options->lower_workgroup_<wbr>access_to_offsets) {<br>
>> >> +            uint32_t size, align;<br>
>> >> +            val->type->deref = vtn_type_layout_std430(b,<br>
>> >> val->type->deref,<br>
>> >> +                                                      &size, &align);<br>
>> >> +            val->type->length = size;<br>
>> >> +            val->type->align = align;<br>
>> >> +            /* These can actually be stored to nir_variables and used<br>
>> >> as<br>
>> >> SSA<br>
>> >> +             * values so they need a real glsl_type.<br>
>> >> +             */<br>
>> >> +            val->type->type = glsl_uint_type();<br>
>> >> +         }<br>
>> >> +      } else {<br>
>> >> +         vtn_assert(storage_class == SpvStorageClassCrossWorkgroup ||<br>
>> >> +                    storage_class == SpvStorageClassInput);<br>
>> >>           uint32_t size, align;<br>
>> >> +         if (b->ptr_size == 64) {<br>
>> >> +            val->type->type = glsl_uint64_t_type();<br>
>> >> +         } else {<br>
>> >> +            val->type->type = glsl_uint_type();<br>
>> >> +         }<br>
>> >> +         val->type->base_type = vtn_base_type_raw_pointer;<br>
>> >> +         /* pointers can be accessed as array, so set the stride as<br>
>> >> size:<br>
>> >> */<br>
>> >>           val->type->deref = vtn_type_layout_std430(b,<br>
>> >> val->type->deref,<br>
>> >>                                                     &size, &align);<br>
>> >> -         val->type->length = size;<br>
>> >> +#define ALIGN(_v, _d) (((_v) + ((_d) - 1)) & ~((_d) - 1))<br>
>> >> +         val->type->stride = ALIGN(size, align);<br>
>> >>           val->type->align = align;<br>
>> >> -         /* These can actually be stored to nir_variables and used as<br>
>> >> SSA<br>
>> >> -          * values so they need a real glsl_type.<br>
>> >> -          */<br>
>> >> -         val->type->type = glsl_uint_type();<br>
>> >>        }<br>
>> >>        break;<br>
>> >>     }<br>
>> >> @@ -3391,9 +3434,16 @@ vtn_handle_preamble_<wbr>instruction(struct<br>
>> >> vtn_builder<br>
>> >> *b, SpvOp opcode,<br>
>> >>        break;<br>
>> >><br>
>> >>     case SpvOpMemoryModel:<br>
>> >> -      vtn_assert(w[1] == SpvAddressingModelLogical);<br>
>> >> +      vtn_assert(w[1] == SpvAddressingModelLogical ||<br>
>> >> +                 w[1] == SpvAddressingModelPhysical32 ||<br>
>> >> +                 w[1] == SpvAddressingModelPhysical64);<br>
>> >>        vtn_assert(w[2] == SpvMemoryModelSimple ||<br>
>> >> -                 w[2] == SpvMemoryModelGLSL450);<br>
>> >> +                 w[2] == SpvMemoryModelGLSL450 ||<br>
>> >> +                 w[2] == SpvMemoryModelOpenCL);<br>
>> >> +      if (w[1] == SpvAddressingModelPhysical32)<br>
>> >> +         b->ptr_size = 32;<br>
>> >> +      else if (w[1] == SpvAddressingModelPhysical64)<br>
>> >> +         b->ptr_size = 64;<br>
>> >>        break;<br>
>> >><br>
>> >>     case SpvOpEntryPoint: {<br>
>> >> @@ -3780,6 +3830,7 @@ vtn_handle_body_instruction(<wbr>struct vtn_builder<br>
>> >> *b,<br>
>> >> SpvOp opcode,<br>
>> >>           sel_type = glsl_vector_type(GLSL_TYPE_<wbr>BOOL,<br>
>> >> res_val->type->length);<br>
>> >>           break;<br>
>> >>        case vtn_base_type_pointer:<br>
>> >> +      case vtn_base_type_raw_pointer:<br>
>> >>           /* We need to have actual storage for pointer types */<br>
>> >>           vtn_fail_if(res_val->type-><wbr>type == NULL,<br>
>> >>                       "Invalid pointer result type for OpSelect");<br>
>> >> diff --git a/src/compiler/spirv/vtn_<wbr>private.h<br>
>> >> b/src/compiler/spirv/vtn_<wbr>private.h<br>
>> >> index bd273122703..dbfe9eab58a 100644<br>
>> >> --- a/src/compiler/spirv/vtn_<wbr>private.h<br>
>> >> +++ b/src/compiler/spirv/vtn_<wbr>private.h<br>
>> >> @@ -262,7 +262,8 @@ enum vtn_base_type {<br>
>> >>     vtn_base_type_matrix,<br>
>> >>     vtn_base_type_array,<br>
>> >>     vtn_base_type_struct,<br>
>> >> -   vtn_base_type_pointer,<br>
>> >> +   vtn_base_type_pointer,         /* a logical pointer */<br>
>> >> +   vtn_base_type_raw_pointer,     /* a physical pointer */<br>
>> >>     vtn_base_type_image,<br>
>> >>     vtn_base_type_sampler,<br>
>> >>     vtn_base_type_sampled_image,<br>
>> >> @@ -407,12 +408,14 @@ enum vtn_variable_mode {<br>
>> >>     vtn_variable_mode_local,<br>
>> >>     vtn_variable_mode_global,<br>
>> >>     vtn_variable_mode_param,<br>
>> >> +   vtn_variable_mode_const,<br>
>> >>     vtn_variable_mode_ubo,<br>
>> >>     vtn_variable_mode_ssbo,<br>
>> >>     vtn_variable_mode_push_<wbr>constant,<br>
>> >>     vtn_variable_mode_image,<br>
>> >>     vtn_variable_mode_sampler,<br>
>> >>     vtn_variable_mode_workgroup,<br>
>> >> +   vtn_variable_mode_cross_<wbr>workgroup,<br>
>> >>     vtn_variable_mode_input,<br>
>> >>     vtn_variable_mode_output,<br>
>> >>  };<br>
>> >> @@ -588,6 +591,13 @@ struct vtn_builder {<br>
>> >><br>
>> >>     bool has_loop_continue;<br>
>> >><br>
>> >> +   /* pointer size is:<br>
>> >> +    *   AddressingModelLogical:    0    (default)<br>
>> >> +    *   AddressingModelPhysical32: 32<br>
>> >> +    *   AddressingModelPhysical64: 64<br>
>> >> +    */<br>
>> >> +   unsigned ptr_size;<br>
>> >> +<br>
>> >>     bool kernel_mode;<br>
>> >>  };<br>
>> >><br>
>> >> @@ -624,7 +634,8 @@ vtn_push_ssa(struct vtn_builder *b, uint32_t<br>
>> >> value_id,<br>
>> >>               struct vtn_type *type, struct vtn_ssa_value *ssa)<br>
>> >>  {<br>
>> >>     struct vtn_value *val;<br>
>> >> -   if (type->base_type == vtn_base_type_pointer) {<br>
>> >> +   if (type->base_type == vtn_base_type_pointer ||<br>
>> >> +       type->base_type == vtn_base_type_raw_pointer) {<br>
>> >>        val = vtn_push_value(b, value_id, vtn_value_type_pointer);<br>
>> >>        val->pointer = vtn_pointer_from_ssa(b, ssa->def, type);<br>
>> >>     } else {<br>
>> >> @@ -688,6 +699,11 @@ struct vtn_ssa_value *vtn_local_load(struct<br>
>> >> vtn_builder *b, nir_deref_var *src);<br>
>> >>  void vtn_local_store(struct vtn_builder *b, struct vtn_ssa_value *src,<br>
>> >>                       nir_deref_var *dest);<br>
>> >><br>
>> >> +struct vtn_ssa_value *vtn_pointer_load(struct vtn_builder *b,<br>
>> >> +                                       struct vtn_pointer *ptr);<br>
>> >> +void vtn_pointer_store(struct vtn_builder *b, struct vtn_ssa_value<br>
>> >> *src,<br>
>> >> +                       struct vtn_pointer *ptr);<br>
>> >> +<br>
>> >>  struct vtn_ssa_value *<br>
>> >>  vtn_variable_load(struct vtn_builder *b, struct vtn_pointer *src);<br>
>> >><br>
>> >> diff --git a/src/compiler/spirv/vtn_<wbr>variables.c<br>
>> >> b/src/compiler/spirv/vtn_<wbr>variables.c<br>
>> >> index b2897407fb1..af9222d6f4e 100644<br>
>> >> --- a/src/compiler/spirv/vtn_<wbr>variables.c<br>
>> >> +++ b/src/compiler/spirv/vtn_<wbr>variables.c<br>
>> >> @@ -51,6 +51,9 @@ vtn_access_chain_extend(struct vtn_builder *b, struct<br>
>> >> vtn_access_chain *old,<br>
>> >>     unsigned old_len = old ? old->length : 0;<br>
>> >>     chain = vtn_access_chain_create(b, old_len + new_ids);<br>
>> >><br>
>> >> +   if (old)<br>
>> >> +      chain->ptr_as_array = old->ptr_as_array;<br>
>> >> +<br>
>> >>     for (unsigned i = 0; i < old_len; i++)<br>
>> >>        chain->link[i] = old->link[i];<br>
>> >><br>
>> >> @@ -88,11 +91,12 @@ vtn_access_chain_pointer_<wbr>dereference(struct<br>
>> >> vtn_builder *b,<br>
>> >>        vtn_access_chain_extend(b, base->chain, deref_chain->length);<br>
>> >>     struct vtn_type *type = base->type;<br>
>> >><br>
>> >> -   /* OpPtrAccessChain is only allowed on things which support<br>
>> >> variable<br>
>> >> -    * pointers.  For everything else, the client is expected to just<br>
>> >> pass<br>
>> >> us<br>
>> >> -    * the right access chain.<br>
>> >> +   /* We can get an *PtrAccessChain with cl kernels, with first<br>
>> >> element<br>
>> >> +    * of deref chain being literal zero.  But we can't really cope w/<br>
>> >> +    * tacking on another level of ptr_as_array.<br>
>> >>      */<br>
>> >> -   vtn_assert(!deref_chain->ptr_<wbr>as_array);<br>
>> >> +   vtn_assert(!(chain->ptr_as_<wbr>array && deref_chain->ptr_as_array));<br>
>> >> +   chain->ptr_as_array = deref_chain->ptr_as_array;<br>
>> >><br>
>> >>     unsigned start = base->chain ? base->chain->length : 0;<br>
>> >>     for (unsigned i = 0; i < deref_chain->length; i++) {<br>
>> >> @@ -135,6 +139,21 @@ vtn_access_link_as_ssa(struct vtn_builder *b,<br>
>> >> struct<br>
>> >> vtn_access_link link,<br>
>> >>     }<br>
>> >>  }<br>
>> >><br>
>> >> +static struct vtn_access_link<br>
>> >> +vtn_to_access_link(struct vtn_builder *b, uint32_t link_id)<br>
>> >> +{<br>
>> >> +   struct vtn_value *link_val = vtn_untyped_value(b, link_id);<br>
>> >> +   static struct vtn_access_link link;<br>
>> >> +   if (link_val->value_type == vtn_value_type_constant) {<br>
>> >> +      link.mode = vtn_access_mode_literal;<br>
>> >> +      <a href="http://link.id" rel="noreferrer" target="_blank">link.id</a> = link_val->constant->values[0].<wbr>u32[0];<br>
>> >> +   } else {<br>
>> >> +      link.mode = vtn_access_mode_id;<br>
>> >> +      <a href="http://link.id" rel="noreferrer" target="_blank">link.id</a> = link_id;<br>
>> >> +   }<br>
>> >> +   return link;<br>
>> >> +}<br>
>> >> +<br>
>> >>  static nir_ssa_def *<br>
>> >>  vtn_variable_resource_index(<wbr>struct vtn_builder *b, struct vtn_variable<br>
>> >> *var,<br>
>> >>                              nir_ssa_def *desc_array_index)<br>
>> >> @@ -207,6 +226,12 @@ vtn_ssa_offset_pointer_<wbr>dereference(struct<br>
>> >> vtn_builder<br>
>> >> *b,<br>
>> >>              /* You can't have a zero-length OpPtrAccessChain */<br>
>> >>              vtn_assert(deref_chain->length >= 1);<br>
>> >>              desc_arr_idx = vtn_access_link_as_ssa(b,<br>
>> >> deref_chain->link[0], 1);<br>
>> >> +         } else if (!glsl_type_is_struct(type-><wbr>type)) {<br>
>> >> +            /* if we have something that is ptr to simple type, like<br>
>> >> an<br>
>> >> +             * int ptr, then just treat that like an array of length<br>
>> >> 1,<br>
>> >> +             * we just want to deref the zero'th element:<br>
>> >> +             */<br>
>> >> +            desc_arr_idx = nir_imm_int(&b->nb, 0);<br>
>> >>           } else {<br>
>> >>              /* We have a regular non-array SSBO. */<br>
>> >>              desc_arr_idx = NULL;<br>
>> >> @@ -304,7 +329,9 @@ vtn_ssa_offset_pointer_<wbr>dereference(struct<br>
>> >> vtn_builder<br>
>> >> *b,<br>
>> >>        case GLSL_TYPE_FLOAT:<br>
>> >>        case GLSL_TYPE_FLOAT16:<br>
>> >>        case GLSL_TYPE_DOUBLE:<br>
>> >> -      case GLSL_TYPE_BOOL:<br>
>> >> +      case GLSL_TYPE_BOOL: {<br>
>> >> +         break;<br>
>> >> +      }<br>
>> >>        case GLSL_TYPE_ARRAY: {<br>
>> >>           nir_ssa_def *elem_offset =<br>
>> >>              vtn_access_link_as_ssa(b, deref_chain->link[idx],<br>
>> >> type->stride);<br>
>> >> @@ -336,6 +363,98 @@ vtn_ssa_offset_pointer_<wbr>dereference(struct<br>
>> >> vtn_builder<br>
>> >> *b,<br>
>> >>     return ptr;<br>
>> >>  }<br>
>> >><br>
>> >> +static struct vtn_pointer *<br>
>> >> +vtn_ssa_raw_pointer_<wbr>dereference(struct vtn_builder *b,<br>
>> >> +                                struct vtn_pointer *base,<br>
>> >> +                                struct vtn_access_chain *deref_chain)<br>
>> >> +{<br>
>> >> +   nir_ssa_def *offset = nir_imm_int(&b->nb, 0);<br>
>> >> +   struct vtn_type *type = base->type;<br>
>> >> +<br>
>> >> +<br>
>> >> +   vtn_assert(type);<br>
>> >> +<br>
>> >> +   unsigned idx = 0;<br>
>> >> +<br>
>> >> +   /* For the *PtrAccessChain deref instructions, the first entry in<br>
>> >> +    * the deref chain is deref'ing the ptr as an array, ie. if you<br>
>> >> +    * have "struct foo *f" then it can be deref'd as either "f->blah",<br>
>> >> +    * which is equiv to "f[0].blah", or "f[n].blah".<br>
>> >> +    */<br>
>> >> +   if (deref_chain->ptr_as_array) {<br>
>> >> +      nir_ssa_def *elem_offset =<br>
>> >> +         vtn_access_link_as_ssa(b, deref_chain->link[idx],<br>
>> >> type->stride);<br>
>> >> +      offset = nir_iadd(&b->nb, offset, elem_offset);<br>
>> >> +      idx++;<br>
>> >> +   }<br>
>> >> +<br>
>> >> +   /* TODO this can probably be refactored out into helper?  Nearly<br>
>> >> +    * the same as in vtn_ssa_offset_pointer_<wbr>dereference() and perhaps<br>
>> >> +    * elsewhere..<br>
>> >> +    *<br>
>> >> +    * Note that the type here in the switch is of what the pointer<br>
>> >> +    * points to, ie. if the base type is uint, we are dereferencing<br>
>> >> +    * (possibly as an array) a uint* pointer.<br>
>> >> +    */<br>
>> >> +   for (; idx < deref_chain->length; idx++) {<br>
>> >> +      switch (glsl_get_base_type(type-><wbr>type)) {<br>
>> >> +      case GLSL_TYPE_UINT:<br>
>> >> +      case GLSL_TYPE_INT:<br>
>> >> +      case GLSL_TYPE_UINT16:<br>
>> >> +      case GLSL_TYPE_INT16:<br>
>> >> +      case GLSL_TYPE_UINT8:<br>
>> >> +      case GLSL_TYPE_INT8:<br>
>> >> +      case GLSL_TYPE_UINT64:<br>
>> >> +      case GLSL_TYPE_INT64:<br>
>> >> +      case GLSL_TYPE_FLOAT:<br>
>> >> +      case GLSL_TYPE_FLOAT16:<br>
>> >> +      case GLSL_TYPE_DOUBLE:<br>
>> >> +      case GLSL_TYPE_BOOL:<br>
>> >> +      case GLSL_TYPE_ARRAY: {<br>
>> >> +         nir_ssa_def *elem_offset =<br>
>> >> +            vtn_access_link_as_ssa(b, deref_chain->link[idx],<br>
>> >> type->stride);<br>
>> >> +         offset = nir_iadd(&b->nb, offset, elem_offset);<br>
>> >> +         if (type->array_element) {<br>
>> >> +            type = type->array_element;<br>
>> >> +         } else {<br>
>> >> +            vtn_assert(idx == (deref_chain->length - 1));<br>
>> >> +         }<br>
>> >> +         break;<br>
>> >> +      }<br>
>> >> +<br>
>> >> +      case GLSL_TYPE_STRUCT: {<br>
>> >> +         vtn_assert(deref_chain->link[<wbr>idx].mode ==<br>
>> >> vtn_access_mode_literal);<br>
>> >> +         unsigned member = deref_chain->link[idx].id;<br>
>> >> +         nir_ssa_def *mem_offset = nir_imm_int(&b->nb,<br>
>> >> type->offsets[member]);<br>
>> >> +         offset = nir_iadd(&b->nb, offset, mem_offset);<br>
>> >> +         type = type->members[member];<br>
>> >> +         break;<br>
>> >> +      }<br>
>> >> +<br>
>> >> +      default:<br>
>> >> +         vtn_fail("Invalid type for deref");<br>
>> >> +      }<br>
>> >> +   }<br>
>> >> +<br>
>> >> +   /* at this point, offset is 32b, but pointer can be either 32b or<br>
>> >> 64b<br>
>> >> +    * depending on memory model:<br>
>> >> +    */<br>
>> >> +   if (b->ptr_size == 64) {<br>
>> >> +      offset = nir_u2u64(&b->nb, offset);<br>
>> >> +   }<br>
>> >> +<br>
>> >> +   /* add pointer address to calculated offset: */<br>
>> >> +   if (base->offset)<br>
>> >> +      offset = nir_iadd(&b->nb, offset, base->offset);<br>
>> >> +<br>
>> >> +   struct vtn_pointer *ptr = rzalloc(b, struct vtn_pointer);<br>
>> >> +   ptr->mode = base->mode;<br>
>> >> +   ptr->type = base->type;<br>
>> >> +   ptr->offset = offset;<br>
>> >> +<br>
>> >> +   return ptr;<br>
>> >> +}<br>
>> >> +<br>
>> >>  /* Dereference the given base pointer by the access chain */<br>
>> >>  static struct vtn_pointer *<br>
>> >>  vtn_pointer_dereference(struct vtn_builder *b,<br>
>> >> @@ -344,6 +463,8 @@ vtn_pointer_dereference(struct vtn_builder *b,<br>
>> >>  {<br>
>> >>     if (vtn_pointer_uses_ssa_offset(<wbr>b, base)) {<br>
>> >>        return vtn_ssa_offset_pointer_<wbr>dereference(b, base, deref_chain);<br>
>> >> +   } else if (base->ptr_type->base_type == vtn_base_type_raw_pointer)<br>
>> >> {<br>
>> >> +      return vtn_ssa_raw_pointer_<wbr>dereference(b, base, deref_chain);<br>
>> >>     } else {<br>
>> >>        return vtn_access_chain_pointer_<wbr>dereference(b, base,<br>
>> >> deref_chain);<br>
>> >>     }<br>
>> >> @@ -373,7 +494,8 @@ vtn_pointer_for_variable(<wbr>struct vtn_builder *b,<br>
>> >><br>
>> >>     pointer->mode = var->mode;<br>
>> >>     pointer->type = var->type;<br>
>> >> -   vtn_assert(ptr_type->base_type == vtn_base_type_pointer);<br>
>> >> +   vtn_assert(ptr_type->base_type == vtn_base_type_pointer ||<br>
>> >> +              ptr_type->base_type == vtn_base_type_raw_pointer);<br>
>> >>     vtn_assert(ptr_type->deref-><wbr>type == var->type->type);<br>
>> >>     pointer->ptr_type = ptr_type;<br>
>> >>     pointer->var = var;<br>
>> >> @@ -384,6 +506,12 @@ vtn_pointer_for_variable(<wbr>struct vtn_builder *b,<br>
>> >>  nir_deref_var *<br>
>> >>  vtn_pointer_to_deref(struct vtn_builder *b, struct vtn_pointer *ptr)<br>
>> >>  {<br>
>> >> +   /* once you've chased a pointer, you no longer really have a var,<br>
>> >> +    * so this case is handled differently<br>
>> >> +    */<br>
>> >> +   if (!ptr->var)<br>
>> >> +      return NULL;<br>
>> >> +<br>
>> >>     /* Do on-the-fly copy propagation for samplers. */<br>
>> >>     if (ptr->var->copy_prop_sampler)<br>
>> >>        return vtn_pointer_to_deref(b, ptr->var->copy_prop_sampler);<br>
>> >> @@ -408,7 +536,19 @@ vtn_pointer_to_deref(struct vtn_builder *b, struct<br>
>> >> vtn_pointer *ptr)<br>
>> >>     nir_deref *tail = &deref_var->deref;<br>
>> >>     nir_variable **members = ptr->var->members;<br>
>> >><br>
>> >> -   for (unsigned i = 0; i < chain->length; i++) {<br>
>> >> +   unsigned i = 0;<br>
>> >> +   if (chain->ptr_as_array) {<br>
>> >> +      /* We can't currently handle this in a nir deref chain.  Perhaps<br>
>> >> +       * a new type of deref node is needed?  But we can at least<br>
>> >> handle<br>
>> >> +       * the case where the first deref link is literal zero by<br>
>> >> skipping<br>
>> >> +       * it.<br>
>> >> +       */<br>
>> >> +      vtn_assert(chain->link[0].mode == vtn_access_mode_literal);<br>
>> >> +      vtn_assert(chain->link[0].id == 0);<br>
>> >> +      i++;<br>
>> >> +   }<br>
>> >> +<br>
>> >> +   for (; i < chain->length; i++) {<br>
>> >>        enum glsl_base_type base_type =<br>
>> >> glsl_get_base_type(deref_type-<wbr>>type);<br>
>> >>        switch (base_type) {<br>
>> >>        case GLSL_TYPE_UINT:<br>
>> >> @@ -598,6 +738,49 @@ vtn_local_store(struct vtn_builder *b, struct<br>
>> >> vtn_ssa_value *src,<br>
>> >>     }<br>
>> >>  }<br>
>> >><br>
>> >> +struct vtn_ssa_value *<br>
>> >> +vtn_pointer_load(struct vtn_builder *b, struct vtn_pointer *ptr)<br>
>> >> +{<br>
>> >> +   const struct glsl_type *type = ptr->type->type;<br>
>> >> +   struct vtn_ssa_value *val = vtn_create_ssa_value(b, type);<br>
>> >> +   nir_intrinsic_op op = nir_intrinsic_load_global;<br>
>> >> +<br>
>> >> +   vtn_assert(ptr->offset);<br>
>> >> +<br>
>> >> +   nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b-><wbr>shader,<br>
>> >> op);<br>
>> >> +   intrin->num_components = glsl_get_vector_elements(type)<wbr>;<br>
>> >> +   intrin->src[0] = nir_src_for_ssa(ptr->offset);<br>
>> >> +<br>
>> >> +   nir_ssa_dest_init(&intrin-><wbr>instr, &intrin->dest,<br>
>> >> +                     intrin->num_components,<br>
>> >> +                     glsl_get_bit_size(type),<br>
>> >> +                     NULL);<br>
>> >> +   val->def = &intrin->dest.ssa;<br>
>> >> +<br>
>> >> +   nir_builder_instr_insert(&b-><wbr>nb, &intrin->instr);<br>
>> >> +<br>
>> >> +   return val;<br>
>> >> +}<br>
>> >> +<br>
>> >> +void<br>
>> >> +vtn_pointer_store(struct vtn_builder *b, struct vtn_ssa_value *src,<br>
>> >> +                  struct vtn_pointer *ptr)<br>
>> >> +{<br>
>> >> +   const struct glsl_type *type = ptr->type->type;<br>
>> >> +   nir_intrinsic_op op = nir_intrinsic_store_global;<br>
>> >> +<br>
>> >> +   vtn_assert(ptr->offset);<br>
>> >> +<br>
>> >> +   nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b-><wbr>shader,<br>
>> >> op);<br>
>> >> +   intrin->num_components = MAX2(1, glsl_get_vector_elements(type)<wbr>);<br>
>> >> +   intrin->src[0] = nir_src_for_ssa(src->def);<br>
>> >> +   intrin->src[1] = nir_src_for_ssa(ptr->offset);<br>
>> >> +<br>
>> >> +   nir_intrinsic_set_write_mask(<wbr>intrin, (1 << intrin->num_components)<br>
>> >> -<br>
>> >> 1);<br>
>> >> +<br>
>> >> +   nir_builder_instr_insert(&b-><wbr>nb, &intrin->instr);<br>
>> >> +}<br>
>> >> +<br>
>> >>  nir_ssa_def *<br>
>> >>  vtn_pointer_to_offset(struct vtn_builder *b, struct vtn_pointer *ptr,<br>
>> >>                        nir_ssa_def **index_out, unsigned *end_idx_out)<br>
>> >> @@ -1004,20 +1187,33 @@ _vtn_variable_load_store(<wbr>struct vtn_builder *b,<br>
>> >> bool load,<br>
>> >>     case GLSL_TYPE_FLOAT:<br>
>> >>     case GLSL_TYPE_FLOAT16:<br>
>> >>     case GLSL_TYPE_BOOL:<br>
>> >> -   case GLSL_TYPE_DOUBLE:<br>
>> >> -      /* At this point, we have a scalar, vector, or matrix so we know<br>
>> >> that<br>
>> >> -       * there cannot be any structure splitting still in the way.  By<br>
>> >> -       * stopping at the matrix level rather than the vector level, we<br>
>> >> -       * ensure that matrices get loaded in the optimal way even if<br>
>> >> they<br>
>> >> -       * are storred row-major in a UBO.<br>
>> >> -       */<br>
>> >> -      if (load) {<br>
>> >> -         *inout = vtn_local_load(b, vtn_pointer_to_deref(b, ptr));<br>
>> >> +   case GLSL_TYPE_DOUBLE: {<br>
>> >> +      nir_deref_var *deref_var = vtn_pointer_to_deref(b, ptr);<br>
>> >> +<br>
>> >> +      if (deref_var) {<br>
>> >> +         /* At this point, we have a scalar, vector, or matrix so we<br>
>> >> know<br>
>> >> that<br>
>> >> +          * there cannot be any structure splitting still in the way.<br>
>> >> By<br>
>> >> +          * stopping at the matrix level rather than the vector level,<br>
>> >> we<br>
>> >> +          * ensure that matrices get loaded in the optimal way even if<br>
>> >> they<br>
>> >> +          * are storred row-major in a UBO.<br>
>> >> +          */<br>
>> >> +         if (load) {<br>
>> >> +            *inout = vtn_local_load(b, deref_var);<br>
>> >> +         } else {<br>
>> >> +            vtn_local_store(b, *inout, deref_var);<br>
>> >> +         }<br>
>> >>        } else {<br>
>> >> -         vtn_local_store(b, *inout, vtn_pointer_to_deref(b, ptr));<br>
>> >> +         /* If deref'ing a raw pointer, we don't have a variable to go<br>
>> >> along<br>
>> >> +          * with it.  Just directly generate load/store_global<br>
>> >> intrinsics:<br>
>> >> +          */<br>
>> >> +         if (load) {<br>
>> >> +            *inout = vtn_pointer_load(b, ptr);<br>
>> >> +         } else {<br>
>> >> +            vtn_pointer_store(b, *inout, ptr);<br>
>> >> +         }<br>
>> >>        }<br>
>> >>        return;<br>
>> >> -<br>
>> >> +   }<br>
>> >>     case GLSL_TYPE_ARRAY:<br>
>> >>     case GLSL_TYPE_STRUCT: {<br>
>> >>        unsigned elems = glsl_get_length(ptr->type-><wbr>type);<br>
>> >> @@ -1052,6 +1248,8 @@ vtn_variable_load(struct vtn_builder *b, struct<br>
>> >> vtn_pointer *src)<br>
>> >>  {<br>
>> >>     if (vtn_pointer_is_external_<wbr>block(b, src)) {<br>
>> >>        return vtn_block_load(b, src);<br>
>> >> +   } else if (!src->var) {<br>
>> >> +      return vtn_pointer_load(b, src);<br>
>> >>     } else {<br>
>> >>        struct vtn_ssa_value *val = NULL;<br>
>> >>        _vtn_variable_load_store(b, true, src, &val);<br>
>> >> @@ -1065,8 +1263,11 @@ vtn_variable_store(struct vtn_builder *b, struct<br>
>> >> vtn_ssa_value *src,<br>
>> >>  {<br>
>> >>     if (vtn_pointer_is_external_<wbr>block(b, dest)) {<br>
>> >>        vtn_assert(dest->mode == vtn_variable_mode_ssbo ||<br>
>> >> -                 dest->mode == vtn_variable_mode_workgroup);<br>
>> >> +                 dest->mode == vtn_variable_mode_workgroup ||<br>
>> >> +                 dest->mode == vtn_variable_mode_param);<br>
>> >>        vtn_block_store(b, src, dest);<br>
>> >> +   } else if (!dest->var) {<br>
>> >> +      vtn_pointer_store(b, src, dest);<br>
>> >>     } else {<br>
>> >>        _vtn_variable_load_store(b, false, dest, &src);<br>
>> >>     }<br>
>> >> @@ -1608,6 +1809,7 @@ static enum vtn_variable_mode<br>
>> >>  vtn_storage_class_to_mode(<wbr>struct vtn_builder *b,<br>
>> >>                            SpvStorageClass class,<br>
>> >>                            struct vtn_type *interface_type,<br>
>> >> +                          bool has_initializer,<br>
>> >>                            nir_variable_mode *nir_mode_out)<br>
>> >>  {<br>
>> >>     enum vtn_variable_mode mode;<br>
>> >> @@ -1635,8 +1837,12 @@ vtn_storage_class_to_mode(<wbr>struct vtn_builder *b,<br>
>> >>        } else if (glsl_type_is_sampler(<wbr>interface_type->type)) {<br>
>> >>           mode = vtn_variable_mode_sampler;<br>
>> >>           nir_mode = nir_var_uniform;<br>
>> >> +      } else if (has_initializer) {<br>
>> >> +         mode = vtn_variable_mode_const;<br>
>> >> +         nir_mode = nir_var_global;<br>
>> >>        } else {<br>
>> >> -         vtn_fail("Invalid uniform constant variable type");<br>
>> >> +         mode = vtn_variable_mode_push_<wbr>constant;<br>
>> >> +         nir_mode = nir_var_uniform;<br>
>> >>        }<br>
>> >>        break;<br>
>> >>     case SpvStorageClassPushConstant:<br>
>> >> @@ -1664,6 +1870,10 @@ vtn_storage_class_to_mode(<wbr>struct vtn_builder *b,<br>
>> >>        nir_mode = nir_var_shared;<br>
>> >>        break;<br>
>> >>     case SpvStorageClassCrossWorkgroup:<br>
>> >> +      mode = vtn_variable_mode_cross_<wbr>workgroup;<br>
>> >> +      // TODO do we want a new nir_mode for raw pointers?<br>
>> >> +      nir_mode = nir_var_global;<br>
>> >> +      break;<br>
>> >>     case SpvStorageClassGeneric:<br>
>> >>     case SpvStorageClassAtomicCounter:<br>
>> >>     default:<br>
>> >> @@ -1692,7 +1902,14 @@ vtn_pointer_to_ssa(struct vtn_builder *b, struct<br>
>> >> vtn_pointer *ptr)<br>
>> >>        struct vtn_access_chain chain = {<br>
>> >>           .length = 0,<br>
>> >>        };<br>
>> >> -      ptr = vtn_ssa_offset_pointer_<wbr>dereference(b, ptr, &chain);<br>
>> >> +<br>
>> >> +      if (vtn_pointer_uses_ssa_offset(<wbr>b, ptr)) {<br>
>> >> +         ptr = vtn_ssa_offset_pointer_<wbr>dereference(b, ptr, &chain);<br>
>> >> +      } else if (ptr->ptr_type->base_type ==<br>
>> >> vtn_base_type_raw_pointer) {<br>
>> >> +         ptr = vtn_ssa_raw_pointer_<wbr>dereference(b, ptr, &chain);<br>
>> >> +      } else {<br>
>> >> +         vtn_fail("unhandled");<br>
>> >> +      }<br>
>> >>     }<br>
>> >><br>
>> >>     vtn_assert(ptr->offset);<br>
>> >> @@ -1710,27 +1927,34 @@ struct vtn_pointer *<br>
>> >>  vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,<br>
>> >>                       struct vtn_type *ptr_type)<br>
>> >>  {<br>
>> >> -   vtn_assert(ssa->num_components <= 2 && ssa->bit_size == 32);<br>
>> >> -   vtn_assert(ptr_type->base_type == vtn_base_type_pointer);<br>
>> >> +   vtn_assert(ptr_type->base_type == vtn_base_type_pointer ||<br>
>> >> +              ptr_type->base_type == vtn_base_type_raw_pointer);<br>
>> >>     vtn_assert(ptr_type->deref-><wbr>base_type != vtn_base_type_pointer);<br>
>> >>     /* This pointer type needs to have actual storage */<br>
>> >>     vtn_assert(ptr_type->type);<br>
>> >><br>
>> >>     struct vtn_pointer *ptr = rzalloc(b, struct vtn_pointer);<br>
>> >>     ptr->mode = vtn_storage_class_to_mode(b, ptr_type->storage_class,<br>
>> >> -                                         ptr_type, NULL);<br>
>> >> +                                         ptr_type, false, NULL);<br>
>> >> +<br>
>> >> +   if (ptr_type->base_type == vtn_base_type_raw_pointer) {<br>
>> >> +      vtn_assert(ssa->num_components == 1 && ssa->bit_size ==<br>
>> >> b->ptr_size);<br>
>> >> +   } else {<br>
>> >> +      vtn_assert(ssa->num_components <= 2 && ssa->bit_size == 32);<br>
>> >> +   }<br>
>> >> +<br>
>> >>     ptr->type = ptr_type->deref;<br>
>> >>     ptr->ptr_type = ptr_type;<br>
>> >><br>
>> >>     if (ssa->num_components > 1) {<br>
>> >>        vtn_assert(ssa->num_components == 2);<br>
>> >>        vtn_assert(ptr->mode == vtn_variable_mode_ubo ||<br>
>> >> -                 ptr->mode == vtn_variable_mode_ssbo);<br>
>> >> +                 ptr->mode == vtn_variable_mode_ssbo ||<br>
>> >> +                 ptr->mode == vtn_variable_mode_global);<br>
>> >>        ptr->block_index = nir_channel(&b->nb, ssa, 0);<br>
>> >>        ptr->offset = nir_channel(&b->nb, ssa, 1);<br>
>> >>     } else {<br>
>> >>        vtn_assert(ssa->num_components == 1);<br>
>> >> -      vtn_assert(ptr->mode == vtn_variable_mode_workgroup);<br>
>> >>        ptr->block_index = NULL;<br>
>> >>        ptr->offset = ssa;<br>
>> >>     }<br>
>> >> @@ -1761,7 +1985,8 @@ vtn_create_variable(struct vtn_builder *b, struct<br>
>> >> vtn_value *val,<br>
>> >>                      struct vtn_type *ptr_type, SpvStorageClass<br>
>> >> storage_class,<br>
>> >>                      nir_constant *initializer)<br>
>> >>  {<br>
>> >> -   vtn_assert(ptr_type->base_type == vtn_base_type_pointer);<br>
>> >> +   vtn_assert(ptr_type->base_type == vtn_base_type_pointer ||<br>
>> >> +              ptr_type->base_type == vtn_base_type_raw_pointer);<br>
>> >>     struct vtn_type *type = ptr_type->deref;<br>
>> >><br>
>> >>     struct vtn_type *without_array = type;<br>
>> >> @@ -1770,7 +1995,8 @@ vtn_create_variable(struct vtn_builder *b, struct<br>
>> >> vtn_value *val,<br>
>> >><br>
>> >>     enum vtn_variable_mode mode;<br>
>> >>     nir_variable_mode nir_mode;<br>
>> >> -   mode = vtn_storage_class_to_mode(b, storage_class, without_array,<br>
>> >> &nir_mode);<br>
>> >> +   mode = vtn_storage_class_to_mode(b, storage_class, without_array,<br>
>> >> +                                    !!initializer, &nir_mode);<br>
>> >><br>
>> >>     switch (mode) {<br>
>> >>     case vtn_variable_mode_ubo:<br>
>> >> @@ -1933,6 +2159,7 @@ vtn_create_variable(struct vtn_builder *b, struct<br>
>> >> vtn_value *val,<br>
>> >>     case vtn_variable_mode_ubo:<br>
>> >>     case vtn_variable_mode_ssbo:<br>
>> >>     case vtn_variable_mode_push_<wbr>constant:<br>
>> >> +   case vtn_variable_mode_cross_<wbr>workgroup:<br>
>> >>        /* These don't need actual variables. */<br>
>> >>        break;<br>
>> >>     }<br>
>> >> @@ -2031,25 +2258,18 @@ vtn_handle_variables(struct vtn_builder *b,<br>
>> >> SpvOp<br>
>> >> opcode,<br>
>> >>     case SpvOpAccessChain:<br>
>> >>     case SpvOpPtrAccessChain:<br>
>> >>     case SpvOpInBoundsAccessChain: {<br>
>> >> +      struct vtn_type *ptr_type = vtn_value(b, w[1],<br>
>> >> vtn_value_type_type)->type;<br>
>> >> +      struct vtn_value *base_val = vtn_untyped_value(b, w[3]);<br>
>> >>        struct vtn_access_chain *chain = vtn_access_chain_create(b,<br>
>> >> count -<br>
>> >> 4);<br>
>> >> -      chain->ptr_as_array = (opcode == SpvOpPtrAccessChain);<br>
>> >> +      chain->ptr_as_array = (opcode == SpvOpPtrAccessChain) ||<br>
>> >> +                            (opcode == SpvOpInBoundsPtrAccessChain);<br>
>> >><br>
>> >>        unsigned idx = 0;<br>
>> >>        for (int i = 4; i < count; i++) {<br>
>> >> -         struct vtn_value *link_val = vtn_untyped_value(b, w[i]);<br>
>> >> -         if (link_val->value_type == vtn_value_type_constant) {<br>
>> >> -            chain->link[idx].mode = vtn_access_mode_literal;<br>
>> >> -            chain->link[idx].id =<br>
>> >> link_val->constant->values[0].<wbr>u32[0];<br>
>> >> -         } else {<br>
>> >> -            chain->link[idx].mode = vtn_access_mode_id;<br>
>> >> -            chain->link[idx].id = w[i];<br>
>> >> -<br>
>> >> -         }<br>
>> >> +         chain->link[idx] = vtn_to_access_link(b, w[i]);<br>
>> >>           idx++;<br>
>> >>        }<br>
>> >><br>
>> >> -      struct vtn_type *ptr_type = vtn_value(b, w[1],<br>
>> >> vtn_value_type_type)->type;<br>
>> >> -      struct vtn_value *base_val = vtn_untyped_value(b, w[3]);<br>
>> >>        if (base_val->value_type == vtn_value_type_sampled_image) {<br>
>> >>           /* This is rather insane.  SPIR-V allows you to use<br>
>> >> OpSampledImage<br>
>> >>            * to combine an array of images with a single sampler to get<br>
>> >> an<br>
>> >> --<br>
>> >> 2.14.3<br>
>> >><br>
>> >> ______________________________<wbr>_________________<br>
>> >> mesa-dev mailing list<br>
>> >> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
>> >> <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/mesa-dev</a><br>
>> ><br>
>> ><br>
><br>
><br>
</div></div></blockquote></div><br></div></div>