<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>