1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Jason Ekstrand (jason@jlekstrand.net)
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "vtn_private.h"
29bf215546Sopenharmony_ci#include "spirv_info.h"
30bf215546Sopenharmony_ci#include "nir_deref.h"
31bf215546Sopenharmony_ci#include <vulkan/vulkan_core.h>
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_cistatic struct vtn_pointer*
34bf215546Sopenharmony_civtn_align_pointer(struct vtn_builder *b, struct vtn_pointer *ptr,
35bf215546Sopenharmony_ci                  unsigned alignment)
36bf215546Sopenharmony_ci{
37bf215546Sopenharmony_ci   if (alignment == 0)
38bf215546Sopenharmony_ci      return ptr;
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci   if (!util_is_power_of_two_nonzero(alignment)) {
41bf215546Sopenharmony_ci      vtn_warn("Provided alignment is not a power of two");
42bf215546Sopenharmony_ci      alignment = 1 << (ffs(alignment) - 1);
43bf215546Sopenharmony_ci   }
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci   /* If this pointer doesn't have a deref, bail.  This either means we're
46bf215546Sopenharmony_ci    * using the old offset+alignment pointers which don't support carrying
47bf215546Sopenharmony_ci    * alignment information or we're a pointer that is below the block
48bf215546Sopenharmony_ci    * boundary in our access chain in which case alignment is meaningless.
49bf215546Sopenharmony_ci    */
50bf215546Sopenharmony_ci   if (ptr->deref == NULL)
51bf215546Sopenharmony_ci      return ptr;
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   /* Ignore alignment information on logical pointers.  This way, we don't
54bf215546Sopenharmony_ci    * trip up drivers with unnecessary casts.
55bf215546Sopenharmony_ci    */
56bf215546Sopenharmony_ci   nir_address_format addr_format = vtn_mode_to_address_format(b, ptr->mode);
57bf215546Sopenharmony_ci   if (addr_format == nir_address_format_logical)
58bf215546Sopenharmony_ci      return ptr;
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   struct vtn_pointer *copy = ralloc(b, struct vtn_pointer);
61bf215546Sopenharmony_ci   *copy = *ptr;
62bf215546Sopenharmony_ci   copy->deref = nir_alignment_deref_cast(&b->nb, ptr->deref, alignment, 0);
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   return copy;
65bf215546Sopenharmony_ci}
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_cistatic void
68bf215546Sopenharmony_ciptr_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
69bf215546Sopenharmony_ci                  const struct vtn_decoration *dec, void *void_ptr)
70bf215546Sopenharmony_ci{
71bf215546Sopenharmony_ci   struct vtn_pointer *ptr = void_ptr;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   switch (dec->decoration) {
74bf215546Sopenharmony_ci   case SpvDecorationNonUniformEXT:
75bf215546Sopenharmony_ci      ptr->access |= ACCESS_NON_UNIFORM;
76bf215546Sopenharmony_ci      break;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   default:
79bf215546Sopenharmony_ci      break;
80bf215546Sopenharmony_ci   }
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_cistruct access_align {
84bf215546Sopenharmony_ci   enum gl_access_qualifier access;
85bf215546Sopenharmony_ci   uint32_t alignment;
86bf215546Sopenharmony_ci};
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_cistatic void
89bf215546Sopenharmony_ciaccess_align_cb(struct vtn_builder *b, struct vtn_value *val, int member,
90bf215546Sopenharmony_ci                const struct vtn_decoration *dec, void *void_ptr)
91bf215546Sopenharmony_ci{
92bf215546Sopenharmony_ci   struct access_align *aa = void_ptr;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   switch (dec->decoration) {
95bf215546Sopenharmony_ci   case SpvDecorationAlignment:
96bf215546Sopenharmony_ci      aa->alignment = dec->operands[0];
97bf215546Sopenharmony_ci      break;
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   case SpvDecorationNonUniformEXT:
100bf215546Sopenharmony_ci      aa->access |= ACCESS_NON_UNIFORM;
101bf215546Sopenharmony_ci      break;
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   default:
104bf215546Sopenharmony_ci      break;
105bf215546Sopenharmony_ci   }
106bf215546Sopenharmony_ci}
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_cistatic struct vtn_pointer*
109bf215546Sopenharmony_civtn_decorate_pointer(struct vtn_builder *b, struct vtn_value *val,
110bf215546Sopenharmony_ci                     struct vtn_pointer *ptr)
111bf215546Sopenharmony_ci{
112bf215546Sopenharmony_ci   struct access_align aa = { 0, };
113bf215546Sopenharmony_ci   vtn_foreach_decoration(b, val, access_align_cb, &aa);
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   ptr = vtn_align_pointer(b, ptr, aa.alignment);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   /* If we're adding access flags, make a copy of the pointer.  We could
118bf215546Sopenharmony_ci    * probably just OR them in without doing so but this prevents us from
119bf215546Sopenharmony_ci    * leaking them any further than actually specified in the SPIR-V.
120bf215546Sopenharmony_ci    */
121bf215546Sopenharmony_ci   if (aa.access & ~ptr->access) {
122bf215546Sopenharmony_ci      struct vtn_pointer *copy = ralloc(b, struct vtn_pointer);
123bf215546Sopenharmony_ci      *copy = *ptr;
124bf215546Sopenharmony_ci      copy->access |= aa.access;
125bf215546Sopenharmony_ci      return copy;
126bf215546Sopenharmony_ci   }
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   return ptr;
129bf215546Sopenharmony_ci}
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_cistruct vtn_value *
132bf215546Sopenharmony_civtn_push_pointer(struct vtn_builder *b, uint32_t value_id,
133bf215546Sopenharmony_ci                 struct vtn_pointer *ptr)
134bf215546Sopenharmony_ci{
135bf215546Sopenharmony_ci   struct vtn_value *val = vtn_push_value(b, value_id, vtn_value_type_pointer);
136bf215546Sopenharmony_ci   val->pointer = vtn_decorate_pointer(b, val, ptr);
137bf215546Sopenharmony_ci   return val;
138bf215546Sopenharmony_ci}
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_civoid
141bf215546Sopenharmony_civtn_copy_value(struct vtn_builder *b, uint32_t src_value_id,
142bf215546Sopenharmony_ci               uint32_t dst_value_id)
143bf215546Sopenharmony_ci{
144bf215546Sopenharmony_ci   struct vtn_value *src = vtn_untyped_value(b, src_value_id);
145bf215546Sopenharmony_ci   struct vtn_value *dst = vtn_untyped_value(b, dst_value_id);
146bf215546Sopenharmony_ci   struct vtn_value src_copy = *src;
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   vtn_fail_if(dst->value_type != vtn_value_type_invalid,
149bf215546Sopenharmony_ci               "SPIR-V id %u has already been written by another instruction",
150bf215546Sopenharmony_ci               dst_value_id);
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   vtn_fail_if(dst->type->id != src->type->id,
153bf215546Sopenharmony_ci               "Result Type must equal Operand type");
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   src_copy.name = dst->name;
156bf215546Sopenharmony_ci   src_copy.decoration = dst->decoration;
157bf215546Sopenharmony_ci   src_copy.type = dst->type;
158bf215546Sopenharmony_ci   *dst = src_copy;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   if (dst->value_type == vtn_value_type_pointer)
161bf215546Sopenharmony_ci      dst->pointer = vtn_decorate_pointer(b, dst, dst->pointer);
162bf215546Sopenharmony_ci}
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_cistatic struct vtn_access_chain *
165bf215546Sopenharmony_civtn_access_chain_create(struct vtn_builder *b, unsigned length)
166bf215546Sopenharmony_ci{
167bf215546Sopenharmony_ci   struct vtn_access_chain *chain;
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   /* Subtract 1 from the length since there's already one built in */
170bf215546Sopenharmony_ci   size_t size = sizeof(*chain) +
171bf215546Sopenharmony_ci                 (MAX2(length, 1) - 1) * sizeof(chain->link[0]);
172bf215546Sopenharmony_ci   chain = rzalloc_size(b, size);
173bf215546Sopenharmony_ci   chain->length = length;
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   return chain;
176bf215546Sopenharmony_ci}
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_cistatic bool
179bf215546Sopenharmony_civtn_mode_is_cross_invocation(struct vtn_builder *b,
180bf215546Sopenharmony_ci                             enum vtn_variable_mode mode)
181bf215546Sopenharmony_ci{
182bf215546Sopenharmony_ci   return mode == vtn_variable_mode_ssbo ||
183bf215546Sopenharmony_ci          mode == vtn_variable_mode_ubo ||
184bf215546Sopenharmony_ci          mode == vtn_variable_mode_phys_ssbo ||
185bf215546Sopenharmony_ci          mode == vtn_variable_mode_push_constant ||
186bf215546Sopenharmony_ci          mode == vtn_variable_mode_workgroup ||
187bf215546Sopenharmony_ci          mode == vtn_variable_mode_cross_workgroup;
188bf215546Sopenharmony_ci}
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic bool
191bf215546Sopenharmony_civtn_pointer_is_external_block(struct vtn_builder *b,
192bf215546Sopenharmony_ci                              struct vtn_pointer *ptr)
193bf215546Sopenharmony_ci{
194bf215546Sopenharmony_ci   return ptr->mode == vtn_variable_mode_ssbo ||
195bf215546Sopenharmony_ci          ptr->mode == vtn_variable_mode_ubo ||
196bf215546Sopenharmony_ci          ptr->mode == vtn_variable_mode_phys_ssbo;
197bf215546Sopenharmony_ci}
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_cistatic nir_ssa_def *
200bf215546Sopenharmony_civtn_access_link_as_ssa(struct vtn_builder *b, struct vtn_access_link link,
201bf215546Sopenharmony_ci                       unsigned stride, unsigned bit_size)
202bf215546Sopenharmony_ci{
203bf215546Sopenharmony_ci   vtn_assert(stride > 0);
204bf215546Sopenharmony_ci   if (link.mode == vtn_access_mode_literal) {
205bf215546Sopenharmony_ci      return nir_imm_intN_t(&b->nb, link.id * stride, bit_size);
206bf215546Sopenharmony_ci   } else {
207bf215546Sopenharmony_ci      nir_ssa_def *ssa = vtn_ssa_value(b, link.id)->def;
208bf215546Sopenharmony_ci      if (ssa->bit_size != bit_size)
209bf215546Sopenharmony_ci         ssa = nir_i2i(&b->nb, ssa, bit_size);
210bf215546Sopenharmony_ci      return nir_imul_imm(&b->nb, ssa, stride);
211bf215546Sopenharmony_ci   }
212bf215546Sopenharmony_ci}
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_cistatic VkDescriptorType
215bf215546Sopenharmony_civk_desc_type_for_mode(struct vtn_builder *b, enum vtn_variable_mode mode)
216bf215546Sopenharmony_ci{
217bf215546Sopenharmony_ci   switch (mode) {
218bf215546Sopenharmony_ci   case vtn_variable_mode_ubo:
219bf215546Sopenharmony_ci      return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
220bf215546Sopenharmony_ci   case vtn_variable_mode_ssbo:
221bf215546Sopenharmony_ci      return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
222bf215546Sopenharmony_ci   case vtn_variable_mode_accel_struct:
223bf215546Sopenharmony_ci      return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
224bf215546Sopenharmony_ci   default:
225bf215546Sopenharmony_ci      vtn_fail("Invalid mode for vulkan_resource_index");
226bf215546Sopenharmony_ci   }
227bf215546Sopenharmony_ci}
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_cistatic nir_ssa_def *
230bf215546Sopenharmony_civtn_variable_resource_index(struct vtn_builder *b, struct vtn_variable *var,
231bf215546Sopenharmony_ci                            nir_ssa_def *desc_array_index)
232bf215546Sopenharmony_ci{
233bf215546Sopenharmony_ci   vtn_assert(b->options->environment == NIR_SPIRV_VULKAN);
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   if (!desc_array_index)
236bf215546Sopenharmony_ci      desc_array_index = nir_imm_int(&b->nb, 0);
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   if (b->vars_used_indirectly) {
239bf215546Sopenharmony_ci      vtn_assert(var->var);
240bf215546Sopenharmony_ci      _mesa_set_add(b->vars_used_indirectly, var->var);
241bf215546Sopenharmony_ci   }
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   nir_intrinsic_instr *instr =
244bf215546Sopenharmony_ci      nir_intrinsic_instr_create(b->nb.shader,
245bf215546Sopenharmony_ci                                 nir_intrinsic_vulkan_resource_index);
246bf215546Sopenharmony_ci   instr->src[0] = nir_src_for_ssa(desc_array_index);
247bf215546Sopenharmony_ci   nir_intrinsic_set_desc_set(instr, var->descriptor_set);
248bf215546Sopenharmony_ci   nir_intrinsic_set_binding(instr, var->binding);
249bf215546Sopenharmony_ci   nir_intrinsic_set_desc_type(instr, vk_desc_type_for_mode(b, var->mode));
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   nir_address_format addr_format = vtn_mode_to_address_format(b, var->mode);
252bf215546Sopenharmony_ci   nir_ssa_dest_init(&instr->instr, &instr->dest,
253bf215546Sopenharmony_ci                     nir_address_format_num_components(addr_format),
254bf215546Sopenharmony_ci                     nir_address_format_bit_size(addr_format), NULL);
255bf215546Sopenharmony_ci   instr->num_components = instr->dest.ssa.num_components;
256bf215546Sopenharmony_ci   nir_builder_instr_insert(&b->nb, &instr->instr);
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci   return &instr->dest.ssa;
259bf215546Sopenharmony_ci}
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_cistatic nir_ssa_def *
262bf215546Sopenharmony_civtn_resource_reindex(struct vtn_builder *b, enum vtn_variable_mode mode,
263bf215546Sopenharmony_ci                     nir_ssa_def *base_index, nir_ssa_def *offset_index)
264bf215546Sopenharmony_ci{
265bf215546Sopenharmony_ci   vtn_assert(b->options->environment == NIR_SPIRV_VULKAN);
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   nir_intrinsic_instr *instr =
268bf215546Sopenharmony_ci      nir_intrinsic_instr_create(b->nb.shader,
269bf215546Sopenharmony_ci                                 nir_intrinsic_vulkan_resource_reindex);
270bf215546Sopenharmony_ci   instr->src[0] = nir_src_for_ssa(base_index);
271bf215546Sopenharmony_ci   instr->src[1] = nir_src_for_ssa(offset_index);
272bf215546Sopenharmony_ci   nir_intrinsic_set_desc_type(instr, vk_desc_type_for_mode(b, mode));
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   nir_address_format addr_format = vtn_mode_to_address_format(b, mode);
275bf215546Sopenharmony_ci   nir_ssa_dest_init(&instr->instr, &instr->dest,
276bf215546Sopenharmony_ci                     nir_address_format_num_components(addr_format),
277bf215546Sopenharmony_ci                     nir_address_format_bit_size(addr_format), NULL);
278bf215546Sopenharmony_ci   instr->num_components = instr->dest.ssa.num_components;
279bf215546Sopenharmony_ci   nir_builder_instr_insert(&b->nb, &instr->instr);
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   return &instr->dest.ssa;
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_cistatic nir_ssa_def *
285bf215546Sopenharmony_civtn_descriptor_load(struct vtn_builder *b, enum vtn_variable_mode mode,
286bf215546Sopenharmony_ci                    nir_ssa_def *desc_index)
287bf215546Sopenharmony_ci{
288bf215546Sopenharmony_ci   vtn_assert(b->options->environment == NIR_SPIRV_VULKAN);
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci   nir_intrinsic_instr *desc_load =
291bf215546Sopenharmony_ci      nir_intrinsic_instr_create(b->nb.shader,
292bf215546Sopenharmony_ci                                 nir_intrinsic_load_vulkan_descriptor);
293bf215546Sopenharmony_ci   desc_load->src[0] = nir_src_for_ssa(desc_index);
294bf215546Sopenharmony_ci   nir_intrinsic_set_desc_type(desc_load, vk_desc_type_for_mode(b, mode));
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   nir_address_format addr_format = vtn_mode_to_address_format(b, mode);
297bf215546Sopenharmony_ci   nir_ssa_dest_init(&desc_load->instr, &desc_load->dest,
298bf215546Sopenharmony_ci                     nir_address_format_num_components(addr_format),
299bf215546Sopenharmony_ci                     nir_address_format_bit_size(addr_format), NULL);
300bf215546Sopenharmony_ci   desc_load->num_components = desc_load->dest.ssa.num_components;
301bf215546Sopenharmony_ci   nir_builder_instr_insert(&b->nb, &desc_load->instr);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   return &desc_load->dest.ssa;
304bf215546Sopenharmony_ci}
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_cistatic struct vtn_pointer *
307bf215546Sopenharmony_civtn_pointer_dereference(struct vtn_builder *b,
308bf215546Sopenharmony_ci                        struct vtn_pointer *base,
309bf215546Sopenharmony_ci                        struct vtn_access_chain *deref_chain)
310bf215546Sopenharmony_ci{
311bf215546Sopenharmony_ci   struct vtn_type *type = base->type;
312bf215546Sopenharmony_ci   enum gl_access_qualifier access = base->access | deref_chain->access;
313bf215546Sopenharmony_ci   unsigned idx = 0;
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   nir_deref_instr *tail;
316bf215546Sopenharmony_ci   if (base->deref) {
317bf215546Sopenharmony_ci      tail = base->deref;
318bf215546Sopenharmony_ci   } else if (b->options->environment == NIR_SPIRV_VULKAN &&
319bf215546Sopenharmony_ci              (vtn_pointer_is_external_block(b, base) ||
320bf215546Sopenharmony_ci               base->mode == vtn_variable_mode_accel_struct)) {
321bf215546Sopenharmony_ci      nir_ssa_def *block_index = base->block_index;
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci      /* We dereferencing an external block pointer.  Correctness of this
324bf215546Sopenharmony_ci       * operation relies on one particular line in the SPIR-V spec, section
325bf215546Sopenharmony_ci       * entitled "Validation Rules for Shader Capabilities":
326bf215546Sopenharmony_ci       *
327bf215546Sopenharmony_ci       *    "Block and BufferBlock decorations cannot decorate a structure
328bf215546Sopenharmony_ci       *    type that is nested at any level inside another structure type
329bf215546Sopenharmony_ci       *    decorated with Block or BufferBlock."
330bf215546Sopenharmony_ci       *
331bf215546Sopenharmony_ci       * This means that we can detect the point where we cross over from
332bf215546Sopenharmony_ci       * descriptor indexing to buffer indexing by looking for the block
333bf215546Sopenharmony_ci       * decorated struct type.  Anything before the block decorated struct
334bf215546Sopenharmony_ci       * type is a descriptor indexing operation and anything after the block
335bf215546Sopenharmony_ci       * decorated struct is a buffer offset operation.
336bf215546Sopenharmony_ci       */
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci      /* Figure out the descriptor array index if any
339bf215546Sopenharmony_ci       *
340bf215546Sopenharmony_ci       * Some of the Vulkan CTS tests with hand-rolled SPIR-V have been known
341bf215546Sopenharmony_ci       * to forget the Block or BufferBlock decoration from time to time.
342bf215546Sopenharmony_ci       * It's more robust if we check for both !block_index and for the type
343bf215546Sopenharmony_ci       * to contain a block.  This way there's a decent chance that arrays of
344bf215546Sopenharmony_ci       * UBOs/SSBOs will work correctly even if variable pointers are
345bf215546Sopenharmony_ci       * completley toast.
346bf215546Sopenharmony_ci       */
347bf215546Sopenharmony_ci      nir_ssa_def *desc_arr_idx = NULL;
348bf215546Sopenharmony_ci      if (!block_index || vtn_type_contains_block(b, type) ||
349bf215546Sopenharmony_ci          base->mode == vtn_variable_mode_accel_struct) {
350bf215546Sopenharmony_ci         /* If our type contains a block, then we're still outside the block
351bf215546Sopenharmony_ci          * and we need to process enough levels of dereferences to get inside
352bf215546Sopenharmony_ci          * of it.  Same applies to acceleration structures.
353bf215546Sopenharmony_ci          */
354bf215546Sopenharmony_ci         if (deref_chain->ptr_as_array) {
355bf215546Sopenharmony_ci            unsigned aoa_size = glsl_get_aoa_size(type->type);
356bf215546Sopenharmony_ci            desc_arr_idx = vtn_access_link_as_ssa(b, deref_chain->link[idx],
357bf215546Sopenharmony_ci                                                  MAX2(aoa_size, 1), 32);
358bf215546Sopenharmony_ci            idx++;
359bf215546Sopenharmony_ci         }
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci         for (; idx < deref_chain->length; idx++) {
362bf215546Sopenharmony_ci            if (type->base_type != vtn_base_type_array) {
363bf215546Sopenharmony_ci               vtn_assert(type->base_type == vtn_base_type_struct);
364bf215546Sopenharmony_ci               break;
365bf215546Sopenharmony_ci            }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci            unsigned aoa_size = glsl_get_aoa_size(type->array_element->type);
368bf215546Sopenharmony_ci            nir_ssa_def *arr_offset =
369bf215546Sopenharmony_ci               vtn_access_link_as_ssa(b, deref_chain->link[idx],
370bf215546Sopenharmony_ci                                      MAX2(aoa_size, 1), 32);
371bf215546Sopenharmony_ci            if (desc_arr_idx)
372bf215546Sopenharmony_ci               desc_arr_idx = nir_iadd(&b->nb, desc_arr_idx, arr_offset);
373bf215546Sopenharmony_ci            else
374bf215546Sopenharmony_ci               desc_arr_idx = arr_offset;
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci            type = type->array_element;
377bf215546Sopenharmony_ci            access |= type->access;
378bf215546Sopenharmony_ci         }
379bf215546Sopenharmony_ci      }
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci      if (!block_index) {
382bf215546Sopenharmony_ci         vtn_assert(base->var && base->type);
383bf215546Sopenharmony_ci         block_index = vtn_variable_resource_index(b, base->var, desc_arr_idx);
384bf215546Sopenharmony_ci      } else if (desc_arr_idx) {
385bf215546Sopenharmony_ci         block_index = vtn_resource_reindex(b, base->mode,
386bf215546Sopenharmony_ci                                            block_index, desc_arr_idx);
387bf215546Sopenharmony_ci      }
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci      if (idx == deref_chain->length) {
390bf215546Sopenharmony_ci         /* The entire deref was consumed in finding the block index.  Return
391bf215546Sopenharmony_ci          * a pointer which just has a block index and a later access chain
392bf215546Sopenharmony_ci          * will dereference deeper.
393bf215546Sopenharmony_ci          */
394bf215546Sopenharmony_ci         struct vtn_pointer *ptr = rzalloc(b, struct vtn_pointer);
395bf215546Sopenharmony_ci         ptr->mode = base->mode;
396bf215546Sopenharmony_ci         ptr->type = type;
397bf215546Sopenharmony_ci         ptr->block_index = block_index;
398bf215546Sopenharmony_ci         ptr->access = access;
399bf215546Sopenharmony_ci         return ptr;
400bf215546Sopenharmony_ci      }
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci      /* If we got here, there's more access chain to handle and we have the
403bf215546Sopenharmony_ci       * final block index.  Insert a descriptor load and cast to a deref to
404bf215546Sopenharmony_ci       * start the deref chain.
405bf215546Sopenharmony_ci       */
406bf215546Sopenharmony_ci      nir_ssa_def *desc = vtn_descriptor_load(b, base->mode, block_index);
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci      assert(base->mode == vtn_variable_mode_ssbo ||
409bf215546Sopenharmony_ci             base->mode == vtn_variable_mode_ubo);
410bf215546Sopenharmony_ci      nir_variable_mode nir_mode =
411bf215546Sopenharmony_ci         base->mode == vtn_variable_mode_ssbo ? nir_var_mem_ssbo : nir_var_mem_ubo;
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci      tail = nir_build_deref_cast(&b->nb, desc, nir_mode,
414bf215546Sopenharmony_ci                                  vtn_type_get_nir_type(b, type, base->mode),
415bf215546Sopenharmony_ci                                  base->ptr_type->stride);
416bf215546Sopenharmony_ci   } else if (base->mode == vtn_variable_mode_shader_record) {
417bf215546Sopenharmony_ci      /* For ShaderRecordBufferKHR variables, we don't have a nir_variable.
418bf215546Sopenharmony_ci       * It's just a fancy handle around a pointer to the shader record for
419bf215546Sopenharmony_ci       * the current shader.
420bf215546Sopenharmony_ci       */
421bf215546Sopenharmony_ci      tail = nir_build_deref_cast(&b->nb, nir_load_shader_record_ptr(&b->nb),
422bf215546Sopenharmony_ci                                  nir_var_mem_constant,
423bf215546Sopenharmony_ci                                  vtn_type_get_nir_type(b, base->type,
424bf215546Sopenharmony_ci                                                           base->mode),
425bf215546Sopenharmony_ci                                  0 /* ptr_as_array stride */);
426bf215546Sopenharmony_ci   } else {
427bf215546Sopenharmony_ci      assert(base->var && base->var->var);
428bf215546Sopenharmony_ci      tail = nir_build_deref_var(&b->nb, base->var->var);
429bf215546Sopenharmony_ci      if (base->ptr_type && base->ptr_type->type) {
430bf215546Sopenharmony_ci         tail->dest.ssa.num_components =
431bf215546Sopenharmony_ci            glsl_get_vector_elements(base->ptr_type->type);
432bf215546Sopenharmony_ci         tail->dest.ssa.bit_size = glsl_get_bit_size(base->ptr_type->type);
433bf215546Sopenharmony_ci      }
434bf215546Sopenharmony_ci   }
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   if (idx == 0 && deref_chain->ptr_as_array) {
437bf215546Sopenharmony_ci      /* We start with a deref cast to get the stride.  Hopefully, we'll be
438bf215546Sopenharmony_ci       * able to delete that cast eventually.
439bf215546Sopenharmony_ci       */
440bf215546Sopenharmony_ci      tail = nir_build_deref_cast(&b->nb, &tail->dest.ssa, tail->modes,
441bf215546Sopenharmony_ci                                  tail->type, base->ptr_type->stride);
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ci      nir_ssa_def *index = vtn_access_link_as_ssa(b, deref_chain->link[0], 1,
444bf215546Sopenharmony_ci                                                  tail->dest.ssa.bit_size);
445bf215546Sopenharmony_ci      tail = nir_build_deref_ptr_as_array(&b->nb, tail, index);
446bf215546Sopenharmony_ci      idx++;
447bf215546Sopenharmony_ci   }
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ci   for (; idx < deref_chain->length; idx++) {
450bf215546Sopenharmony_ci      if (glsl_type_is_struct_or_ifc(type->type)) {
451bf215546Sopenharmony_ci         vtn_assert(deref_chain->link[idx].mode == vtn_access_mode_literal);
452bf215546Sopenharmony_ci         unsigned field = deref_chain->link[idx].id;
453bf215546Sopenharmony_ci         tail = nir_build_deref_struct(&b->nb, tail, field);
454bf215546Sopenharmony_ci         type = type->members[field];
455bf215546Sopenharmony_ci      } else {
456bf215546Sopenharmony_ci         nir_ssa_def *arr_index =
457bf215546Sopenharmony_ci            vtn_access_link_as_ssa(b, deref_chain->link[idx], 1,
458bf215546Sopenharmony_ci                                   tail->dest.ssa.bit_size);
459bf215546Sopenharmony_ci         tail = nir_build_deref_array(&b->nb, tail, arr_index);
460bf215546Sopenharmony_ci         type = type->array_element;
461bf215546Sopenharmony_ci      }
462bf215546Sopenharmony_ci      tail->arr.in_bounds = deref_chain->in_bounds;
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci      access |= type->access;
465bf215546Sopenharmony_ci   }
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci   struct vtn_pointer *ptr = rzalloc(b, struct vtn_pointer);
468bf215546Sopenharmony_ci   ptr->mode = base->mode;
469bf215546Sopenharmony_ci   ptr->type = type;
470bf215546Sopenharmony_ci   ptr->var = base->var;
471bf215546Sopenharmony_ci   ptr->deref = tail;
472bf215546Sopenharmony_ci   ptr->access = access;
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   return ptr;
475bf215546Sopenharmony_ci}
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_cinir_deref_instr *
478bf215546Sopenharmony_civtn_pointer_to_deref(struct vtn_builder *b, struct vtn_pointer *ptr)
479bf215546Sopenharmony_ci{
480bf215546Sopenharmony_ci   if (!ptr->deref) {
481bf215546Sopenharmony_ci      struct vtn_access_chain chain = {
482bf215546Sopenharmony_ci         .length = 0,
483bf215546Sopenharmony_ci      };
484bf215546Sopenharmony_ci      ptr = vtn_pointer_dereference(b, ptr, &chain);
485bf215546Sopenharmony_ci   }
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci   return ptr->deref;
488bf215546Sopenharmony_ci}
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_cistatic void
491bf215546Sopenharmony_ci_vtn_local_load_store(struct vtn_builder *b, bool load, nir_deref_instr *deref,
492bf215546Sopenharmony_ci                      struct vtn_ssa_value *inout,
493bf215546Sopenharmony_ci                      enum gl_access_qualifier access)
494bf215546Sopenharmony_ci{
495bf215546Sopenharmony_ci   if (glsl_type_is_vector_or_scalar(deref->type)) {
496bf215546Sopenharmony_ci      if (load) {
497bf215546Sopenharmony_ci         inout->def = nir_load_deref_with_access(&b->nb, deref, access);
498bf215546Sopenharmony_ci      } else {
499bf215546Sopenharmony_ci         nir_store_deref_with_access(&b->nb, deref, inout->def, ~0, access);
500bf215546Sopenharmony_ci      }
501bf215546Sopenharmony_ci   } else if (glsl_type_is_array(deref->type) ||
502bf215546Sopenharmony_ci              glsl_type_is_matrix(deref->type)) {
503bf215546Sopenharmony_ci      unsigned elems = glsl_get_length(deref->type);
504bf215546Sopenharmony_ci      for (unsigned i = 0; i < elems; i++) {
505bf215546Sopenharmony_ci         nir_deref_instr *child =
506bf215546Sopenharmony_ci            nir_build_deref_array_imm(&b->nb, deref, i);
507bf215546Sopenharmony_ci         _vtn_local_load_store(b, load, child, inout->elems[i], access);
508bf215546Sopenharmony_ci      }
509bf215546Sopenharmony_ci   } else {
510bf215546Sopenharmony_ci      vtn_assert(glsl_type_is_struct_or_ifc(deref->type));
511bf215546Sopenharmony_ci      unsigned elems = glsl_get_length(deref->type);
512bf215546Sopenharmony_ci      for (unsigned i = 0; i < elems; i++) {
513bf215546Sopenharmony_ci         nir_deref_instr *child = nir_build_deref_struct(&b->nb, deref, i);
514bf215546Sopenharmony_ci         _vtn_local_load_store(b, load, child, inout->elems[i], access);
515bf215546Sopenharmony_ci      }
516bf215546Sopenharmony_ci   }
517bf215546Sopenharmony_ci}
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_cinir_deref_instr *
520bf215546Sopenharmony_civtn_nir_deref(struct vtn_builder *b, uint32_t id)
521bf215546Sopenharmony_ci{
522bf215546Sopenharmony_ci   struct vtn_pointer *ptr = vtn_pointer(b, id);
523bf215546Sopenharmony_ci   return vtn_pointer_to_deref(b, ptr);
524bf215546Sopenharmony_ci}
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci/*
527bf215546Sopenharmony_ci * Gets the NIR-level deref tail, which may have as a child an array deref
528bf215546Sopenharmony_ci * selecting which component due to OpAccessChain supporting per-component
529bf215546Sopenharmony_ci * indexing in SPIR-V.
530bf215546Sopenharmony_ci */
531bf215546Sopenharmony_cistatic nir_deref_instr *
532bf215546Sopenharmony_ciget_deref_tail(nir_deref_instr *deref)
533bf215546Sopenharmony_ci{
534bf215546Sopenharmony_ci   if (deref->deref_type != nir_deref_type_array)
535bf215546Sopenharmony_ci      return deref;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   nir_deref_instr *parent =
538bf215546Sopenharmony_ci      nir_instr_as_deref(deref->parent.ssa->parent_instr);
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci   if (glsl_type_is_vector(parent->type))
541bf215546Sopenharmony_ci      return parent;
542bf215546Sopenharmony_ci   else
543bf215546Sopenharmony_ci      return deref;
544bf215546Sopenharmony_ci}
545bf215546Sopenharmony_ci
546bf215546Sopenharmony_cistruct vtn_ssa_value *
547bf215546Sopenharmony_civtn_local_load(struct vtn_builder *b, nir_deref_instr *src,
548bf215546Sopenharmony_ci               enum gl_access_qualifier access)
549bf215546Sopenharmony_ci{
550bf215546Sopenharmony_ci   nir_deref_instr *src_tail = get_deref_tail(src);
551bf215546Sopenharmony_ci   struct vtn_ssa_value *val = vtn_create_ssa_value(b, src_tail->type);
552bf215546Sopenharmony_ci   _vtn_local_load_store(b, true, src_tail, val, access);
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci   if (src_tail != src) {
555bf215546Sopenharmony_ci      val->type = src->type;
556bf215546Sopenharmony_ci      val->def = nir_vector_extract(&b->nb, val->def, src->arr.index.ssa);
557bf215546Sopenharmony_ci   }
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   return val;
560bf215546Sopenharmony_ci}
561bf215546Sopenharmony_ci
562bf215546Sopenharmony_civoid
563bf215546Sopenharmony_civtn_local_store(struct vtn_builder *b, struct vtn_ssa_value *src,
564bf215546Sopenharmony_ci                nir_deref_instr *dest, enum gl_access_qualifier access)
565bf215546Sopenharmony_ci{
566bf215546Sopenharmony_ci   nir_deref_instr *dest_tail = get_deref_tail(dest);
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci   if (dest_tail != dest) {
569bf215546Sopenharmony_ci      struct vtn_ssa_value *val = vtn_create_ssa_value(b, dest_tail->type);
570bf215546Sopenharmony_ci      _vtn_local_load_store(b, true, dest_tail, val, access);
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci      val->def = nir_vector_insert(&b->nb, val->def, src->def,
573bf215546Sopenharmony_ci                                   dest->arr.index.ssa);
574bf215546Sopenharmony_ci      _vtn_local_load_store(b, false, dest_tail, val, access);
575bf215546Sopenharmony_ci   } else {
576bf215546Sopenharmony_ci      _vtn_local_load_store(b, false, dest_tail, src, access);
577bf215546Sopenharmony_ci   }
578bf215546Sopenharmony_ci}
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_cistatic nir_ssa_def *
581bf215546Sopenharmony_civtn_pointer_to_descriptor(struct vtn_builder *b, struct vtn_pointer *ptr)
582bf215546Sopenharmony_ci{
583bf215546Sopenharmony_ci   assert(ptr->mode == vtn_variable_mode_accel_struct);
584bf215546Sopenharmony_ci   if (!ptr->block_index) {
585bf215546Sopenharmony_ci      struct vtn_access_chain chain = {
586bf215546Sopenharmony_ci         .length = 0,
587bf215546Sopenharmony_ci      };
588bf215546Sopenharmony_ci      ptr = vtn_pointer_dereference(b, ptr, &chain);
589bf215546Sopenharmony_ci   }
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   vtn_assert(ptr->deref == NULL && ptr->block_index != NULL);
592bf215546Sopenharmony_ci   return vtn_descriptor_load(b, ptr->mode, ptr->block_index);
593bf215546Sopenharmony_ci}
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_cistatic void
596bf215546Sopenharmony_ci_vtn_variable_load_store(struct vtn_builder *b, bool load,
597bf215546Sopenharmony_ci                         struct vtn_pointer *ptr,
598bf215546Sopenharmony_ci                         enum gl_access_qualifier access,
599bf215546Sopenharmony_ci                         struct vtn_ssa_value **inout)
600bf215546Sopenharmony_ci{
601bf215546Sopenharmony_ci   if (ptr->mode == vtn_variable_mode_uniform ||
602bf215546Sopenharmony_ci       ptr->mode == vtn_variable_mode_image) {
603bf215546Sopenharmony_ci      if (ptr->type->base_type == vtn_base_type_image ||
604bf215546Sopenharmony_ci          ptr->type->base_type == vtn_base_type_sampler) {
605bf215546Sopenharmony_ci         /* See also our handling of OpTypeSampler and OpTypeImage */
606bf215546Sopenharmony_ci         vtn_assert(load);
607bf215546Sopenharmony_ci         (*inout)->def = vtn_pointer_to_ssa(b, ptr);
608bf215546Sopenharmony_ci         return;
609bf215546Sopenharmony_ci      } else if (ptr->type->base_type == vtn_base_type_sampled_image) {
610bf215546Sopenharmony_ci         /* See also our handling of OpTypeSampledImage */
611bf215546Sopenharmony_ci         vtn_assert(load);
612bf215546Sopenharmony_ci         struct vtn_sampled_image si = {
613bf215546Sopenharmony_ci            .image = vtn_pointer_to_deref(b, ptr),
614bf215546Sopenharmony_ci            .sampler = vtn_pointer_to_deref(b, ptr),
615bf215546Sopenharmony_ci         };
616bf215546Sopenharmony_ci         (*inout)->def = vtn_sampled_image_to_nir_ssa(b, si);
617bf215546Sopenharmony_ci         return;
618bf215546Sopenharmony_ci      }
619bf215546Sopenharmony_ci   } else if (ptr->mode == vtn_variable_mode_accel_struct) {
620bf215546Sopenharmony_ci      vtn_assert(load);
621bf215546Sopenharmony_ci      (*inout)->def = vtn_pointer_to_descriptor(b, ptr);
622bf215546Sopenharmony_ci      return;
623bf215546Sopenharmony_ci   }
624bf215546Sopenharmony_ci
625bf215546Sopenharmony_ci   enum glsl_base_type base_type = glsl_get_base_type(ptr->type->type);
626bf215546Sopenharmony_ci   switch (base_type) {
627bf215546Sopenharmony_ci   case GLSL_TYPE_UINT:
628bf215546Sopenharmony_ci   case GLSL_TYPE_INT:
629bf215546Sopenharmony_ci   case GLSL_TYPE_UINT16:
630bf215546Sopenharmony_ci   case GLSL_TYPE_INT16:
631bf215546Sopenharmony_ci   case GLSL_TYPE_UINT8:
632bf215546Sopenharmony_ci   case GLSL_TYPE_INT8:
633bf215546Sopenharmony_ci   case GLSL_TYPE_UINT64:
634bf215546Sopenharmony_ci   case GLSL_TYPE_INT64:
635bf215546Sopenharmony_ci   case GLSL_TYPE_FLOAT:
636bf215546Sopenharmony_ci   case GLSL_TYPE_FLOAT16:
637bf215546Sopenharmony_ci   case GLSL_TYPE_BOOL:
638bf215546Sopenharmony_ci   case GLSL_TYPE_DOUBLE:
639bf215546Sopenharmony_ci      if (glsl_type_is_vector_or_scalar(ptr->type->type)) {
640bf215546Sopenharmony_ci         /* We hit a vector or scalar; go ahead and emit the load[s] */
641bf215546Sopenharmony_ci         nir_deref_instr *deref = vtn_pointer_to_deref(b, ptr);
642bf215546Sopenharmony_ci         if (vtn_mode_is_cross_invocation(b, ptr->mode)) {
643bf215546Sopenharmony_ci            /* If it's cross-invocation, we call nir_load/store_deref
644bf215546Sopenharmony_ci             * directly.  The vtn_local_load/store helpers are too clever and
645bf215546Sopenharmony_ci             * do magic to avoid array derefs of vectors.  That magic is both
646bf215546Sopenharmony_ci             * less efficient than the direct load/store and, in the case of
647bf215546Sopenharmony_ci             * stores, is broken because it creates a race condition if two
648bf215546Sopenharmony_ci             * threads are writing to different components of the same vector
649bf215546Sopenharmony_ci             * due to the load+insert+store it uses to emulate the array
650bf215546Sopenharmony_ci             * deref.
651bf215546Sopenharmony_ci             */
652bf215546Sopenharmony_ci            if (load) {
653bf215546Sopenharmony_ci               (*inout)->def = nir_load_deref_with_access(&b->nb, deref,
654bf215546Sopenharmony_ci                                                          ptr->type->access | access);
655bf215546Sopenharmony_ci            } else {
656bf215546Sopenharmony_ci               nir_store_deref_with_access(&b->nb, deref, (*inout)->def, ~0,
657bf215546Sopenharmony_ci                                           ptr->type->access | access);
658bf215546Sopenharmony_ci            }
659bf215546Sopenharmony_ci         } else {
660bf215546Sopenharmony_ci            if (load) {
661bf215546Sopenharmony_ci               *inout = vtn_local_load(b, deref, ptr->type->access | access);
662bf215546Sopenharmony_ci            } else {
663bf215546Sopenharmony_ci               vtn_local_store(b, *inout, deref, ptr->type->access | access);
664bf215546Sopenharmony_ci            }
665bf215546Sopenharmony_ci         }
666bf215546Sopenharmony_ci         return;
667bf215546Sopenharmony_ci      }
668bf215546Sopenharmony_ci      FALLTHROUGH;
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci   case GLSL_TYPE_INTERFACE:
671bf215546Sopenharmony_ci   case GLSL_TYPE_ARRAY:
672bf215546Sopenharmony_ci   case GLSL_TYPE_STRUCT: {
673bf215546Sopenharmony_ci      unsigned elems = glsl_get_length(ptr->type->type);
674bf215546Sopenharmony_ci      struct vtn_access_chain chain = {
675bf215546Sopenharmony_ci         .length = 1,
676bf215546Sopenharmony_ci         .link = {
677bf215546Sopenharmony_ci            { .mode = vtn_access_mode_literal, },
678bf215546Sopenharmony_ci         }
679bf215546Sopenharmony_ci      };
680bf215546Sopenharmony_ci      for (unsigned i = 0; i < elems; i++) {
681bf215546Sopenharmony_ci         chain.link[0].id = i;
682bf215546Sopenharmony_ci         struct vtn_pointer *elem = vtn_pointer_dereference(b, ptr, &chain);
683bf215546Sopenharmony_ci         _vtn_variable_load_store(b, load, elem, ptr->type->access | access,
684bf215546Sopenharmony_ci                                  &(*inout)->elems[i]);
685bf215546Sopenharmony_ci      }
686bf215546Sopenharmony_ci      return;
687bf215546Sopenharmony_ci   }
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci   default:
690bf215546Sopenharmony_ci      vtn_fail("Invalid access chain type");
691bf215546Sopenharmony_ci   }
692bf215546Sopenharmony_ci}
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_cistruct vtn_ssa_value *
695bf215546Sopenharmony_civtn_variable_load(struct vtn_builder *b, struct vtn_pointer *src,
696bf215546Sopenharmony_ci                  enum gl_access_qualifier access)
697bf215546Sopenharmony_ci{
698bf215546Sopenharmony_ci   struct vtn_ssa_value *val = vtn_create_ssa_value(b, src->type->type);
699bf215546Sopenharmony_ci   _vtn_variable_load_store(b, true, src, src->access | access, &val);
700bf215546Sopenharmony_ci   return val;
701bf215546Sopenharmony_ci}
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_civoid
704bf215546Sopenharmony_civtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
705bf215546Sopenharmony_ci                   struct vtn_pointer *dest, enum gl_access_qualifier access)
706bf215546Sopenharmony_ci{
707bf215546Sopenharmony_ci   _vtn_variable_load_store(b, false, dest, dest->access | access, &src);
708bf215546Sopenharmony_ci}
709bf215546Sopenharmony_ci
710bf215546Sopenharmony_cistatic void
711bf215546Sopenharmony_ci_vtn_variable_copy(struct vtn_builder *b, struct vtn_pointer *dest,
712bf215546Sopenharmony_ci                   struct vtn_pointer *src, enum gl_access_qualifier dest_access,
713bf215546Sopenharmony_ci                   enum gl_access_qualifier src_access)
714bf215546Sopenharmony_ci{
715bf215546Sopenharmony_ci   vtn_assert(glsl_get_bare_type(src->type->type) ==
716bf215546Sopenharmony_ci              glsl_get_bare_type(dest->type->type));
717bf215546Sopenharmony_ci   enum glsl_base_type base_type = glsl_get_base_type(src->type->type);
718bf215546Sopenharmony_ci   switch (base_type) {
719bf215546Sopenharmony_ci   case GLSL_TYPE_UINT:
720bf215546Sopenharmony_ci   case GLSL_TYPE_INT:
721bf215546Sopenharmony_ci   case GLSL_TYPE_UINT16:
722bf215546Sopenharmony_ci   case GLSL_TYPE_INT16:
723bf215546Sopenharmony_ci   case GLSL_TYPE_UINT8:
724bf215546Sopenharmony_ci   case GLSL_TYPE_INT8:
725bf215546Sopenharmony_ci   case GLSL_TYPE_UINT64:
726bf215546Sopenharmony_ci   case GLSL_TYPE_INT64:
727bf215546Sopenharmony_ci   case GLSL_TYPE_FLOAT:
728bf215546Sopenharmony_ci   case GLSL_TYPE_FLOAT16:
729bf215546Sopenharmony_ci   case GLSL_TYPE_DOUBLE:
730bf215546Sopenharmony_ci   case GLSL_TYPE_BOOL:
731bf215546Sopenharmony_ci      /* At this point, we have a scalar, vector, or matrix so we know that
732bf215546Sopenharmony_ci       * there cannot be any structure splitting still in the way.  By
733bf215546Sopenharmony_ci       * stopping at the matrix level rather than the vector level, we
734bf215546Sopenharmony_ci       * ensure that matrices get loaded in the optimal way even if they
735bf215546Sopenharmony_ci       * are storred row-major in a UBO.
736bf215546Sopenharmony_ci       */
737bf215546Sopenharmony_ci      vtn_variable_store(b, vtn_variable_load(b, src, src_access), dest, dest_access);
738bf215546Sopenharmony_ci      return;
739bf215546Sopenharmony_ci
740bf215546Sopenharmony_ci   case GLSL_TYPE_INTERFACE:
741bf215546Sopenharmony_ci   case GLSL_TYPE_ARRAY:
742bf215546Sopenharmony_ci   case GLSL_TYPE_STRUCT: {
743bf215546Sopenharmony_ci      struct vtn_access_chain chain = {
744bf215546Sopenharmony_ci         .length = 1,
745bf215546Sopenharmony_ci         .link = {
746bf215546Sopenharmony_ci            { .mode = vtn_access_mode_literal, },
747bf215546Sopenharmony_ci         }
748bf215546Sopenharmony_ci      };
749bf215546Sopenharmony_ci      unsigned elems = glsl_get_length(src->type->type);
750bf215546Sopenharmony_ci      for (unsigned i = 0; i < elems; i++) {
751bf215546Sopenharmony_ci         chain.link[0].id = i;
752bf215546Sopenharmony_ci         struct vtn_pointer *src_elem =
753bf215546Sopenharmony_ci            vtn_pointer_dereference(b, src, &chain);
754bf215546Sopenharmony_ci         struct vtn_pointer *dest_elem =
755bf215546Sopenharmony_ci            vtn_pointer_dereference(b, dest, &chain);
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci         _vtn_variable_copy(b, dest_elem, src_elem, dest_access, src_access);
758bf215546Sopenharmony_ci      }
759bf215546Sopenharmony_ci      return;
760bf215546Sopenharmony_ci   }
761bf215546Sopenharmony_ci
762bf215546Sopenharmony_ci   default:
763bf215546Sopenharmony_ci      vtn_fail("Invalid access chain type");
764bf215546Sopenharmony_ci   }
765bf215546Sopenharmony_ci}
766bf215546Sopenharmony_ci
767bf215546Sopenharmony_cistatic void
768bf215546Sopenharmony_civtn_variable_copy(struct vtn_builder *b, struct vtn_pointer *dest,
769bf215546Sopenharmony_ci                  struct vtn_pointer *src, enum gl_access_qualifier dest_access,
770bf215546Sopenharmony_ci                  enum gl_access_qualifier src_access)
771bf215546Sopenharmony_ci{
772bf215546Sopenharmony_ci   /* TODO: At some point, we should add a special-case for when we can
773bf215546Sopenharmony_ci    * just emit a copy_var intrinsic.
774bf215546Sopenharmony_ci    */
775bf215546Sopenharmony_ci   _vtn_variable_copy(b, dest, src, dest_access, src_access);
776bf215546Sopenharmony_ci}
777bf215546Sopenharmony_ci
778bf215546Sopenharmony_cistatic void
779bf215546Sopenharmony_ciset_mode_system_value(struct vtn_builder *b, nir_variable_mode *mode)
780bf215546Sopenharmony_ci{
781bf215546Sopenharmony_ci   vtn_assert(*mode == nir_var_system_value || *mode == nir_var_shader_in ||
782bf215546Sopenharmony_ci              /* Hack for NV_mesh_shader due to lack of dedicated storage class. */
783bf215546Sopenharmony_ci              *mode == nir_var_mem_task_payload);
784bf215546Sopenharmony_ci   *mode = nir_var_system_value;
785bf215546Sopenharmony_ci}
786bf215546Sopenharmony_ci
787bf215546Sopenharmony_cistatic void
788bf215546Sopenharmony_civtn_get_builtin_location(struct vtn_builder *b,
789bf215546Sopenharmony_ci                         SpvBuiltIn builtin, int *location,
790bf215546Sopenharmony_ci                         nir_variable_mode *mode)
791bf215546Sopenharmony_ci{
792bf215546Sopenharmony_ci   switch (builtin) {
793bf215546Sopenharmony_ci   case SpvBuiltInPosition:
794bf215546Sopenharmony_ci   case SpvBuiltInPositionPerViewNV:
795bf215546Sopenharmony_ci      *location = VARYING_SLOT_POS;
796bf215546Sopenharmony_ci      break;
797bf215546Sopenharmony_ci   case SpvBuiltInPointSize:
798bf215546Sopenharmony_ci      *location = VARYING_SLOT_PSIZ;
799bf215546Sopenharmony_ci      break;
800bf215546Sopenharmony_ci   case SpvBuiltInClipDistance:
801bf215546Sopenharmony_ci   case SpvBuiltInClipDistancePerViewNV:
802bf215546Sopenharmony_ci      *location = VARYING_SLOT_CLIP_DIST0;
803bf215546Sopenharmony_ci      break;
804bf215546Sopenharmony_ci   case SpvBuiltInCullDistance:
805bf215546Sopenharmony_ci   case SpvBuiltInCullDistancePerViewNV:
806bf215546Sopenharmony_ci      *location = VARYING_SLOT_CULL_DIST0;
807bf215546Sopenharmony_ci      break;
808bf215546Sopenharmony_ci   case SpvBuiltInVertexId:
809bf215546Sopenharmony_ci   case SpvBuiltInVertexIndex:
810bf215546Sopenharmony_ci      /* The Vulkan spec defines VertexIndex to be non-zero-based and doesn't
811bf215546Sopenharmony_ci       * allow VertexId.  The ARB_gl_spirv spec defines VertexId to be the
812bf215546Sopenharmony_ci       * same as gl_VertexID, which is non-zero-based, and removes
813bf215546Sopenharmony_ci       * VertexIndex.  Since they're both defined to be non-zero-based, we use
814bf215546Sopenharmony_ci       * SYSTEM_VALUE_VERTEX_ID for both.
815bf215546Sopenharmony_ci       */
816bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_VERTEX_ID;
817bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
818bf215546Sopenharmony_ci      break;
819bf215546Sopenharmony_ci   case SpvBuiltInInstanceIndex:
820bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_INSTANCE_INDEX;
821bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
822bf215546Sopenharmony_ci      break;
823bf215546Sopenharmony_ci   case SpvBuiltInInstanceId:
824bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_INSTANCE_ID;
825bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
826bf215546Sopenharmony_ci      break;
827bf215546Sopenharmony_ci   case SpvBuiltInPrimitiveId:
828bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_FRAGMENT) {
829bf215546Sopenharmony_ci         vtn_assert(*mode == nir_var_shader_in);
830bf215546Sopenharmony_ci         *location = VARYING_SLOT_PRIMITIVE_ID;
831bf215546Sopenharmony_ci      } else if (*mode == nir_var_shader_out) {
832bf215546Sopenharmony_ci         *location = VARYING_SLOT_PRIMITIVE_ID;
833bf215546Sopenharmony_ci      } else {
834bf215546Sopenharmony_ci         *location = SYSTEM_VALUE_PRIMITIVE_ID;
835bf215546Sopenharmony_ci         set_mode_system_value(b, mode);
836bf215546Sopenharmony_ci      }
837bf215546Sopenharmony_ci      break;
838bf215546Sopenharmony_ci   case SpvBuiltInInvocationId:
839bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_INVOCATION_ID;
840bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
841bf215546Sopenharmony_ci      break;
842bf215546Sopenharmony_ci   case SpvBuiltInLayer:
843bf215546Sopenharmony_ci   case SpvBuiltInLayerPerViewNV:
844bf215546Sopenharmony_ci      *location = VARYING_SLOT_LAYER;
845bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_FRAGMENT)
846bf215546Sopenharmony_ci         *mode = nir_var_shader_in;
847bf215546Sopenharmony_ci      else if (b->shader->info.stage == MESA_SHADER_GEOMETRY)
848bf215546Sopenharmony_ci         *mode = nir_var_shader_out;
849bf215546Sopenharmony_ci      else if (b->options && b->options->caps.shader_viewport_index_layer &&
850bf215546Sopenharmony_ci               (b->shader->info.stage == MESA_SHADER_VERTEX ||
851bf215546Sopenharmony_ci                b->shader->info.stage == MESA_SHADER_TESS_EVAL ||
852bf215546Sopenharmony_ci                b->shader->info.stage == MESA_SHADER_MESH))
853bf215546Sopenharmony_ci         *mode = nir_var_shader_out;
854bf215546Sopenharmony_ci      else
855bf215546Sopenharmony_ci         vtn_fail("invalid stage for SpvBuiltInLayer");
856bf215546Sopenharmony_ci      break;
857bf215546Sopenharmony_ci   case SpvBuiltInViewportIndex:
858bf215546Sopenharmony_ci      *location = VARYING_SLOT_VIEWPORT;
859bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_GEOMETRY)
860bf215546Sopenharmony_ci         *mode = nir_var_shader_out;
861bf215546Sopenharmony_ci      else if (b->options && b->options->caps.shader_viewport_index_layer &&
862bf215546Sopenharmony_ci               (b->shader->info.stage == MESA_SHADER_VERTEX ||
863bf215546Sopenharmony_ci                b->shader->info.stage == MESA_SHADER_TESS_EVAL ||
864bf215546Sopenharmony_ci                b->shader->info.stage == MESA_SHADER_MESH))
865bf215546Sopenharmony_ci         *mode = nir_var_shader_out;
866bf215546Sopenharmony_ci      else if (b->shader->info.stage == MESA_SHADER_FRAGMENT)
867bf215546Sopenharmony_ci         *mode = nir_var_shader_in;
868bf215546Sopenharmony_ci      else
869bf215546Sopenharmony_ci         vtn_fail("invalid stage for SpvBuiltInViewportIndex");
870bf215546Sopenharmony_ci      break;
871bf215546Sopenharmony_ci   case SpvBuiltInViewportMaskNV:
872bf215546Sopenharmony_ci   case SpvBuiltInViewportMaskPerViewNV:
873bf215546Sopenharmony_ci      *location = VARYING_SLOT_VIEWPORT_MASK;
874bf215546Sopenharmony_ci      *mode = nir_var_shader_out;
875bf215546Sopenharmony_ci      break;
876bf215546Sopenharmony_ci   case SpvBuiltInTessLevelOuter:
877bf215546Sopenharmony_ci      *location = VARYING_SLOT_TESS_LEVEL_OUTER;
878bf215546Sopenharmony_ci      break;
879bf215546Sopenharmony_ci   case SpvBuiltInTessLevelInner:
880bf215546Sopenharmony_ci      *location = VARYING_SLOT_TESS_LEVEL_INNER;
881bf215546Sopenharmony_ci      break;
882bf215546Sopenharmony_ci   case SpvBuiltInTessCoord:
883bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_TESS_COORD;
884bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
885bf215546Sopenharmony_ci      break;
886bf215546Sopenharmony_ci   case SpvBuiltInPatchVertices:
887bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_VERTICES_IN;
888bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
889bf215546Sopenharmony_ci      break;
890bf215546Sopenharmony_ci   case SpvBuiltInFragCoord:
891bf215546Sopenharmony_ci      vtn_assert(*mode == nir_var_shader_in);
892bf215546Sopenharmony_ci      *mode = nir_var_system_value;
893bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_FRAG_COORD;
894bf215546Sopenharmony_ci      break;
895bf215546Sopenharmony_ci   case SpvBuiltInPointCoord:
896bf215546Sopenharmony_ci      vtn_assert(*mode == nir_var_shader_in);
897bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
898bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_POINT_COORD;
899bf215546Sopenharmony_ci      break;
900bf215546Sopenharmony_ci   case SpvBuiltInFrontFacing:
901bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_FRONT_FACE;
902bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
903bf215546Sopenharmony_ci      break;
904bf215546Sopenharmony_ci   case SpvBuiltInSampleId:
905bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SAMPLE_ID;
906bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
907bf215546Sopenharmony_ci      break;
908bf215546Sopenharmony_ci   case SpvBuiltInSamplePosition:
909bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SAMPLE_POS;
910bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
911bf215546Sopenharmony_ci      break;
912bf215546Sopenharmony_ci   case SpvBuiltInSampleMask:
913bf215546Sopenharmony_ci      if (*mode == nir_var_shader_out) {
914bf215546Sopenharmony_ci         *location = FRAG_RESULT_SAMPLE_MASK;
915bf215546Sopenharmony_ci      } else {
916bf215546Sopenharmony_ci         *location = SYSTEM_VALUE_SAMPLE_MASK_IN;
917bf215546Sopenharmony_ci         set_mode_system_value(b, mode);
918bf215546Sopenharmony_ci      }
919bf215546Sopenharmony_ci      break;
920bf215546Sopenharmony_ci   case SpvBuiltInFragDepth:
921bf215546Sopenharmony_ci      *location = FRAG_RESULT_DEPTH;
922bf215546Sopenharmony_ci      vtn_assert(*mode == nir_var_shader_out);
923bf215546Sopenharmony_ci      break;
924bf215546Sopenharmony_ci   case SpvBuiltInHelperInvocation:
925bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_HELPER_INVOCATION;
926bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
927bf215546Sopenharmony_ci      break;
928bf215546Sopenharmony_ci   case SpvBuiltInNumWorkgroups:
929bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_NUM_WORKGROUPS;
930bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
931bf215546Sopenharmony_ci      break;
932bf215546Sopenharmony_ci   case SpvBuiltInWorkgroupSize:
933bf215546Sopenharmony_ci   case SpvBuiltInEnqueuedWorkgroupSize:
934bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_WORKGROUP_SIZE;
935bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
936bf215546Sopenharmony_ci      break;
937bf215546Sopenharmony_ci   case SpvBuiltInWorkgroupId:
938bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_WORKGROUP_ID;
939bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
940bf215546Sopenharmony_ci      break;
941bf215546Sopenharmony_ci   case SpvBuiltInLocalInvocationId:
942bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_LOCAL_INVOCATION_ID;
943bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
944bf215546Sopenharmony_ci      break;
945bf215546Sopenharmony_ci   case SpvBuiltInLocalInvocationIndex:
946bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_LOCAL_INVOCATION_INDEX;
947bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
948bf215546Sopenharmony_ci      break;
949bf215546Sopenharmony_ci   case SpvBuiltInGlobalInvocationId:
950bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_GLOBAL_INVOCATION_ID;
951bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
952bf215546Sopenharmony_ci      break;
953bf215546Sopenharmony_ci   case SpvBuiltInGlobalLinearId:
954bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX;
955bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
956bf215546Sopenharmony_ci      break;
957bf215546Sopenharmony_ci   case SpvBuiltInGlobalOffset:
958bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BASE_GLOBAL_INVOCATION_ID;
959bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
960bf215546Sopenharmony_ci      break;
961bf215546Sopenharmony_ci   case SpvBuiltInBaseVertex:
962bf215546Sopenharmony_ci      /* OpenGL gl_BaseVertex (SYSTEM_VALUE_BASE_VERTEX) is not the same
963bf215546Sopenharmony_ci       * semantic as Vulkan BaseVertex (SYSTEM_VALUE_FIRST_VERTEX).
964bf215546Sopenharmony_ci       */
965bf215546Sopenharmony_ci      if (b->options->environment == NIR_SPIRV_OPENGL)
966bf215546Sopenharmony_ci         *location = SYSTEM_VALUE_BASE_VERTEX;
967bf215546Sopenharmony_ci      else
968bf215546Sopenharmony_ci         *location = SYSTEM_VALUE_FIRST_VERTEX;
969bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
970bf215546Sopenharmony_ci      break;
971bf215546Sopenharmony_ci   case SpvBuiltInBaseInstance:
972bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BASE_INSTANCE;
973bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
974bf215546Sopenharmony_ci      break;
975bf215546Sopenharmony_ci   case SpvBuiltInDrawIndex:
976bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_DRAW_ID;
977bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
978bf215546Sopenharmony_ci      break;
979bf215546Sopenharmony_ci   case SpvBuiltInSubgroupSize:
980bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_SIZE;
981bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
982bf215546Sopenharmony_ci      break;
983bf215546Sopenharmony_ci   case SpvBuiltInSubgroupId:
984bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_ID;
985bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
986bf215546Sopenharmony_ci      break;
987bf215546Sopenharmony_ci   case SpvBuiltInSubgroupLocalInvocationId:
988bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_INVOCATION;
989bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
990bf215546Sopenharmony_ci      break;
991bf215546Sopenharmony_ci   case SpvBuiltInNumSubgroups:
992bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_NUM_SUBGROUPS;
993bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
994bf215546Sopenharmony_ci      break;
995bf215546Sopenharmony_ci   case SpvBuiltInDeviceIndex:
996bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_DEVICE_INDEX;
997bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
998bf215546Sopenharmony_ci      break;
999bf215546Sopenharmony_ci   case SpvBuiltInViewIndex:
1000bf215546Sopenharmony_ci      if (b->options && b->options->view_index_is_input) {
1001bf215546Sopenharmony_ci         *location = VARYING_SLOT_VIEW_INDEX;
1002bf215546Sopenharmony_ci         vtn_assert(*mode == nir_var_shader_in);
1003bf215546Sopenharmony_ci      } else {
1004bf215546Sopenharmony_ci         *location = SYSTEM_VALUE_VIEW_INDEX;
1005bf215546Sopenharmony_ci         set_mode_system_value(b, mode);
1006bf215546Sopenharmony_ci      }
1007bf215546Sopenharmony_ci      break;
1008bf215546Sopenharmony_ci   case SpvBuiltInSubgroupEqMask:
1009bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_EQ_MASK,
1010bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1011bf215546Sopenharmony_ci      break;
1012bf215546Sopenharmony_ci   case SpvBuiltInSubgroupGeMask:
1013bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_GE_MASK,
1014bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1015bf215546Sopenharmony_ci      break;
1016bf215546Sopenharmony_ci   case SpvBuiltInSubgroupGtMask:
1017bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_GT_MASK,
1018bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1019bf215546Sopenharmony_ci      break;
1020bf215546Sopenharmony_ci   case SpvBuiltInSubgroupLeMask:
1021bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_LE_MASK,
1022bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1023bf215546Sopenharmony_ci      break;
1024bf215546Sopenharmony_ci   case SpvBuiltInSubgroupLtMask:
1025bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_SUBGROUP_LT_MASK,
1026bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1027bf215546Sopenharmony_ci      break;
1028bf215546Sopenharmony_ci   case SpvBuiltInFragStencilRefEXT:
1029bf215546Sopenharmony_ci      *location = FRAG_RESULT_STENCIL;
1030bf215546Sopenharmony_ci      vtn_assert(*mode == nir_var_shader_out);
1031bf215546Sopenharmony_ci      break;
1032bf215546Sopenharmony_ci   case SpvBuiltInWorkDim:
1033bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_WORK_DIM;
1034bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1035bf215546Sopenharmony_ci      break;
1036bf215546Sopenharmony_ci   case SpvBuiltInGlobalSize:
1037bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_GLOBAL_GROUP_SIZE;
1038bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1039bf215546Sopenharmony_ci      break;
1040bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordNoPerspAMD:
1041bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL;
1042bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1043bf215546Sopenharmony_ci      break;
1044bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordNoPerspCentroidAMD:
1045bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID;
1046bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1047bf215546Sopenharmony_ci      break;
1048bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordNoPerspSampleAMD:
1049bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_LINEAR_SAMPLE;
1050bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1051bf215546Sopenharmony_ci      break;
1052bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordSmoothAMD:
1053bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL;
1054bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1055bf215546Sopenharmony_ci      break;
1056bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordSmoothCentroidAMD:
1057bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID;
1058bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1059bf215546Sopenharmony_ci      break;
1060bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordSmoothSampleAMD:
1061bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE;
1062bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1063bf215546Sopenharmony_ci      break;
1064bf215546Sopenharmony_ci   case SpvBuiltInBaryCoordPullModelAMD:
1065bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_BARYCENTRIC_PULL_MODEL;
1066bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1067bf215546Sopenharmony_ci      break;
1068bf215546Sopenharmony_ci   case SpvBuiltInLaunchIdKHR:
1069bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_LAUNCH_ID;
1070bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1071bf215546Sopenharmony_ci      break;
1072bf215546Sopenharmony_ci   case SpvBuiltInLaunchSizeKHR:
1073bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_LAUNCH_SIZE;
1074bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1075bf215546Sopenharmony_ci      break;
1076bf215546Sopenharmony_ci   case SpvBuiltInWorldRayOriginKHR:
1077bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_WORLD_ORIGIN;
1078bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1079bf215546Sopenharmony_ci      break;
1080bf215546Sopenharmony_ci   case SpvBuiltInWorldRayDirectionKHR:
1081bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_WORLD_DIRECTION;
1082bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1083bf215546Sopenharmony_ci      break;
1084bf215546Sopenharmony_ci   case SpvBuiltInObjectRayOriginKHR:
1085bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_OBJECT_ORIGIN;
1086bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1087bf215546Sopenharmony_ci      break;
1088bf215546Sopenharmony_ci   case SpvBuiltInObjectRayDirectionKHR:
1089bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_OBJECT_DIRECTION;
1090bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1091bf215546Sopenharmony_ci      break;
1092bf215546Sopenharmony_ci   case SpvBuiltInObjectToWorldKHR:
1093bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_OBJECT_TO_WORLD;
1094bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1095bf215546Sopenharmony_ci      break;
1096bf215546Sopenharmony_ci   case SpvBuiltInWorldToObjectKHR:
1097bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_WORLD_TO_OBJECT;
1098bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1099bf215546Sopenharmony_ci      break;
1100bf215546Sopenharmony_ci   case SpvBuiltInRayTminKHR:
1101bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_T_MIN;
1102bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1103bf215546Sopenharmony_ci      break;
1104bf215546Sopenharmony_ci   case SpvBuiltInRayTmaxKHR:
1105bf215546Sopenharmony_ci   case SpvBuiltInHitTNV:
1106bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_T_MAX;
1107bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1108bf215546Sopenharmony_ci      break;
1109bf215546Sopenharmony_ci   case SpvBuiltInInstanceCustomIndexKHR:
1110bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_INSTANCE_CUSTOM_INDEX;
1111bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1112bf215546Sopenharmony_ci      break;
1113bf215546Sopenharmony_ci   case SpvBuiltInHitKindKHR:
1114bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_HIT_KIND;
1115bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1116bf215546Sopenharmony_ci      break;
1117bf215546Sopenharmony_ci   case SpvBuiltInIncomingRayFlagsKHR:
1118bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_FLAGS;
1119bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1120bf215546Sopenharmony_ci      break;
1121bf215546Sopenharmony_ci   case SpvBuiltInRayGeometryIndexKHR:
1122bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_RAY_GEOMETRY_INDEX;
1123bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1124bf215546Sopenharmony_ci      break;
1125bf215546Sopenharmony_ci   case SpvBuiltInCullMaskKHR:
1126bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_CULL_MASK;
1127bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1128bf215546Sopenharmony_ci      break;
1129bf215546Sopenharmony_ci   case SpvBuiltInShadingRateKHR:
1130bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_FRAG_SHADING_RATE;
1131bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1132bf215546Sopenharmony_ci      break;
1133bf215546Sopenharmony_ci   case SpvBuiltInPrimitiveShadingRateKHR:
1134bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_VERTEX ||
1135bf215546Sopenharmony_ci          b->shader->info.stage == MESA_SHADER_GEOMETRY ||
1136bf215546Sopenharmony_ci          b->shader->info.stage == MESA_SHADER_MESH) {
1137bf215546Sopenharmony_ci         *location = VARYING_SLOT_PRIMITIVE_SHADING_RATE;
1138bf215546Sopenharmony_ci         *mode = nir_var_shader_out;
1139bf215546Sopenharmony_ci      } else {
1140bf215546Sopenharmony_ci         vtn_fail("invalid stage for SpvBuiltInPrimitiveShadingRateKHR");
1141bf215546Sopenharmony_ci      }
1142bf215546Sopenharmony_ci      break;
1143bf215546Sopenharmony_ci   case SpvBuiltInPrimitiveCountNV:
1144bf215546Sopenharmony_ci      *location = VARYING_SLOT_PRIMITIVE_COUNT;
1145bf215546Sopenharmony_ci      break;
1146bf215546Sopenharmony_ci   case SpvBuiltInPrimitiveIndicesNV:
1147bf215546Sopenharmony_ci      *location = VARYING_SLOT_PRIMITIVE_INDICES;
1148bf215546Sopenharmony_ci      break;
1149bf215546Sopenharmony_ci   case SpvBuiltInTaskCountNV:
1150bf215546Sopenharmony_ci      /* NV_mesh_shader only. */
1151bf215546Sopenharmony_ci      *location = VARYING_SLOT_TASK_COUNT;
1152bf215546Sopenharmony_ci      *mode = nir_var_shader_out;
1153bf215546Sopenharmony_ci      break;
1154bf215546Sopenharmony_ci   case SpvBuiltInMeshViewCountNV:
1155bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_MESH_VIEW_COUNT;
1156bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1157bf215546Sopenharmony_ci      break;
1158bf215546Sopenharmony_ci   case SpvBuiltInMeshViewIndicesNV:
1159bf215546Sopenharmony_ci      *location = SYSTEM_VALUE_MESH_VIEW_INDICES;
1160bf215546Sopenharmony_ci      set_mode_system_value(b, mode);
1161bf215546Sopenharmony_ci      break;
1162bf215546Sopenharmony_ci   default:
1163bf215546Sopenharmony_ci      vtn_fail("Unsupported builtin: %s (%u)",
1164bf215546Sopenharmony_ci               spirv_builtin_to_string(builtin), builtin);
1165bf215546Sopenharmony_ci   }
1166bf215546Sopenharmony_ci}
1167bf215546Sopenharmony_ci
1168bf215546Sopenharmony_cistatic void
1169bf215546Sopenharmony_ciapply_var_decoration(struct vtn_builder *b,
1170bf215546Sopenharmony_ci                     struct nir_variable_data *var_data,
1171bf215546Sopenharmony_ci                     const struct vtn_decoration *dec)
1172bf215546Sopenharmony_ci{
1173bf215546Sopenharmony_ci   switch (dec->decoration) {
1174bf215546Sopenharmony_ci   case SpvDecorationRelaxedPrecision:
1175bf215546Sopenharmony_ci      var_data->precision = GLSL_PRECISION_MEDIUM;
1176bf215546Sopenharmony_ci      break;
1177bf215546Sopenharmony_ci   case SpvDecorationNoPerspective:
1178bf215546Sopenharmony_ci      var_data->interpolation = INTERP_MODE_NOPERSPECTIVE;
1179bf215546Sopenharmony_ci      break;
1180bf215546Sopenharmony_ci   case SpvDecorationFlat:
1181bf215546Sopenharmony_ci      var_data->interpolation = INTERP_MODE_FLAT;
1182bf215546Sopenharmony_ci      break;
1183bf215546Sopenharmony_ci   case SpvDecorationExplicitInterpAMD:
1184bf215546Sopenharmony_ci      var_data->interpolation = INTERP_MODE_EXPLICIT;
1185bf215546Sopenharmony_ci      break;
1186bf215546Sopenharmony_ci   case SpvDecorationCentroid:
1187bf215546Sopenharmony_ci      var_data->centroid = true;
1188bf215546Sopenharmony_ci      break;
1189bf215546Sopenharmony_ci   case SpvDecorationSample:
1190bf215546Sopenharmony_ci      var_data->sample = true;
1191bf215546Sopenharmony_ci      break;
1192bf215546Sopenharmony_ci   case SpvDecorationInvariant:
1193bf215546Sopenharmony_ci      var_data->invariant = true;
1194bf215546Sopenharmony_ci      break;
1195bf215546Sopenharmony_ci   case SpvDecorationConstant:
1196bf215546Sopenharmony_ci      var_data->read_only = true;
1197bf215546Sopenharmony_ci      break;
1198bf215546Sopenharmony_ci   case SpvDecorationNonReadable:
1199bf215546Sopenharmony_ci      var_data->access |= ACCESS_NON_READABLE;
1200bf215546Sopenharmony_ci      break;
1201bf215546Sopenharmony_ci   case SpvDecorationNonWritable:
1202bf215546Sopenharmony_ci      var_data->read_only = true;
1203bf215546Sopenharmony_ci      var_data->access |= ACCESS_NON_WRITEABLE;
1204bf215546Sopenharmony_ci      break;
1205bf215546Sopenharmony_ci   case SpvDecorationRestrict:
1206bf215546Sopenharmony_ci      var_data->access |= ACCESS_RESTRICT;
1207bf215546Sopenharmony_ci      break;
1208bf215546Sopenharmony_ci   case SpvDecorationAliased:
1209bf215546Sopenharmony_ci      var_data->access &= ~ACCESS_RESTRICT;
1210bf215546Sopenharmony_ci      break;
1211bf215546Sopenharmony_ci   case SpvDecorationVolatile:
1212bf215546Sopenharmony_ci      var_data->access |= ACCESS_VOLATILE;
1213bf215546Sopenharmony_ci      break;
1214bf215546Sopenharmony_ci   case SpvDecorationCoherent:
1215bf215546Sopenharmony_ci      var_data->access |= ACCESS_COHERENT;
1216bf215546Sopenharmony_ci      break;
1217bf215546Sopenharmony_ci   case SpvDecorationComponent:
1218bf215546Sopenharmony_ci      var_data->location_frac = dec->operands[0];
1219bf215546Sopenharmony_ci      break;
1220bf215546Sopenharmony_ci   case SpvDecorationIndex:
1221bf215546Sopenharmony_ci      var_data->index = dec->operands[0];
1222bf215546Sopenharmony_ci      break;
1223bf215546Sopenharmony_ci   case SpvDecorationBuiltIn: {
1224bf215546Sopenharmony_ci      SpvBuiltIn builtin = dec->operands[0];
1225bf215546Sopenharmony_ci
1226bf215546Sopenharmony_ci      nir_variable_mode mode = var_data->mode;
1227bf215546Sopenharmony_ci      vtn_get_builtin_location(b, builtin, &var_data->location, &mode);
1228bf215546Sopenharmony_ci      var_data->mode = mode;
1229bf215546Sopenharmony_ci
1230bf215546Sopenharmony_ci      switch (builtin) {
1231bf215546Sopenharmony_ci      case SpvBuiltInTessLevelOuter:
1232bf215546Sopenharmony_ci      case SpvBuiltInTessLevelInner:
1233bf215546Sopenharmony_ci      case SpvBuiltInClipDistance:
1234bf215546Sopenharmony_ci      case SpvBuiltInClipDistancePerViewNV:
1235bf215546Sopenharmony_ci      case SpvBuiltInCullDistance:
1236bf215546Sopenharmony_ci      case SpvBuiltInCullDistancePerViewNV:
1237bf215546Sopenharmony_ci         var_data->compact = true;
1238bf215546Sopenharmony_ci         break;
1239bf215546Sopenharmony_ci      default:
1240bf215546Sopenharmony_ci         break;
1241bf215546Sopenharmony_ci      }
1242bf215546Sopenharmony_ci
1243bf215546Sopenharmony_ci      break;
1244bf215546Sopenharmony_ci   }
1245bf215546Sopenharmony_ci
1246bf215546Sopenharmony_ci   case SpvDecorationSpecId:
1247bf215546Sopenharmony_ci   case SpvDecorationRowMajor:
1248bf215546Sopenharmony_ci   case SpvDecorationColMajor:
1249bf215546Sopenharmony_ci   case SpvDecorationMatrixStride:
1250bf215546Sopenharmony_ci   case SpvDecorationUniform:
1251bf215546Sopenharmony_ci   case SpvDecorationUniformId:
1252bf215546Sopenharmony_ci   case SpvDecorationLinkageAttributes:
1253bf215546Sopenharmony_ci      break; /* Do nothing with these here */
1254bf215546Sopenharmony_ci
1255bf215546Sopenharmony_ci   case SpvDecorationPatch:
1256bf215546Sopenharmony_ci      var_data->patch = true;
1257bf215546Sopenharmony_ci      break;
1258bf215546Sopenharmony_ci
1259bf215546Sopenharmony_ci   case SpvDecorationLocation:
1260bf215546Sopenharmony_ci      vtn_fail("Should be handled earlier by var_decoration_cb()");
1261bf215546Sopenharmony_ci
1262bf215546Sopenharmony_ci   case SpvDecorationBlock:
1263bf215546Sopenharmony_ci   case SpvDecorationBufferBlock:
1264bf215546Sopenharmony_ci   case SpvDecorationArrayStride:
1265bf215546Sopenharmony_ci   case SpvDecorationGLSLShared:
1266bf215546Sopenharmony_ci   case SpvDecorationGLSLPacked:
1267bf215546Sopenharmony_ci      break; /* These can apply to a type but we don't care about them */
1268bf215546Sopenharmony_ci
1269bf215546Sopenharmony_ci   case SpvDecorationBinding:
1270bf215546Sopenharmony_ci   case SpvDecorationDescriptorSet:
1271bf215546Sopenharmony_ci   case SpvDecorationNoContraction:
1272bf215546Sopenharmony_ci   case SpvDecorationInputAttachmentIndex:
1273bf215546Sopenharmony_ci      vtn_warn("Decoration not allowed for variable or structure member: %s",
1274bf215546Sopenharmony_ci               spirv_decoration_to_string(dec->decoration));
1275bf215546Sopenharmony_ci      break;
1276bf215546Sopenharmony_ci
1277bf215546Sopenharmony_ci   case SpvDecorationXfbBuffer:
1278bf215546Sopenharmony_ci      var_data->explicit_xfb_buffer = true;
1279bf215546Sopenharmony_ci      var_data->xfb.buffer = dec->operands[0];
1280bf215546Sopenharmony_ci      var_data->always_active_io = true;
1281bf215546Sopenharmony_ci      break;
1282bf215546Sopenharmony_ci   case SpvDecorationXfbStride:
1283bf215546Sopenharmony_ci      var_data->explicit_xfb_stride = true;
1284bf215546Sopenharmony_ci      var_data->xfb.stride = dec->operands[0];
1285bf215546Sopenharmony_ci      break;
1286bf215546Sopenharmony_ci   case SpvDecorationOffset:
1287bf215546Sopenharmony_ci      var_data->explicit_offset = true;
1288bf215546Sopenharmony_ci      var_data->offset = dec->operands[0];
1289bf215546Sopenharmony_ci      break;
1290bf215546Sopenharmony_ci
1291bf215546Sopenharmony_ci   case SpvDecorationStream:
1292bf215546Sopenharmony_ci      var_data->stream = dec->operands[0];
1293bf215546Sopenharmony_ci      break;
1294bf215546Sopenharmony_ci
1295bf215546Sopenharmony_ci   case SpvDecorationCPacked:
1296bf215546Sopenharmony_ci   case SpvDecorationSaturatedConversion:
1297bf215546Sopenharmony_ci   case SpvDecorationFuncParamAttr:
1298bf215546Sopenharmony_ci   case SpvDecorationFPRoundingMode:
1299bf215546Sopenharmony_ci   case SpvDecorationFPFastMathMode:
1300bf215546Sopenharmony_ci   case SpvDecorationAlignment:
1301bf215546Sopenharmony_ci      if (b->shader->info.stage != MESA_SHADER_KERNEL) {
1302bf215546Sopenharmony_ci         vtn_warn("Decoration only allowed for CL-style kernels: %s",
1303bf215546Sopenharmony_ci                  spirv_decoration_to_string(dec->decoration));
1304bf215546Sopenharmony_ci      }
1305bf215546Sopenharmony_ci      break;
1306bf215546Sopenharmony_ci
1307bf215546Sopenharmony_ci   case SpvDecorationUserSemantic:
1308bf215546Sopenharmony_ci   case SpvDecorationUserTypeGOOGLE:
1309bf215546Sopenharmony_ci      /* User semantic decorations can safely be ignored by the driver. */
1310bf215546Sopenharmony_ci      break;
1311bf215546Sopenharmony_ci
1312bf215546Sopenharmony_ci   case SpvDecorationRestrictPointerEXT:
1313bf215546Sopenharmony_ci   case SpvDecorationAliasedPointerEXT:
1314bf215546Sopenharmony_ci      /* TODO: We should actually plumb alias information through NIR. */
1315bf215546Sopenharmony_ci      break;
1316bf215546Sopenharmony_ci
1317bf215546Sopenharmony_ci   case SpvDecorationPerPrimitiveNV:
1318bf215546Sopenharmony_ci      vtn_fail_if(
1319bf215546Sopenharmony_ci         !(b->shader->info.stage == MESA_SHADER_MESH && var_data->mode == nir_var_shader_out) &&
1320bf215546Sopenharmony_ci         !(b->shader->info.stage == MESA_SHADER_FRAGMENT && var_data->mode == nir_var_shader_in),
1321bf215546Sopenharmony_ci         "PerPrimitiveNV decoration only allowed for Mesh shader outputs or Fragment shader inputs");
1322bf215546Sopenharmony_ci      var_data->per_primitive = true;
1323bf215546Sopenharmony_ci      break;
1324bf215546Sopenharmony_ci
1325bf215546Sopenharmony_ci   case SpvDecorationPerTaskNV:
1326bf215546Sopenharmony_ci      vtn_fail_if(
1327bf215546Sopenharmony_ci         (b->shader->info.stage != MESA_SHADER_MESH &&
1328bf215546Sopenharmony_ci          b->shader->info.stage != MESA_SHADER_TASK) ||
1329bf215546Sopenharmony_ci         var_data->mode != nir_var_mem_task_payload,
1330bf215546Sopenharmony_ci         "PerTaskNV decoration only allowed on Task/Mesh payload variables.");
1331bf215546Sopenharmony_ci      break;
1332bf215546Sopenharmony_ci
1333bf215546Sopenharmony_ci   case SpvDecorationPerViewNV:
1334bf215546Sopenharmony_ci      vtn_fail_if(b->shader->info.stage != MESA_SHADER_MESH,
1335bf215546Sopenharmony_ci                  "PerViewNV decoration only allowed in Mesh shaders");
1336bf215546Sopenharmony_ci      var_data->per_view = true;
1337bf215546Sopenharmony_ci      break;
1338bf215546Sopenharmony_ci
1339bf215546Sopenharmony_ci   default:
1340bf215546Sopenharmony_ci      vtn_fail_with_decoration("Unhandled decoration", dec->decoration);
1341bf215546Sopenharmony_ci   }
1342bf215546Sopenharmony_ci}
1343bf215546Sopenharmony_ci
1344bf215546Sopenharmony_cistatic void
1345bf215546Sopenharmony_cigather_var_kind_cb(struct vtn_builder *b, struct vtn_value *val, int member,
1346bf215546Sopenharmony_ci                   const struct vtn_decoration *dec, void *void_var)
1347bf215546Sopenharmony_ci{
1348bf215546Sopenharmony_ci   struct vtn_variable *vtn_var = void_var;
1349bf215546Sopenharmony_ci   switch (dec->decoration) {
1350bf215546Sopenharmony_ci   case SpvDecorationPatch:
1351bf215546Sopenharmony_ci      vtn_var->var->data.patch = true;
1352bf215546Sopenharmony_ci      break;
1353bf215546Sopenharmony_ci   case SpvDecorationPerPrimitiveNV:
1354bf215546Sopenharmony_ci      vtn_var->var->data.per_primitive = true;
1355bf215546Sopenharmony_ci      break;
1356bf215546Sopenharmony_ci   case SpvDecorationPerViewNV:
1357bf215546Sopenharmony_ci      vtn_var->var->data.per_view = true;
1358bf215546Sopenharmony_ci      break;
1359bf215546Sopenharmony_ci   default:
1360bf215546Sopenharmony_ci      /* Nothing to do. */
1361bf215546Sopenharmony_ci      break;
1362bf215546Sopenharmony_ci   }
1363bf215546Sopenharmony_ci}
1364bf215546Sopenharmony_ci
1365bf215546Sopenharmony_cistatic void
1366bf215546Sopenharmony_civar_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
1367bf215546Sopenharmony_ci                  const struct vtn_decoration *dec, void *void_var)
1368bf215546Sopenharmony_ci{
1369bf215546Sopenharmony_ci   struct vtn_variable *vtn_var = void_var;
1370bf215546Sopenharmony_ci
1371bf215546Sopenharmony_ci   /* Handle decorations that apply to a vtn_variable as a whole */
1372bf215546Sopenharmony_ci   switch (dec->decoration) {
1373bf215546Sopenharmony_ci   case SpvDecorationBinding:
1374bf215546Sopenharmony_ci      vtn_var->binding = dec->operands[0];
1375bf215546Sopenharmony_ci      vtn_var->explicit_binding = true;
1376bf215546Sopenharmony_ci      return;
1377bf215546Sopenharmony_ci   case SpvDecorationDescriptorSet:
1378bf215546Sopenharmony_ci      vtn_var->descriptor_set = dec->operands[0];
1379bf215546Sopenharmony_ci      return;
1380bf215546Sopenharmony_ci   case SpvDecorationInputAttachmentIndex:
1381bf215546Sopenharmony_ci      vtn_var->input_attachment_index = dec->operands[0];
1382bf215546Sopenharmony_ci      return;
1383bf215546Sopenharmony_ci   case SpvDecorationPatch:
1384bf215546Sopenharmony_ci      vtn_var->var->data.patch = true;
1385bf215546Sopenharmony_ci      break;
1386bf215546Sopenharmony_ci   case SpvDecorationOffset:
1387bf215546Sopenharmony_ci      vtn_var->offset = dec->operands[0];
1388bf215546Sopenharmony_ci      break;
1389bf215546Sopenharmony_ci   case SpvDecorationNonWritable:
1390bf215546Sopenharmony_ci      vtn_var->access |= ACCESS_NON_WRITEABLE;
1391bf215546Sopenharmony_ci      break;
1392bf215546Sopenharmony_ci   case SpvDecorationNonReadable:
1393bf215546Sopenharmony_ci      vtn_var->access |= ACCESS_NON_READABLE;
1394bf215546Sopenharmony_ci      break;
1395bf215546Sopenharmony_ci   case SpvDecorationVolatile:
1396bf215546Sopenharmony_ci      vtn_var->access |= ACCESS_VOLATILE;
1397bf215546Sopenharmony_ci      break;
1398bf215546Sopenharmony_ci   case SpvDecorationCoherent:
1399bf215546Sopenharmony_ci      vtn_var->access |= ACCESS_COHERENT;
1400bf215546Sopenharmony_ci      break;
1401bf215546Sopenharmony_ci   case SpvDecorationCounterBuffer:
1402bf215546Sopenharmony_ci      /* Counter buffer decorations can safely be ignored by the driver. */
1403bf215546Sopenharmony_ci      return;
1404bf215546Sopenharmony_ci   default:
1405bf215546Sopenharmony_ci      break;
1406bf215546Sopenharmony_ci   }
1407bf215546Sopenharmony_ci
1408bf215546Sopenharmony_ci   if (val->value_type == vtn_value_type_pointer) {
1409bf215546Sopenharmony_ci      assert(val->pointer->var == void_var);
1410bf215546Sopenharmony_ci      assert(member == -1);
1411bf215546Sopenharmony_ci   } else {
1412bf215546Sopenharmony_ci      assert(val->value_type == vtn_value_type_type);
1413bf215546Sopenharmony_ci   }
1414bf215546Sopenharmony_ci
1415bf215546Sopenharmony_ci   /* Location is odd.  If applied to a split structure, we have to walk the
1416bf215546Sopenharmony_ci    * whole thing and accumulate the location.  It's easier to handle as a
1417bf215546Sopenharmony_ci    * special case.
1418bf215546Sopenharmony_ci    */
1419bf215546Sopenharmony_ci   if (dec->decoration == SpvDecorationLocation) {
1420bf215546Sopenharmony_ci      unsigned location = dec->operands[0];
1421bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_FRAGMENT &&
1422bf215546Sopenharmony_ci          vtn_var->mode == vtn_variable_mode_output) {
1423bf215546Sopenharmony_ci         location += FRAG_RESULT_DATA0;
1424bf215546Sopenharmony_ci      } else if (b->shader->info.stage == MESA_SHADER_VERTEX &&
1425bf215546Sopenharmony_ci                 vtn_var->mode == vtn_variable_mode_input) {
1426bf215546Sopenharmony_ci         location += VERT_ATTRIB_GENERIC0;
1427bf215546Sopenharmony_ci      } else if (vtn_var->mode == vtn_variable_mode_input ||
1428bf215546Sopenharmony_ci                 vtn_var->mode == vtn_variable_mode_output) {
1429bf215546Sopenharmony_ci         location += vtn_var->var->data.patch ? VARYING_SLOT_PATCH0 : VARYING_SLOT_VAR0;
1430bf215546Sopenharmony_ci      } else if (vtn_var->mode == vtn_variable_mode_call_data ||
1431bf215546Sopenharmony_ci                 vtn_var->mode == vtn_variable_mode_ray_payload) {
1432bf215546Sopenharmony_ci         /* This location is fine as-is */
1433bf215546Sopenharmony_ci      } else if (vtn_var->mode != vtn_variable_mode_uniform &&
1434bf215546Sopenharmony_ci                 vtn_var->mode != vtn_variable_mode_image) {
1435bf215546Sopenharmony_ci         vtn_warn("Location must be on input, output, uniform, sampler or "
1436bf215546Sopenharmony_ci                  "image variable");
1437bf215546Sopenharmony_ci         return;
1438bf215546Sopenharmony_ci      }
1439bf215546Sopenharmony_ci
1440bf215546Sopenharmony_ci      if (vtn_var->var->num_members == 0) {
1441bf215546Sopenharmony_ci         /* This handles the member and lone variable cases */
1442bf215546Sopenharmony_ci         vtn_var->var->data.location = location;
1443bf215546Sopenharmony_ci      } else {
1444bf215546Sopenharmony_ci         /* This handles the structure member case */
1445bf215546Sopenharmony_ci         assert(vtn_var->var->members);
1446bf215546Sopenharmony_ci
1447bf215546Sopenharmony_ci         if (member == -1)
1448bf215546Sopenharmony_ci            vtn_var->base_location = location;
1449bf215546Sopenharmony_ci         else
1450bf215546Sopenharmony_ci            vtn_var->var->members[member].location = location;
1451bf215546Sopenharmony_ci      }
1452bf215546Sopenharmony_ci
1453bf215546Sopenharmony_ci      return;
1454bf215546Sopenharmony_ci   } else {
1455bf215546Sopenharmony_ci      if (vtn_var->var) {
1456bf215546Sopenharmony_ci         if (vtn_var->var->num_members == 0) {
1457bf215546Sopenharmony_ci            /* We call this function on types as well as variables and not all
1458bf215546Sopenharmony_ci             * struct types get split so we can end up having stray member
1459bf215546Sopenharmony_ci             * decorations; just ignore them.
1460bf215546Sopenharmony_ci             */
1461bf215546Sopenharmony_ci            if (member == -1)
1462bf215546Sopenharmony_ci               apply_var_decoration(b, &vtn_var->var->data, dec);
1463bf215546Sopenharmony_ci         } else if (member >= 0) {
1464bf215546Sopenharmony_ci            /* Member decorations must come from a type */
1465bf215546Sopenharmony_ci            assert(val->value_type == vtn_value_type_type);
1466bf215546Sopenharmony_ci            apply_var_decoration(b, &vtn_var->var->members[member], dec);
1467bf215546Sopenharmony_ci         } else {
1468bf215546Sopenharmony_ci            unsigned length =
1469bf215546Sopenharmony_ci               glsl_get_length(glsl_without_array(vtn_var->type->type));
1470bf215546Sopenharmony_ci            for (unsigned i = 0; i < length; i++)
1471bf215546Sopenharmony_ci               apply_var_decoration(b, &vtn_var->var->members[i], dec);
1472bf215546Sopenharmony_ci         }
1473bf215546Sopenharmony_ci      } else {
1474bf215546Sopenharmony_ci         /* A few variables, those with external storage, have no actual
1475bf215546Sopenharmony_ci          * nir_variables associated with them.  Fortunately, all decorations
1476bf215546Sopenharmony_ci          * we care about for those variables are on the type only.
1477bf215546Sopenharmony_ci          */
1478bf215546Sopenharmony_ci         vtn_assert(vtn_var->mode == vtn_variable_mode_ubo ||
1479bf215546Sopenharmony_ci                    vtn_var->mode == vtn_variable_mode_ssbo ||
1480bf215546Sopenharmony_ci                    vtn_var->mode == vtn_variable_mode_push_constant);
1481bf215546Sopenharmony_ci      }
1482bf215546Sopenharmony_ci   }
1483bf215546Sopenharmony_ci}
1484bf215546Sopenharmony_ci
1485bf215546Sopenharmony_cienum vtn_variable_mode
1486bf215546Sopenharmony_civtn_storage_class_to_mode(struct vtn_builder *b,
1487bf215546Sopenharmony_ci                          SpvStorageClass class,
1488bf215546Sopenharmony_ci                          struct vtn_type *interface_type,
1489bf215546Sopenharmony_ci                          nir_variable_mode *nir_mode_out)
1490bf215546Sopenharmony_ci{
1491bf215546Sopenharmony_ci   enum vtn_variable_mode mode;
1492bf215546Sopenharmony_ci   nir_variable_mode nir_mode;
1493bf215546Sopenharmony_ci   switch (class) {
1494bf215546Sopenharmony_ci   case SpvStorageClassUniform:
1495bf215546Sopenharmony_ci      /* Assume it's an UBO if we lack the interface_type. */
1496bf215546Sopenharmony_ci      if (!interface_type || interface_type->block) {
1497bf215546Sopenharmony_ci         mode = vtn_variable_mode_ubo;
1498bf215546Sopenharmony_ci         nir_mode = nir_var_mem_ubo;
1499bf215546Sopenharmony_ci      } else if (interface_type->buffer_block) {
1500bf215546Sopenharmony_ci         mode = vtn_variable_mode_ssbo;
1501bf215546Sopenharmony_ci         nir_mode = nir_var_mem_ssbo;
1502bf215546Sopenharmony_ci      } else {
1503bf215546Sopenharmony_ci         /* Default-block uniforms, coming from gl_spirv */
1504bf215546Sopenharmony_ci         mode = vtn_variable_mode_uniform;
1505bf215546Sopenharmony_ci         nir_mode = nir_var_uniform;
1506bf215546Sopenharmony_ci      }
1507bf215546Sopenharmony_ci      break;
1508bf215546Sopenharmony_ci   case SpvStorageClassStorageBuffer:
1509bf215546Sopenharmony_ci      mode = vtn_variable_mode_ssbo;
1510bf215546Sopenharmony_ci      nir_mode = nir_var_mem_ssbo;
1511bf215546Sopenharmony_ci      break;
1512bf215546Sopenharmony_ci   case SpvStorageClassPhysicalStorageBuffer:
1513bf215546Sopenharmony_ci      mode = vtn_variable_mode_phys_ssbo;
1514bf215546Sopenharmony_ci      nir_mode = nir_var_mem_global;
1515bf215546Sopenharmony_ci      break;
1516bf215546Sopenharmony_ci   case SpvStorageClassUniformConstant:
1517bf215546Sopenharmony_ci      /* interface_type is only NULL when OpTypeForwardPointer is used and
1518bf215546Sopenharmony_ci       * OpTypeForwardPointer can only be used for struct types, not images or
1519bf215546Sopenharmony_ci       * acceleration structures.
1520bf215546Sopenharmony_ci       */
1521bf215546Sopenharmony_ci      if (interface_type)
1522bf215546Sopenharmony_ci         interface_type = vtn_type_without_array(interface_type);
1523bf215546Sopenharmony_ci
1524bf215546Sopenharmony_ci      if (interface_type &&
1525bf215546Sopenharmony_ci          interface_type->base_type == vtn_base_type_image &&
1526bf215546Sopenharmony_ci          glsl_type_is_image(interface_type->glsl_image)) {
1527bf215546Sopenharmony_ci         mode = vtn_variable_mode_image;
1528bf215546Sopenharmony_ci         nir_mode = nir_var_image;
1529bf215546Sopenharmony_ci      } else if (b->shader->info.stage == MESA_SHADER_KERNEL) {
1530bf215546Sopenharmony_ci         mode = vtn_variable_mode_constant;
1531bf215546Sopenharmony_ci         nir_mode = nir_var_mem_constant;
1532bf215546Sopenharmony_ci      } else {
1533bf215546Sopenharmony_ci         /* interface_type is only NULL when OpTypeForwardPointer is used and
1534bf215546Sopenharmony_ci          * OpTypeForwardPointer cannot be used with the UniformConstant
1535bf215546Sopenharmony_ci          * storage class.
1536bf215546Sopenharmony_ci          */
1537bf215546Sopenharmony_ci         assert(interface_type != NULL);
1538bf215546Sopenharmony_ci         if (interface_type->base_type == vtn_base_type_accel_struct) {
1539bf215546Sopenharmony_ci            mode = vtn_variable_mode_accel_struct;
1540bf215546Sopenharmony_ci            nir_mode = nir_var_uniform;
1541bf215546Sopenharmony_ci         } else {
1542bf215546Sopenharmony_ci            mode = vtn_variable_mode_uniform;
1543bf215546Sopenharmony_ci            nir_mode = nir_var_uniform;
1544bf215546Sopenharmony_ci         }
1545bf215546Sopenharmony_ci      }
1546bf215546Sopenharmony_ci      break;
1547bf215546Sopenharmony_ci   case SpvStorageClassPushConstant:
1548bf215546Sopenharmony_ci      mode = vtn_variable_mode_push_constant;
1549bf215546Sopenharmony_ci      nir_mode = nir_var_mem_push_const;
1550bf215546Sopenharmony_ci      break;
1551bf215546Sopenharmony_ci   case SpvStorageClassInput:
1552bf215546Sopenharmony_ci      mode = vtn_variable_mode_input;
1553bf215546Sopenharmony_ci      nir_mode = nir_var_shader_in;
1554bf215546Sopenharmony_ci
1555bf215546Sopenharmony_ci      /* NV_mesh_shader: fixup due to lack of dedicated storage class */
1556bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_MESH) {
1557bf215546Sopenharmony_ci         mode = vtn_variable_mode_task_payload;
1558bf215546Sopenharmony_ci         nir_mode = nir_var_mem_task_payload;
1559bf215546Sopenharmony_ci      }
1560bf215546Sopenharmony_ci      break;
1561bf215546Sopenharmony_ci   case SpvStorageClassOutput:
1562bf215546Sopenharmony_ci      mode = vtn_variable_mode_output;
1563bf215546Sopenharmony_ci      nir_mode = nir_var_shader_out;
1564bf215546Sopenharmony_ci
1565bf215546Sopenharmony_ci      /* NV_mesh_shader: fixup due to lack of dedicated storage class */
1566bf215546Sopenharmony_ci      if (b->shader->info.stage == MESA_SHADER_TASK) {
1567bf215546Sopenharmony_ci         mode = vtn_variable_mode_task_payload;
1568bf215546Sopenharmony_ci         nir_mode = nir_var_mem_task_payload;
1569bf215546Sopenharmony_ci      }
1570bf215546Sopenharmony_ci      break;
1571bf215546Sopenharmony_ci   case SpvStorageClassPrivate:
1572bf215546Sopenharmony_ci      mode = vtn_variable_mode_private;
1573bf215546Sopenharmony_ci      nir_mode = nir_var_shader_temp;
1574bf215546Sopenharmony_ci      break;
1575bf215546Sopenharmony_ci   case SpvStorageClassFunction:
1576bf215546Sopenharmony_ci      mode = vtn_variable_mode_function;
1577bf215546Sopenharmony_ci      nir_mode = nir_var_function_temp;
1578bf215546Sopenharmony_ci      break;
1579bf215546Sopenharmony_ci   case SpvStorageClassWorkgroup:
1580bf215546Sopenharmony_ci      mode = vtn_variable_mode_workgroup;
1581bf215546Sopenharmony_ci      nir_mode = nir_var_mem_shared;
1582bf215546Sopenharmony_ci      break;
1583bf215546Sopenharmony_ci   case SpvStorageClassAtomicCounter:
1584bf215546Sopenharmony_ci      mode = vtn_variable_mode_atomic_counter;
1585bf215546Sopenharmony_ci      nir_mode = nir_var_uniform;
1586bf215546Sopenharmony_ci      break;
1587bf215546Sopenharmony_ci   case SpvStorageClassCrossWorkgroup:
1588bf215546Sopenharmony_ci      mode = vtn_variable_mode_cross_workgroup;
1589bf215546Sopenharmony_ci      nir_mode = nir_var_mem_global;
1590bf215546Sopenharmony_ci      break;
1591bf215546Sopenharmony_ci   case SpvStorageClassImage:
1592bf215546Sopenharmony_ci      mode = vtn_variable_mode_image;
1593bf215546Sopenharmony_ci      nir_mode = nir_var_image;
1594bf215546Sopenharmony_ci      break;
1595bf215546Sopenharmony_ci   case SpvStorageClassCallableDataKHR:
1596bf215546Sopenharmony_ci      mode = vtn_variable_mode_call_data;
1597bf215546Sopenharmony_ci      nir_mode = nir_var_shader_temp;
1598bf215546Sopenharmony_ci      break;
1599bf215546Sopenharmony_ci   case SpvStorageClassIncomingCallableDataKHR:
1600bf215546Sopenharmony_ci      mode = vtn_variable_mode_call_data_in;
1601bf215546Sopenharmony_ci      nir_mode = nir_var_shader_call_data;
1602bf215546Sopenharmony_ci      break;
1603bf215546Sopenharmony_ci   case SpvStorageClassRayPayloadKHR:
1604bf215546Sopenharmony_ci      mode = vtn_variable_mode_ray_payload;
1605bf215546Sopenharmony_ci      nir_mode = nir_var_shader_temp;
1606bf215546Sopenharmony_ci      break;
1607bf215546Sopenharmony_ci   case SpvStorageClassIncomingRayPayloadKHR:
1608bf215546Sopenharmony_ci      mode = vtn_variable_mode_ray_payload_in;
1609bf215546Sopenharmony_ci      nir_mode = nir_var_shader_call_data;
1610bf215546Sopenharmony_ci      break;
1611bf215546Sopenharmony_ci   case SpvStorageClassHitAttributeKHR:
1612bf215546Sopenharmony_ci      mode = vtn_variable_mode_hit_attrib;
1613bf215546Sopenharmony_ci      nir_mode = nir_var_ray_hit_attrib;
1614bf215546Sopenharmony_ci      break;
1615bf215546Sopenharmony_ci   case SpvStorageClassShaderRecordBufferKHR:
1616bf215546Sopenharmony_ci      mode = vtn_variable_mode_shader_record;
1617bf215546Sopenharmony_ci      nir_mode = nir_var_mem_constant;
1618bf215546Sopenharmony_ci      break;
1619bf215546Sopenharmony_ci
1620bf215546Sopenharmony_ci   case SpvStorageClassGeneric:
1621bf215546Sopenharmony_ci      mode = vtn_variable_mode_generic;
1622bf215546Sopenharmony_ci      nir_mode = nir_var_mem_generic;
1623bf215546Sopenharmony_ci      break;
1624bf215546Sopenharmony_ci   default:
1625bf215546Sopenharmony_ci      vtn_fail("Unhandled variable storage class: %s (%u)",
1626bf215546Sopenharmony_ci               spirv_storageclass_to_string(class), class);
1627bf215546Sopenharmony_ci   }
1628bf215546Sopenharmony_ci
1629bf215546Sopenharmony_ci   if (nir_mode_out)
1630bf215546Sopenharmony_ci      *nir_mode_out = nir_mode;
1631bf215546Sopenharmony_ci
1632bf215546Sopenharmony_ci   return mode;
1633bf215546Sopenharmony_ci}
1634bf215546Sopenharmony_ci
1635bf215546Sopenharmony_cinir_address_format
1636bf215546Sopenharmony_civtn_mode_to_address_format(struct vtn_builder *b, enum vtn_variable_mode mode)
1637bf215546Sopenharmony_ci{
1638bf215546Sopenharmony_ci   switch (mode) {
1639bf215546Sopenharmony_ci   case vtn_variable_mode_ubo:
1640bf215546Sopenharmony_ci      return b->options->ubo_addr_format;
1641bf215546Sopenharmony_ci
1642bf215546Sopenharmony_ci   case vtn_variable_mode_ssbo:
1643bf215546Sopenharmony_ci      return b->options->ssbo_addr_format;
1644bf215546Sopenharmony_ci
1645bf215546Sopenharmony_ci   case vtn_variable_mode_phys_ssbo:
1646bf215546Sopenharmony_ci      return b->options->phys_ssbo_addr_format;
1647bf215546Sopenharmony_ci
1648bf215546Sopenharmony_ci   case vtn_variable_mode_push_constant:
1649bf215546Sopenharmony_ci      return b->options->push_const_addr_format;
1650bf215546Sopenharmony_ci
1651bf215546Sopenharmony_ci   case vtn_variable_mode_workgroup:
1652bf215546Sopenharmony_ci      return b->options->shared_addr_format;
1653bf215546Sopenharmony_ci
1654bf215546Sopenharmony_ci   case vtn_variable_mode_generic:
1655bf215546Sopenharmony_ci   case vtn_variable_mode_cross_workgroup:
1656bf215546Sopenharmony_ci      return b->options->global_addr_format;
1657bf215546Sopenharmony_ci
1658bf215546Sopenharmony_ci   case vtn_variable_mode_shader_record:
1659bf215546Sopenharmony_ci   case vtn_variable_mode_constant:
1660bf215546Sopenharmony_ci      return b->options->constant_addr_format;
1661bf215546Sopenharmony_ci
1662bf215546Sopenharmony_ci   case vtn_variable_mode_accel_struct:
1663bf215546Sopenharmony_ci      return nir_address_format_64bit_global;
1664bf215546Sopenharmony_ci
1665bf215546Sopenharmony_ci   case vtn_variable_mode_task_payload:
1666bf215546Sopenharmony_ci      return b->options->task_payload_addr_format;
1667bf215546Sopenharmony_ci
1668bf215546Sopenharmony_ci   case vtn_variable_mode_function:
1669bf215546Sopenharmony_ci      if (b->physical_ptrs)
1670bf215546Sopenharmony_ci         return b->options->temp_addr_format;
1671bf215546Sopenharmony_ci      FALLTHROUGH;
1672bf215546Sopenharmony_ci
1673bf215546Sopenharmony_ci   case vtn_variable_mode_private:
1674bf215546Sopenharmony_ci   case vtn_variable_mode_uniform:
1675bf215546Sopenharmony_ci   case vtn_variable_mode_atomic_counter:
1676bf215546Sopenharmony_ci   case vtn_variable_mode_input:
1677bf215546Sopenharmony_ci   case vtn_variable_mode_output:
1678bf215546Sopenharmony_ci   case vtn_variable_mode_image:
1679bf215546Sopenharmony_ci   case vtn_variable_mode_call_data:
1680bf215546Sopenharmony_ci   case vtn_variable_mode_call_data_in:
1681bf215546Sopenharmony_ci   case vtn_variable_mode_ray_payload:
1682bf215546Sopenharmony_ci   case vtn_variable_mode_ray_payload_in:
1683bf215546Sopenharmony_ci   case vtn_variable_mode_hit_attrib:
1684bf215546Sopenharmony_ci      return nir_address_format_logical;
1685bf215546Sopenharmony_ci   }
1686bf215546Sopenharmony_ci
1687bf215546Sopenharmony_ci   unreachable("Invalid variable mode");
1688bf215546Sopenharmony_ci}
1689bf215546Sopenharmony_ci
1690bf215546Sopenharmony_cinir_ssa_def *
1691bf215546Sopenharmony_civtn_pointer_to_ssa(struct vtn_builder *b, struct vtn_pointer *ptr)
1692bf215546Sopenharmony_ci{
1693bf215546Sopenharmony_ci   if ((vtn_pointer_is_external_block(b, ptr) &&
1694bf215546Sopenharmony_ci        vtn_type_contains_block(b, ptr->type) &&
1695bf215546Sopenharmony_ci        ptr->mode != vtn_variable_mode_phys_ssbo) ||
1696bf215546Sopenharmony_ci       ptr->mode == vtn_variable_mode_accel_struct) {
1697bf215546Sopenharmony_ci      /* In this case, we're looking for a block index and not an actual
1698bf215546Sopenharmony_ci       * deref.
1699bf215546Sopenharmony_ci       *
1700bf215546Sopenharmony_ci       * For PhysicalStorageBuffer pointers, we don't have a block index
1701bf215546Sopenharmony_ci       * at all because we get the pointer directly from the client.  This
1702bf215546Sopenharmony_ci       * assumes that there will never be a SSBO binding variable using the
1703bf215546Sopenharmony_ci       * PhysicalStorageBuffer storage class.  This assumption appears
1704bf215546Sopenharmony_ci       * to be correct according to the Vulkan spec because the table,
1705bf215546Sopenharmony_ci       * "Shader Resource and Storage Class Correspondence," the only the
1706bf215546Sopenharmony_ci       * Uniform storage class with BufferBlock or the StorageBuffer
1707bf215546Sopenharmony_ci       * storage class with Block can be used.
1708bf215546Sopenharmony_ci       */
1709bf215546Sopenharmony_ci      if (!ptr->block_index) {
1710bf215546Sopenharmony_ci         /* If we don't have a block_index then we must be a pointer to the
1711bf215546Sopenharmony_ci          * variable itself.
1712bf215546Sopenharmony_ci          */
1713bf215546Sopenharmony_ci         vtn_assert(!ptr->deref);
1714bf215546Sopenharmony_ci
1715bf215546Sopenharmony_ci         struct vtn_access_chain chain = {
1716bf215546Sopenharmony_ci            .length = 0,
1717bf215546Sopenharmony_ci         };
1718bf215546Sopenharmony_ci         ptr = vtn_pointer_dereference(b, ptr, &chain);
1719bf215546Sopenharmony_ci      }
1720bf215546Sopenharmony_ci
1721bf215546Sopenharmony_ci      return ptr->block_index;
1722bf215546Sopenharmony_ci   } else {
1723bf215546Sopenharmony_ci      return &vtn_pointer_to_deref(b, ptr)->dest.ssa;
1724bf215546Sopenharmony_ci   }
1725bf215546Sopenharmony_ci}
1726bf215546Sopenharmony_ci
1727bf215546Sopenharmony_cistruct vtn_pointer *
1728bf215546Sopenharmony_civtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
1729bf215546Sopenharmony_ci                     struct vtn_type *ptr_type)
1730bf215546Sopenharmony_ci{
1731bf215546Sopenharmony_ci   vtn_assert(ptr_type->base_type == vtn_base_type_pointer);
1732bf215546Sopenharmony_ci
1733bf215546Sopenharmony_ci   struct vtn_pointer *ptr = rzalloc(b, struct vtn_pointer);
1734bf215546Sopenharmony_ci   struct vtn_type *without_array =
1735bf215546Sopenharmony_ci      vtn_type_without_array(ptr_type->deref);
1736bf215546Sopenharmony_ci
1737bf215546Sopenharmony_ci   nir_variable_mode nir_mode;
1738bf215546Sopenharmony_ci   ptr->mode = vtn_storage_class_to_mode(b, ptr_type->storage_class,
1739bf215546Sopenharmony_ci                                         without_array, &nir_mode);
1740bf215546Sopenharmony_ci   ptr->type = ptr_type->deref;
1741bf215546Sopenharmony_ci   ptr->ptr_type = ptr_type;
1742bf215546Sopenharmony_ci
1743bf215546Sopenharmony_ci   const struct glsl_type *deref_type =
1744bf215546Sopenharmony_ci      vtn_type_get_nir_type(b, ptr_type->deref, ptr->mode);
1745bf215546Sopenharmony_ci   if (!vtn_pointer_is_external_block(b, ptr) &&
1746bf215546Sopenharmony_ci       ptr->mode != vtn_variable_mode_accel_struct) {
1747bf215546Sopenharmony_ci      ptr->deref = nir_build_deref_cast(&b->nb, ssa, nir_mode,
1748bf215546Sopenharmony_ci                                        deref_type, ptr_type->stride);
1749bf215546Sopenharmony_ci   } else if ((vtn_type_contains_block(b, ptr->type) &&
1750bf215546Sopenharmony_ci               ptr->mode != vtn_variable_mode_phys_ssbo) ||
1751bf215546Sopenharmony_ci              ptr->mode == vtn_variable_mode_accel_struct) {
1752bf215546Sopenharmony_ci      /* This is a pointer to somewhere in an array of blocks, not a
1753bf215546Sopenharmony_ci       * pointer to somewhere inside the block.  Set the block index
1754bf215546Sopenharmony_ci       * instead of making a cast.
1755bf215546Sopenharmony_ci       */
1756bf215546Sopenharmony_ci      ptr->block_index = ssa;
1757bf215546Sopenharmony_ci   } else {
1758bf215546Sopenharmony_ci      /* This is a pointer to something internal or a pointer inside a
1759bf215546Sopenharmony_ci       * block.  It's just a regular cast.
1760bf215546Sopenharmony_ci       *
1761bf215546Sopenharmony_ci       * For PhysicalStorageBuffer pointers, we don't have a block index
1762bf215546Sopenharmony_ci       * at all because we get the pointer directly from the client.  This
1763bf215546Sopenharmony_ci       * assumes that there will never be a SSBO binding variable using the
1764bf215546Sopenharmony_ci       * PhysicalStorageBuffer storage class.  This assumption appears
1765bf215546Sopenharmony_ci       * to be correct according to the Vulkan spec because the table,
1766bf215546Sopenharmony_ci       * "Shader Resource and Storage Class Correspondence," the only the
1767bf215546Sopenharmony_ci       * Uniform storage class with BufferBlock or the StorageBuffer
1768bf215546Sopenharmony_ci       * storage class with Block can be used.
1769bf215546Sopenharmony_ci       */
1770bf215546Sopenharmony_ci      ptr->deref = nir_build_deref_cast(&b->nb, ssa, nir_mode,
1771bf215546Sopenharmony_ci                                        deref_type, ptr_type->stride);
1772bf215546Sopenharmony_ci      ptr->deref->dest.ssa.num_components =
1773bf215546Sopenharmony_ci         glsl_get_vector_elements(ptr_type->type);
1774bf215546Sopenharmony_ci      ptr->deref->dest.ssa.bit_size = glsl_get_bit_size(ptr_type->type);
1775bf215546Sopenharmony_ci   }
1776bf215546Sopenharmony_ci
1777bf215546Sopenharmony_ci   return ptr;
1778bf215546Sopenharmony_ci}
1779bf215546Sopenharmony_ci
1780bf215546Sopenharmony_cistatic void
1781bf215546Sopenharmony_ciassign_missing_member_locations(struct vtn_variable *var)
1782bf215546Sopenharmony_ci{
1783bf215546Sopenharmony_ci   unsigned length =
1784bf215546Sopenharmony_ci      glsl_get_length(glsl_without_array(var->type->type));
1785bf215546Sopenharmony_ci   int location = var->base_location;
1786bf215546Sopenharmony_ci
1787bf215546Sopenharmony_ci   for (unsigned i = 0; i < length; i++) {
1788bf215546Sopenharmony_ci      /* From the Vulkan spec:
1789bf215546Sopenharmony_ci       *
1790bf215546Sopenharmony_ci       * “If the structure type is a Block but without a Location, then each
1791bf215546Sopenharmony_ci       *  of its members must have a Location decoration.”
1792bf215546Sopenharmony_ci       *
1793bf215546Sopenharmony_ci       */
1794bf215546Sopenharmony_ci      if (var->type->block) {
1795bf215546Sopenharmony_ci         assert(var->base_location != -1 ||
1796bf215546Sopenharmony_ci                var->var->members[i].location != -1);
1797bf215546Sopenharmony_ci      }
1798bf215546Sopenharmony_ci
1799bf215546Sopenharmony_ci      /* From the Vulkan spec:
1800bf215546Sopenharmony_ci       *
1801bf215546Sopenharmony_ci       * “Any member with its own Location decoration is assigned that
1802bf215546Sopenharmony_ci       *  location. Each remaining member is assigned the location after the
1803bf215546Sopenharmony_ci       *  immediately preceding member in declaration order.”
1804bf215546Sopenharmony_ci       */
1805bf215546Sopenharmony_ci      if (var->var->members[i].location != -1)
1806bf215546Sopenharmony_ci         location = var->var->members[i].location;
1807bf215546Sopenharmony_ci      else
1808bf215546Sopenharmony_ci         var->var->members[i].location = location;
1809bf215546Sopenharmony_ci
1810bf215546Sopenharmony_ci      /* Below we use type instead of interface_type, because interface_type
1811bf215546Sopenharmony_ci       * is only available when it is a Block. This code also supports
1812bf215546Sopenharmony_ci       * input/outputs that are just structs
1813bf215546Sopenharmony_ci       */
1814bf215546Sopenharmony_ci      const struct glsl_type *member_type =
1815bf215546Sopenharmony_ci         glsl_get_struct_field(glsl_without_array(var->type->type), i);
1816bf215546Sopenharmony_ci
1817bf215546Sopenharmony_ci      location +=
1818bf215546Sopenharmony_ci         glsl_count_attribute_slots(member_type,
1819bf215546Sopenharmony_ci                                    false /* is_gl_vertex_input */);
1820bf215546Sopenharmony_ci   }
1821bf215546Sopenharmony_ci}
1822bf215546Sopenharmony_ci
1823bf215546Sopenharmony_cinir_deref_instr *
1824bf215546Sopenharmony_civtn_get_call_payload_for_location(struct vtn_builder *b, uint32_t location_id)
1825bf215546Sopenharmony_ci{
1826bf215546Sopenharmony_ci   uint32_t location = vtn_constant_uint(b, location_id);
1827bf215546Sopenharmony_ci   nir_foreach_variable_with_modes(var, b->nb.shader, nir_var_shader_temp) {
1828bf215546Sopenharmony_ci      if (var->data.explicit_location &&
1829bf215546Sopenharmony_ci          var->data.location == location)
1830bf215546Sopenharmony_ci         return nir_build_deref_var(&b->nb, var);
1831bf215546Sopenharmony_ci   }
1832bf215546Sopenharmony_ci   vtn_fail("Couldn't find variable with a storage class of CallableDataKHR "
1833bf215546Sopenharmony_ci            "or RayPayloadKHR and location %d", location);
1834bf215546Sopenharmony_ci}
1835bf215546Sopenharmony_ci
1836bf215546Sopenharmony_cistatic bool
1837bf215546Sopenharmony_civtn_type_is_ray_query(struct vtn_type *type)
1838bf215546Sopenharmony_ci{
1839bf215546Sopenharmony_ci   return vtn_type_without_array(type)->base_type == vtn_base_type_ray_query;
1840bf215546Sopenharmony_ci}
1841bf215546Sopenharmony_ci
1842bf215546Sopenharmony_cistatic void
1843bf215546Sopenharmony_civtn_create_variable(struct vtn_builder *b, struct vtn_value *val,
1844bf215546Sopenharmony_ci                    struct vtn_type *ptr_type, SpvStorageClass storage_class,
1845bf215546Sopenharmony_ci                    struct vtn_value *initializer)
1846bf215546Sopenharmony_ci{
1847bf215546Sopenharmony_ci   vtn_assert(ptr_type->base_type == vtn_base_type_pointer);
1848bf215546Sopenharmony_ci   struct vtn_type *type = ptr_type->deref;
1849bf215546Sopenharmony_ci
1850bf215546Sopenharmony_ci   struct vtn_type *without_array = vtn_type_without_array(ptr_type->deref);
1851bf215546Sopenharmony_ci
1852bf215546Sopenharmony_ci   enum vtn_variable_mode mode;
1853bf215546Sopenharmony_ci   nir_variable_mode nir_mode;
1854bf215546Sopenharmony_ci   mode = vtn_storage_class_to_mode(b, storage_class, without_array, &nir_mode);
1855bf215546Sopenharmony_ci
1856bf215546Sopenharmony_ci   switch (mode) {
1857bf215546Sopenharmony_ci   case vtn_variable_mode_ubo:
1858bf215546Sopenharmony_ci      /* There's no other way to get vtn_variable_mode_ubo */
1859bf215546Sopenharmony_ci      vtn_assert(without_array->block);
1860bf215546Sopenharmony_ci      break;
1861bf215546Sopenharmony_ci   case vtn_variable_mode_ssbo:
1862bf215546Sopenharmony_ci      if (storage_class == SpvStorageClassStorageBuffer &&
1863bf215546Sopenharmony_ci          !without_array->block) {
1864bf215546Sopenharmony_ci         if (b->variable_pointers) {
1865bf215546Sopenharmony_ci            vtn_fail("Variables in the StorageBuffer storage class must "
1866bf215546Sopenharmony_ci                     "have a struct type with the Block decoration");
1867bf215546Sopenharmony_ci         } else {
1868bf215546Sopenharmony_ci            /* If variable pointers are not present, it's still malformed
1869bf215546Sopenharmony_ci             * SPIR-V but we can parse it and do the right thing anyway.
1870bf215546Sopenharmony_ci             * Since some of the 8-bit storage tests have bugs in this are,
1871bf215546Sopenharmony_ci             * just make it a warning for now.
1872bf215546Sopenharmony_ci             */
1873bf215546Sopenharmony_ci            vtn_warn("Variables in the StorageBuffer storage class must "
1874bf215546Sopenharmony_ci                     "have a struct type with the Block decoration");
1875bf215546Sopenharmony_ci         }
1876bf215546Sopenharmony_ci      }
1877bf215546Sopenharmony_ci      break;
1878bf215546Sopenharmony_ci
1879bf215546Sopenharmony_ci   case vtn_variable_mode_generic:
1880bf215546Sopenharmony_ci      vtn_fail("Cannot create a variable with the Generic storage class");
1881bf215546Sopenharmony_ci      break;
1882bf215546Sopenharmony_ci
1883bf215546Sopenharmony_ci   case vtn_variable_mode_image:
1884bf215546Sopenharmony_ci      if (storage_class == SpvStorageClassImage)
1885bf215546Sopenharmony_ci         vtn_fail("Cannot create a variable with the Image storage class");
1886bf215546Sopenharmony_ci      else
1887bf215546Sopenharmony_ci         vtn_assert(storage_class == SpvStorageClassUniformConstant);
1888bf215546Sopenharmony_ci      break;
1889bf215546Sopenharmony_ci
1890bf215546Sopenharmony_ci   case vtn_variable_mode_phys_ssbo:
1891bf215546Sopenharmony_ci      vtn_fail("Cannot create a variable with the "
1892bf215546Sopenharmony_ci               "PhysicalStorageBuffer storage class");
1893bf215546Sopenharmony_ci      break;
1894bf215546Sopenharmony_ci
1895bf215546Sopenharmony_ci   default:
1896bf215546Sopenharmony_ci      /* No tallying is needed */
1897bf215546Sopenharmony_ci      break;
1898bf215546Sopenharmony_ci   }
1899bf215546Sopenharmony_ci
1900bf215546Sopenharmony_ci   struct vtn_variable *var = rzalloc(b, struct vtn_variable);
1901bf215546Sopenharmony_ci   var->type = type;
1902bf215546Sopenharmony_ci   var->mode = mode;
1903bf215546Sopenharmony_ci   var->base_location = -1;
1904bf215546Sopenharmony_ci
1905bf215546Sopenharmony_ci   val->pointer = rzalloc(b, struct vtn_pointer);
1906bf215546Sopenharmony_ci   val->pointer->mode = var->mode;
1907bf215546Sopenharmony_ci   val->pointer->type = var->type;
1908bf215546Sopenharmony_ci   val->pointer->ptr_type = ptr_type;
1909bf215546Sopenharmony_ci   val->pointer->var = var;
1910bf215546Sopenharmony_ci   val->pointer->access = var->type->access;
1911bf215546Sopenharmony_ci
1912bf215546Sopenharmony_ci   switch (var->mode) {
1913bf215546Sopenharmony_ci   case vtn_variable_mode_function:
1914bf215546Sopenharmony_ci   case vtn_variable_mode_private:
1915bf215546Sopenharmony_ci   case vtn_variable_mode_uniform:
1916bf215546Sopenharmony_ci   case vtn_variable_mode_atomic_counter:
1917bf215546Sopenharmony_ci   case vtn_variable_mode_constant:
1918bf215546Sopenharmony_ci   case vtn_variable_mode_call_data:
1919bf215546Sopenharmony_ci   case vtn_variable_mode_call_data_in:
1920bf215546Sopenharmony_ci   case vtn_variable_mode_image:
1921bf215546Sopenharmony_ci   case vtn_variable_mode_ray_payload:
1922bf215546Sopenharmony_ci   case vtn_variable_mode_ray_payload_in:
1923bf215546Sopenharmony_ci   case vtn_variable_mode_hit_attrib:
1924bf215546Sopenharmony_ci      /* For these, we create the variable normally */
1925bf215546Sopenharmony_ci      var->var = rzalloc(b->shader, nir_variable);
1926bf215546Sopenharmony_ci      var->var->name = ralloc_strdup(var->var, val->name);
1927bf215546Sopenharmony_ci      var->var->type = vtn_type_get_nir_type(b, var->type, var->mode);
1928bf215546Sopenharmony_ci
1929bf215546Sopenharmony_ci      /* This is a total hack but we need some way to flag variables which are
1930bf215546Sopenharmony_ci       * going to be call payloads.  See get_call_payload_deref.
1931bf215546Sopenharmony_ci       */
1932bf215546Sopenharmony_ci      if (storage_class == SpvStorageClassCallableDataKHR ||
1933bf215546Sopenharmony_ci          storage_class == SpvStorageClassRayPayloadKHR)
1934bf215546Sopenharmony_ci         var->var->data.explicit_location = true;
1935bf215546Sopenharmony_ci
1936bf215546Sopenharmony_ci      var->var->data.mode = nir_mode;
1937bf215546Sopenharmony_ci      var->var->data.location = -1;
1938bf215546Sopenharmony_ci      var->var->data.ray_query = vtn_type_is_ray_query(var->type);
1939bf215546Sopenharmony_ci      var->var->interface_type = NULL;
1940bf215546Sopenharmony_ci      break;
1941bf215546Sopenharmony_ci
1942bf215546Sopenharmony_ci   case vtn_variable_mode_ubo:
1943bf215546Sopenharmony_ci   case vtn_variable_mode_ssbo:
1944bf215546Sopenharmony_ci   case vtn_variable_mode_push_constant:
1945bf215546Sopenharmony_ci   case vtn_variable_mode_accel_struct:
1946bf215546Sopenharmony_ci   case vtn_variable_mode_shader_record:
1947bf215546Sopenharmony_ci      var->var = rzalloc(b->shader, nir_variable);
1948bf215546Sopenharmony_ci      var->var->name = ralloc_strdup(var->var, val->name);
1949bf215546Sopenharmony_ci
1950bf215546Sopenharmony_ci      var->var->type = vtn_type_get_nir_type(b, var->type, var->mode);
1951bf215546Sopenharmony_ci      var->var->interface_type = var->var->type;
1952bf215546Sopenharmony_ci
1953bf215546Sopenharmony_ci      var->var->data.mode = nir_mode;
1954bf215546Sopenharmony_ci      var->var->data.location = -1;
1955bf215546Sopenharmony_ci      var->var->data.driver_location = 0;
1956bf215546Sopenharmony_ci      var->var->data.access = var->type->access;
1957bf215546Sopenharmony_ci      break;
1958bf215546Sopenharmony_ci
1959bf215546Sopenharmony_ci   case vtn_variable_mode_workgroup:
1960bf215546Sopenharmony_ci   case vtn_variable_mode_cross_workgroup:
1961bf215546Sopenharmony_ci   case vtn_variable_mode_task_payload:
1962bf215546Sopenharmony_ci      /* Create the variable normally */
1963bf215546Sopenharmony_ci      var->var = rzalloc(b->shader, nir_variable);
1964bf215546Sopenharmony_ci      var->var->name = ralloc_strdup(var->var, val->name);
1965bf215546Sopenharmony_ci      var->var->type = vtn_type_get_nir_type(b, var->type, var->mode);
1966bf215546Sopenharmony_ci      var->var->data.mode = nir_mode;
1967bf215546Sopenharmony_ci      break;
1968bf215546Sopenharmony_ci
1969bf215546Sopenharmony_ci   case vtn_variable_mode_input:
1970bf215546Sopenharmony_ci   case vtn_variable_mode_output: {
1971bf215546Sopenharmony_ci      var->var = rzalloc(b->shader, nir_variable);
1972bf215546Sopenharmony_ci      var->var->name = ralloc_strdup(var->var, val->name);
1973bf215546Sopenharmony_ci      var->var->type = vtn_type_get_nir_type(b, var->type, var->mode);
1974bf215546Sopenharmony_ci      var->var->data.mode = nir_mode;
1975bf215546Sopenharmony_ci
1976bf215546Sopenharmony_ci      /* In order to know whether or not we're a per-vertex inout, we need
1977bf215546Sopenharmony_ci       * the patch qualifier.  This means walking the variable decorations
1978bf215546Sopenharmony_ci       * early before we actually create any variables.  Not a big deal.
1979bf215546Sopenharmony_ci       *
1980bf215546Sopenharmony_ci       * GLSLang really likes to place decorations in the most interior
1981bf215546Sopenharmony_ci       * thing it possibly can.  In particular, if you have a struct, it
1982bf215546Sopenharmony_ci       * will place the patch decorations on the struct members.  This
1983bf215546Sopenharmony_ci       * should be handled by the variable splitting below just fine.
1984bf215546Sopenharmony_ci       *
1985bf215546Sopenharmony_ci       * If you have an array-of-struct, things get even more weird as it
1986bf215546Sopenharmony_ci       * will place the patch decorations on the struct even though it's
1987bf215546Sopenharmony_ci       * inside an array and some of the members being patch and others not
1988bf215546Sopenharmony_ci       * makes no sense whatsoever.  Since the only sensible thing is for
1989bf215546Sopenharmony_ci       * it to be all or nothing, we'll call it patch if any of the members
1990bf215546Sopenharmony_ci       * are declared patch.
1991bf215546Sopenharmony_ci       */
1992bf215546Sopenharmony_ci      vtn_foreach_decoration(b, val, gather_var_kind_cb, var);
1993bf215546Sopenharmony_ci      if (glsl_type_is_array(var->type->type) &&
1994bf215546Sopenharmony_ci          glsl_type_is_struct_or_ifc(without_array->type)) {
1995bf215546Sopenharmony_ci         vtn_foreach_decoration(b, vtn_value(b, without_array->id,
1996bf215546Sopenharmony_ci                                             vtn_value_type_type),
1997bf215546Sopenharmony_ci                                gather_var_kind_cb, var);
1998bf215546Sopenharmony_ci      }
1999bf215546Sopenharmony_ci
2000bf215546Sopenharmony_ci      struct vtn_type *per_vertex_type = var->type;
2001bf215546Sopenharmony_ci      if (nir_is_arrayed_io(var->var, b->shader->info.stage))
2002bf215546Sopenharmony_ci         per_vertex_type = var->type->array_element;
2003bf215546Sopenharmony_ci
2004bf215546Sopenharmony_ci      /* Figure out the interface block type. */
2005bf215546Sopenharmony_ci      struct vtn_type *iface_type = per_vertex_type;
2006bf215546Sopenharmony_ci      if (var->mode == vtn_variable_mode_output &&
2007bf215546Sopenharmony_ci          (b->shader->info.stage == MESA_SHADER_VERTEX ||
2008bf215546Sopenharmony_ci           b->shader->info.stage == MESA_SHADER_TESS_EVAL ||
2009bf215546Sopenharmony_ci           b->shader->info.stage == MESA_SHADER_GEOMETRY)) {
2010bf215546Sopenharmony_ci         /* For vertex data outputs, we can end up with arrays of blocks for
2011bf215546Sopenharmony_ci          * transform feedback where each array element corresponds to a
2012bf215546Sopenharmony_ci          * different XFB output buffer.
2013bf215546Sopenharmony_ci          */
2014bf215546Sopenharmony_ci         while (iface_type->base_type == vtn_base_type_array)
2015bf215546Sopenharmony_ci            iface_type = iface_type->array_element;
2016bf215546Sopenharmony_ci      }
2017bf215546Sopenharmony_ci      if (iface_type->base_type == vtn_base_type_struct && iface_type->block)
2018bf215546Sopenharmony_ci         var->var->interface_type = vtn_type_get_nir_type(b, iface_type,
2019bf215546Sopenharmony_ci                                                          var->mode);
2020bf215546Sopenharmony_ci
2021bf215546Sopenharmony_ci      /* If it's a block, set it up as per-member so can be splitted later by
2022bf215546Sopenharmony_ci       * nir_split_per_member_structs.
2023bf215546Sopenharmony_ci       *
2024bf215546Sopenharmony_ci       * This is for a couple of reasons.  For one, builtins may all come in a
2025bf215546Sopenharmony_ci       * block and we really want those split out into separate variables.
2026bf215546Sopenharmony_ci       * For another, interpolation qualifiers can be applied to members of
2027bf215546Sopenharmony_ci       * the top-level struct and we need to be able to preserve that
2028bf215546Sopenharmony_ci       * information.
2029bf215546Sopenharmony_ci       */
2030bf215546Sopenharmony_ci      if (per_vertex_type->base_type == vtn_base_type_struct &&
2031bf215546Sopenharmony_ci          per_vertex_type->block) {
2032bf215546Sopenharmony_ci         var->var->num_members = glsl_get_length(per_vertex_type->type);
2033bf215546Sopenharmony_ci         var->var->members = rzalloc_array(var->var, struct nir_variable_data,
2034bf215546Sopenharmony_ci                                           var->var->num_members);
2035bf215546Sopenharmony_ci
2036bf215546Sopenharmony_ci         for (unsigned i = 0; i < var->var->num_members; i++) {
2037bf215546Sopenharmony_ci            var->var->members[i].mode = nir_mode;
2038bf215546Sopenharmony_ci            var->var->members[i].patch = var->var->data.patch;
2039bf215546Sopenharmony_ci            var->var->members[i].location = -1;
2040bf215546Sopenharmony_ci         }
2041bf215546Sopenharmony_ci      }
2042bf215546Sopenharmony_ci
2043bf215546Sopenharmony_ci      /* For inputs and outputs, we need to grab locations and builtin
2044bf215546Sopenharmony_ci       * information from the per-vertex type.
2045bf215546Sopenharmony_ci       */
2046bf215546Sopenharmony_ci      vtn_foreach_decoration(b, vtn_value(b, per_vertex_type->id,
2047bf215546Sopenharmony_ci                                          vtn_value_type_type),
2048bf215546Sopenharmony_ci                             var_decoration_cb, var);
2049bf215546Sopenharmony_ci
2050bf215546Sopenharmony_ci      break;
2051bf215546Sopenharmony_ci   }
2052bf215546Sopenharmony_ci
2053bf215546Sopenharmony_ci   case vtn_variable_mode_phys_ssbo:
2054bf215546Sopenharmony_ci   case vtn_variable_mode_generic:
2055bf215546Sopenharmony_ci      unreachable("Should have been caught before");
2056bf215546Sopenharmony_ci   }
2057bf215546Sopenharmony_ci
2058bf215546Sopenharmony_ci   /* Ignore incorrectly generated Undef initializers. */
2059bf215546Sopenharmony_ci   if (b->wa_llvm_spirv_ignore_workgroup_initializer &&
2060bf215546Sopenharmony_ci       initializer &&
2061bf215546Sopenharmony_ci       storage_class == SpvStorageClassWorkgroup)
2062bf215546Sopenharmony_ci      initializer = NULL;
2063bf215546Sopenharmony_ci
2064bf215546Sopenharmony_ci   /* Only initialize variable when there is an initializer and it's not
2065bf215546Sopenharmony_ci    * undef.
2066bf215546Sopenharmony_ci    */
2067bf215546Sopenharmony_ci   if (initializer && !initializer->is_undef_constant) {
2068bf215546Sopenharmony_ci      switch (storage_class) {
2069bf215546Sopenharmony_ci      case SpvStorageClassWorkgroup:
2070bf215546Sopenharmony_ci         /* VK_KHR_zero_initialize_workgroup_memory. */
2071bf215546Sopenharmony_ci         vtn_fail_if(b->options->environment != NIR_SPIRV_VULKAN,
2072bf215546Sopenharmony_ci                     "Only Vulkan supports variable initializer "
2073bf215546Sopenharmony_ci                     "for Workgroup variable %u",
2074bf215546Sopenharmony_ci                     vtn_id_for_value(b, val));
2075bf215546Sopenharmony_ci         vtn_fail_if(initializer->value_type != vtn_value_type_constant ||
2076bf215546Sopenharmony_ci                     !initializer->is_null_constant,
2077bf215546Sopenharmony_ci                     "Workgroup variable %u can only have OpConstantNull "
2078bf215546Sopenharmony_ci                     "as initializer, but have %u instead",
2079bf215546Sopenharmony_ci                     vtn_id_for_value(b, val),
2080bf215546Sopenharmony_ci                     vtn_id_for_value(b, initializer));
2081bf215546Sopenharmony_ci         b->shader->info.zero_initialize_shared_memory = true;
2082bf215546Sopenharmony_ci         break;
2083bf215546Sopenharmony_ci
2084bf215546Sopenharmony_ci      case SpvStorageClassUniformConstant:
2085bf215546Sopenharmony_ci         vtn_fail_if(b->options->environment != NIR_SPIRV_OPENGL &&
2086bf215546Sopenharmony_ci                     b->options->environment != NIR_SPIRV_OPENCL,
2087bf215546Sopenharmony_ci                     "Only OpenGL and OpenCL support variable initializer "
2088bf215546Sopenharmony_ci                     "for UniformConstant variable %u\n",
2089bf215546Sopenharmony_ci                     vtn_id_for_value(b, val));
2090bf215546Sopenharmony_ci         vtn_fail_if(initializer->value_type != vtn_value_type_constant,
2091bf215546Sopenharmony_ci                     "UniformConstant variable %u can only have a constant "
2092bf215546Sopenharmony_ci                     "initializer, but have %u instead",
2093bf215546Sopenharmony_ci                     vtn_id_for_value(b, val),
2094bf215546Sopenharmony_ci                     vtn_id_for_value(b, initializer));
2095bf215546Sopenharmony_ci         break;
2096bf215546Sopenharmony_ci
2097bf215546Sopenharmony_ci      case SpvStorageClassOutput:
2098bf215546Sopenharmony_ci      case SpvStorageClassPrivate:
2099bf215546Sopenharmony_ci         vtn_assert(b->options->environment != NIR_SPIRV_OPENCL);
2100bf215546Sopenharmony_ci         /* These can have any initializer. */
2101bf215546Sopenharmony_ci         break;
2102bf215546Sopenharmony_ci
2103bf215546Sopenharmony_ci      case SpvStorageClassFunction:
2104bf215546Sopenharmony_ci         /* These can have any initializer. */
2105bf215546Sopenharmony_ci         break;
2106bf215546Sopenharmony_ci
2107bf215546Sopenharmony_ci      case SpvStorageClassCrossWorkgroup:
2108bf215546Sopenharmony_ci         vtn_assert(b->options->environment == NIR_SPIRV_OPENCL);
2109bf215546Sopenharmony_ci         vtn_fail("Initializer for CrossWorkgroup variable %u "
2110bf215546Sopenharmony_ci                  "not yet supported in Mesa.",
2111bf215546Sopenharmony_ci                  vtn_id_for_value(b, val));
2112bf215546Sopenharmony_ci         break;
2113bf215546Sopenharmony_ci
2114bf215546Sopenharmony_ci      default: {
2115bf215546Sopenharmony_ci         const enum nir_spirv_execution_environment env =
2116bf215546Sopenharmony_ci            b->options->environment;
2117bf215546Sopenharmony_ci         const char *env_name =
2118bf215546Sopenharmony_ci            env == NIR_SPIRV_VULKAN ? "Vulkan" :
2119bf215546Sopenharmony_ci            env == NIR_SPIRV_OPENCL ? "OpenCL" :
2120bf215546Sopenharmony_ci            env == NIR_SPIRV_OPENGL ? "OpenGL" :
2121bf215546Sopenharmony_ci            NULL;
2122bf215546Sopenharmony_ci         vtn_assert(env_name);
2123bf215546Sopenharmony_ci         vtn_fail("In %s, any OpVariable with an Initializer operand "
2124bf215546Sopenharmony_ci                  "must have %s%s%s, or Function as "
2125bf215546Sopenharmony_ci                  "its Storage Class operand.  Variable %u has an "
2126bf215546Sopenharmony_ci                  "Initializer but its Storage Class is %s.",
2127bf215546Sopenharmony_ci                  env_name,
2128bf215546Sopenharmony_ci                  env == NIR_SPIRV_VULKAN ? "Private, Output, Workgroup" : "",
2129bf215546Sopenharmony_ci                  env == NIR_SPIRV_OPENCL ? "CrossWorkgroup, UniformConstant" : "",
2130bf215546Sopenharmony_ci                  env == NIR_SPIRV_OPENGL ? "Private, Output, UniformConstant" : "",
2131bf215546Sopenharmony_ci                  vtn_id_for_value(b, val),
2132bf215546Sopenharmony_ci                  spirv_storageclass_to_string(storage_class));
2133bf215546Sopenharmony_ci         }
2134bf215546Sopenharmony_ci      }
2135bf215546Sopenharmony_ci
2136bf215546Sopenharmony_ci      switch (initializer->value_type) {
2137bf215546Sopenharmony_ci      case vtn_value_type_constant:
2138bf215546Sopenharmony_ci         var->var->constant_initializer =
2139bf215546Sopenharmony_ci            nir_constant_clone(initializer->constant, var->var);
2140bf215546Sopenharmony_ci         break;
2141bf215546Sopenharmony_ci      case vtn_value_type_pointer:
2142bf215546Sopenharmony_ci         var->var->pointer_initializer = initializer->pointer->var->var;
2143bf215546Sopenharmony_ci         break;
2144bf215546Sopenharmony_ci      default:
2145bf215546Sopenharmony_ci         vtn_fail("SPIR-V variable initializer %u must be constant or pointer",
2146bf215546Sopenharmony_ci                  vtn_id_for_value(b, initializer));
2147bf215546Sopenharmony_ci      }
2148bf215546Sopenharmony_ci   }
2149bf215546Sopenharmony_ci
2150bf215546Sopenharmony_ci   if (var->mode == vtn_variable_mode_uniform ||
2151bf215546Sopenharmony_ci       var->mode == vtn_variable_mode_image ||
2152bf215546Sopenharmony_ci       var->mode == vtn_variable_mode_ssbo) {
2153bf215546Sopenharmony_ci      /* SSBOs and images are assumed to not alias in the Simple, GLSL and Vulkan memory models */
2154bf215546Sopenharmony_ci      var->var->data.access |= b->mem_model != SpvMemoryModelOpenCL ? ACCESS_RESTRICT : 0;
2155bf215546Sopenharmony_ci   }
2156bf215546Sopenharmony_ci
2157bf215546Sopenharmony_ci   vtn_foreach_decoration(b, val, var_decoration_cb, var);
2158bf215546Sopenharmony_ci   vtn_foreach_decoration(b, val, ptr_decoration_cb, val->pointer);
2159bf215546Sopenharmony_ci
2160bf215546Sopenharmony_ci   /* Propagate access flags from the OpVariable decorations. */
2161bf215546Sopenharmony_ci   val->pointer->access |= var->access;
2162bf215546Sopenharmony_ci
2163bf215546Sopenharmony_ci   if ((var->mode == vtn_variable_mode_input ||
2164bf215546Sopenharmony_ci        var->mode == vtn_variable_mode_output) &&
2165bf215546Sopenharmony_ci       var->var->members) {
2166bf215546Sopenharmony_ci      assign_missing_member_locations(var);
2167bf215546Sopenharmony_ci   }
2168bf215546Sopenharmony_ci
2169bf215546Sopenharmony_ci   if (var->mode == vtn_variable_mode_uniform ||
2170bf215546Sopenharmony_ci       var->mode == vtn_variable_mode_image ||
2171bf215546Sopenharmony_ci       var->mode == vtn_variable_mode_ubo ||
2172bf215546Sopenharmony_ci       var->mode == vtn_variable_mode_ssbo ||
2173bf215546Sopenharmony_ci       var->mode == vtn_variable_mode_atomic_counter) {
2174bf215546Sopenharmony_ci      /* XXX: We still need the binding information in the nir_variable
2175bf215546Sopenharmony_ci       * for these. We should fix that.
2176bf215546Sopenharmony_ci       */
2177bf215546Sopenharmony_ci      var->var->data.binding = var->binding;
2178bf215546Sopenharmony_ci      var->var->data.explicit_binding = var->explicit_binding;
2179bf215546Sopenharmony_ci      var->var->data.descriptor_set = var->descriptor_set;
2180bf215546Sopenharmony_ci      var->var->data.index = var->input_attachment_index;
2181bf215546Sopenharmony_ci      var->var->data.offset = var->offset;
2182bf215546Sopenharmony_ci
2183bf215546Sopenharmony_ci      if (glsl_type_is_image(glsl_without_array(var->var->type)))
2184bf215546Sopenharmony_ci         var->var->data.image.format = without_array->image_format;
2185bf215546Sopenharmony_ci   }
2186bf215546Sopenharmony_ci
2187bf215546Sopenharmony_ci   if (var->mode == vtn_variable_mode_function) {
2188bf215546Sopenharmony_ci      vtn_assert(var->var != NULL && var->var->members == NULL);
2189bf215546Sopenharmony_ci      nir_function_impl_add_variable(b->nb.impl, var->var);
2190bf215546Sopenharmony_ci   } else if (var->var) {
2191bf215546Sopenharmony_ci      nir_shader_add_variable(b->shader, var->var);
2192bf215546Sopenharmony_ci   } else {
2193bf215546Sopenharmony_ci      vtn_assert(vtn_pointer_is_external_block(b, val->pointer) ||
2194bf215546Sopenharmony_ci                 var->mode == vtn_variable_mode_accel_struct ||
2195bf215546Sopenharmony_ci                 var->mode == vtn_variable_mode_shader_record);
2196bf215546Sopenharmony_ci   }
2197bf215546Sopenharmony_ci}
2198bf215546Sopenharmony_ci
2199bf215546Sopenharmony_cistatic void
2200bf215546Sopenharmony_civtn_assert_types_equal(struct vtn_builder *b, SpvOp opcode,
2201bf215546Sopenharmony_ci                       struct vtn_type *dst_type,
2202bf215546Sopenharmony_ci                       struct vtn_type *src_type)
2203bf215546Sopenharmony_ci{
2204bf215546Sopenharmony_ci   if (dst_type->id == src_type->id)
2205bf215546Sopenharmony_ci      return;
2206bf215546Sopenharmony_ci
2207bf215546Sopenharmony_ci   if (vtn_types_compatible(b, dst_type, src_type)) {
2208bf215546Sopenharmony_ci      /* Early versions of GLSLang would re-emit types unnecessarily and you
2209bf215546Sopenharmony_ci       * would end up with OpLoad, OpStore, or OpCopyMemory opcodes which have
2210bf215546Sopenharmony_ci       * mismatched source and destination types.
2211bf215546Sopenharmony_ci       *
2212bf215546Sopenharmony_ci       * https://github.com/KhronosGroup/glslang/issues/304
2213bf215546Sopenharmony_ci       * https://github.com/KhronosGroup/glslang/issues/307
2214bf215546Sopenharmony_ci       * https://bugs.freedesktop.org/show_bug.cgi?id=104338
2215bf215546Sopenharmony_ci       * https://bugs.freedesktop.org/show_bug.cgi?id=104424
2216bf215546Sopenharmony_ci       */
2217bf215546Sopenharmony_ci      vtn_warn("Source and destination types of %s do not have the same "
2218bf215546Sopenharmony_ci               "ID (but are compatible): %u vs %u",
2219bf215546Sopenharmony_ci                spirv_op_to_string(opcode), dst_type->id, src_type->id);
2220bf215546Sopenharmony_ci      return;
2221bf215546Sopenharmony_ci   }
2222bf215546Sopenharmony_ci
2223bf215546Sopenharmony_ci   vtn_fail("Source and destination types of %s do not match: %s vs. %s",
2224bf215546Sopenharmony_ci            spirv_op_to_string(opcode),
2225bf215546Sopenharmony_ci            glsl_get_type_name(dst_type->type),
2226bf215546Sopenharmony_ci            glsl_get_type_name(src_type->type));
2227bf215546Sopenharmony_ci}
2228bf215546Sopenharmony_ci
2229bf215546Sopenharmony_cistatic nir_ssa_def *
2230bf215546Sopenharmony_cinir_shrink_zero_pad_vec(nir_builder *b, nir_ssa_def *val,
2231bf215546Sopenharmony_ci                        unsigned num_components)
2232bf215546Sopenharmony_ci{
2233bf215546Sopenharmony_ci   if (val->num_components == num_components)
2234bf215546Sopenharmony_ci      return val;
2235bf215546Sopenharmony_ci
2236bf215546Sopenharmony_ci   nir_ssa_def *comps[NIR_MAX_VEC_COMPONENTS];
2237bf215546Sopenharmony_ci   for (unsigned i = 0; i < num_components; i++) {
2238bf215546Sopenharmony_ci      if (i < val->num_components)
2239bf215546Sopenharmony_ci         comps[i] = nir_channel(b, val, i);
2240bf215546Sopenharmony_ci      else
2241bf215546Sopenharmony_ci         comps[i] = nir_imm_intN_t(b, 0, val->bit_size);
2242bf215546Sopenharmony_ci   }
2243bf215546Sopenharmony_ci   return nir_vec(b, comps, num_components);
2244bf215546Sopenharmony_ci}
2245bf215546Sopenharmony_ci
2246bf215546Sopenharmony_cistatic nir_ssa_def *
2247bf215546Sopenharmony_cinir_sloppy_bitcast(nir_builder *b, nir_ssa_def *val,
2248bf215546Sopenharmony_ci                   const struct glsl_type *type)
2249bf215546Sopenharmony_ci{
2250bf215546Sopenharmony_ci   const unsigned num_components = glsl_get_vector_elements(type);
2251bf215546Sopenharmony_ci   const unsigned bit_size = glsl_get_bit_size(type);
2252bf215546Sopenharmony_ci
2253bf215546Sopenharmony_ci   /* First, zero-pad to ensure that the value is big enough that when we
2254bf215546Sopenharmony_ci    * bit-cast it, we don't loose anything.
2255bf215546Sopenharmony_ci    */
2256bf215546Sopenharmony_ci   if (val->bit_size < bit_size) {
2257bf215546Sopenharmony_ci      const unsigned src_num_components_needed =
2258bf215546Sopenharmony_ci         vtn_align_u32(val->num_components, bit_size / val->bit_size);
2259bf215546Sopenharmony_ci      val = nir_shrink_zero_pad_vec(b, val, src_num_components_needed);
2260bf215546Sopenharmony_ci   }
2261bf215546Sopenharmony_ci
2262bf215546Sopenharmony_ci   val = nir_bitcast_vector(b, val, bit_size);
2263bf215546Sopenharmony_ci
2264bf215546Sopenharmony_ci   return nir_shrink_zero_pad_vec(b, val, num_components);
2265bf215546Sopenharmony_ci}
2266bf215546Sopenharmony_ci
2267bf215546Sopenharmony_cistatic bool
2268bf215546Sopenharmony_civtn_get_mem_operands(struct vtn_builder *b, const uint32_t *w, unsigned count,
2269bf215546Sopenharmony_ci                     unsigned *idx, SpvMemoryAccessMask *access, unsigned *alignment,
2270bf215546Sopenharmony_ci                     SpvScope *dest_scope, SpvScope *src_scope)
2271bf215546Sopenharmony_ci{
2272bf215546Sopenharmony_ci   *access = 0;
2273bf215546Sopenharmony_ci   *alignment = 0;
2274bf215546Sopenharmony_ci   if (*idx >= count)
2275bf215546Sopenharmony_ci      return false;
2276bf215546Sopenharmony_ci
2277bf215546Sopenharmony_ci   *access = w[(*idx)++];
2278bf215546Sopenharmony_ci   if (*access & SpvMemoryAccessAlignedMask) {
2279bf215546Sopenharmony_ci      vtn_assert(*idx < count);
2280bf215546Sopenharmony_ci      *alignment = w[(*idx)++];
2281bf215546Sopenharmony_ci   }
2282bf215546Sopenharmony_ci
2283bf215546Sopenharmony_ci   if (*access & SpvMemoryAccessMakePointerAvailableMask) {
2284bf215546Sopenharmony_ci      vtn_assert(*idx < count);
2285bf215546Sopenharmony_ci      vtn_assert(dest_scope);
2286bf215546Sopenharmony_ci      *dest_scope = vtn_constant_uint(b, w[(*idx)++]);
2287bf215546Sopenharmony_ci   }
2288bf215546Sopenharmony_ci
2289bf215546Sopenharmony_ci   if (*access & SpvMemoryAccessMakePointerVisibleMask) {
2290bf215546Sopenharmony_ci      vtn_assert(*idx < count);
2291bf215546Sopenharmony_ci      vtn_assert(src_scope);
2292bf215546Sopenharmony_ci      *src_scope = vtn_constant_uint(b, w[(*idx)++]);
2293bf215546Sopenharmony_ci   }
2294bf215546Sopenharmony_ci
2295bf215546Sopenharmony_ci   return true;
2296bf215546Sopenharmony_ci}
2297bf215546Sopenharmony_ci
2298bf215546Sopenharmony_cistatic enum gl_access_qualifier
2299bf215546Sopenharmony_cispv_access_to_gl_access(SpvMemoryAccessMask access)
2300bf215546Sopenharmony_ci{
2301bf215546Sopenharmony_ci   unsigned result = 0;
2302bf215546Sopenharmony_ci
2303bf215546Sopenharmony_ci   if (access & SpvMemoryAccessVolatileMask)
2304bf215546Sopenharmony_ci      result |= ACCESS_VOLATILE;
2305bf215546Sopenharmony_ci   if (access & SpvMemoryAccessNontemporalMask)
2306bf215546Sopenharmony_ci      result |= ACCESS_STREAM_CACHE_POLICY;
2307bf215546Sopenharmony_ci
2308bf215546Sopenharmony_ci   return result;
2309bf215546Sopenharmony_ci}
2310bf215546Sopenharmony_ci
2311bf215546Sopenharmony_ci
2312bf215546Sopenharmony_ciSpvMemorySemanticsMask
2313bf215546Sopenharmony_civtn_mode_to_memory_semantics(enum vtn_variable_mode mode)
2314bf215546Sopenharmony_ci{
2315bf215546Sopenharmony_ci   switch (mode) {
2316bf215546Sopenharmony_ci   case vtn_variable_mode_ssbo:
2317bf215546Sopenharmony_ci   case vtn_variable_mode_phys_ssbo:
2318bf215546Sopenharmony_ci      return SpvMemorySemanticsUniformMemoryMask;
2319bf215546Sopenharmony_ci   case vtn_variable_mode_workgroup:
2320bf215546Sopenharmony_ci      return SpvMemorySemanticsWorkgroupMemoryMask;
2321bf215546Sopenharmony_ci   case vtn_variable_mode_cross_workgroup:
2322bf215546Sopenharmony_ci      return SpvMemorySemanticsCrossWorkgroupMemoryMask;
2323bf215546Sopenharmony_ci   case vtn_variable_mode_atomic_counter:
2324bf215546Sopenharmony_ci      return SpvMemorySemanticsAtomicCounterMemoryMask;
2325bf215546Sopenharmony_ci   case vtn_variable_mode_image:
2326bf215546Sopenharmony_ci      return SpvMemorySemanticsImageMemoryMask;
2327bf215546Sopenharmony_ci   case vtn_variable_mode_output:
2328bf215546Sopenharmony_ci      return SpvMemorySemanticsOutputMemoryMask;
2329bf215546Sopenharmony_ci   default:
2330bf215546Sopenharmony_ci      return SpvMemorySemanticsMaskNone;
2331bf215546Sopenharmony_ci   }
2332bf215546Sopenharmony_ci}
2333bf215546Sopenharmony_ci
2334bf215546Sopenharmony_cistatic void
2335bf215546Sopenharmony_civtn_emit_make_visible_barrier(struct vtn_builder *b, SpvMemoryAccessMask access,
2336bf215546Sopenharmony_ci                              SpvScope scope, enum vtn_variable_mode mode)
2337bf215546Sopenharmony_ci{
2338bf215546Sopenharmony_ci   if (!(access & SpvMemoryAccessMakePointerVisibleMask))
2339bf215546Sopenharmony_ci      return;
2340bf215546Sopenharmony_ci
2341bf215546Sopenharmony_ci   vtn_emit_memory_barrier(b, scope, SpvMemorySemanticsMakeVisibleMask |
2342bf215546Sopenharmony_ci                                     SpvMemorySemanticsAcquireMask |
2343bf215546Sopenharmony_ci                                     vtn_mode_to_memory_semantics(mode));
2344bf215546Sopenharmony_ci}
2345bf215546Sopenharmony_ci
2346bf215546Sopenharmony_cistatic void
2347bf215546Sopenharmony_civtn_emit_make_available_barrier(struct vtn_builder *b, SpvMemoryAccessMask access,
2348bf215546Sopenharmony_ci                                SpvScope scope, enum vtn_variable_mode mode)
2349bf215546Sopenharmony_ci{
2350bf215546Sopenharmony_ci   if (!(access & SpvMemoryAccessMakePointerAvailableMask))
2351bf215546Sopenharmony_ci      return;
2352bf215546Sopenharmony_ci
2353bf215546Sopenharmony_ci   vtn_emit_memory_barrier(b, scope, SpvMemorySemanticsMakeAvailableMask |
2354bf215546Sopenharmony_ci                                     SpvMemorySemanticsReleaseMask |
2355bf215546Sopenharmony_ci                                     vtn_mode_to_memory_semantics(mode));
2356bf215546Sopenharmony_ci}
2357bf215546Sopenharmony_ci
2358bf215546Sopenharmony_cistatic void
2359bf215546Sopenharmony_ciptr_nonuniform_workaround_cb(struct vtn_builder *b, struct vtn_value *val,
2360bf215546Sopenharmony_ci                  int member, const struct vtn_decoration *dec, void *void_ptr)
2361bf215546Sopenharmony_ci{
2362bf215546Sopenharmony_ci   enum gl_access_qualifier *access = void_ptr;
2363bf215546Sopenharmony_ci
2364bf215546Sopenharmony_ci   switch (dec->decoration) {
2365bf215546Sopenharmony_ci   case SpvDecorationNonUniformEXT:
2366bf215546Sopenharmony_ci      *access |= ACCESS_NON_UNIFORM;
2367bf215546Sopenharmony_ci      break;
2368bf215546Sopenharmony_ci
2369bf215546Sopenharmony_ci   default:
2370bf215546Sopenharmony_ci      break;
2371bf215546Sopenharmony_ci   }
2372bf215546Sopenharmony_ci}
2373bf215546Sopenharmony_ci
2374bf215546Sopenharmony_civoid
2375bf215546Sopenharmony_civtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
2376bf215546Sopenharmony_ci                     const uint32_t *w, unsigned count)
2377bf215546Sopenharmony_ci{
2378bf215546Sopenharmony_ci   switch (opcode) {
2379bf215546Sopenharmony_ci   case SpvOpUndef: {
2380bf215546Sopenharmony_ci      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_undef);
2381bf215546Sopenharmony_ci      val->type = vtn_get_type(b, w[1]);
2382bf215546Sopenharmony_ci      val->is_undef_constant = true;
2383bf215546Sopenharmony_ci      break;
2384bf215546Sopenharmony_ci   }
2385bf215546Sopenharmony_ci
2386bf215546Sopenharmony_ci   case SpvOpVariable: {
2387bf215546Sopenharmony_ci      struct vtn_type *ptr_type = vtn_get_type(b, w[1]);
2388bf215546Sopenharmony_ci
2389bf215546Sopenharmony_ci      SpvStorageClass storage_class = w[3];
2390bf215546Sopenharmony_ci
2391bf215546Sopenharmony_ci      const bool is_global = storage_class != SpvStorageClassFunction;
2392bf215546Sopenharmony_ci      const bool is_io = storage_class == SpvStorageClassInput ||
2393bf215546Sopenharmony_ci                         storage_class == SpvStorageClassOutput;
2394bf215546Sopenharmony_ci
2395bf215546Sopenharmony_ci      /* Skip global variables that are not used by the entrypoint.  Before
2396bf215546Sopenharmony_ci       * SPIR-V 1.4 the interface is only used for I/O variables, so extra
2397bf215546Sopenharmony_ci       * variables will still need to be removed later.
2398bf215546Sopenharmony_ci       */
2399bf215546Sopenharmony_ci      if (!b->options->create_library &&
2400bf215546Sopenharmony_ci          (is_io || (b->version >= 0x10400 && is_global))) {
2401bf215546Sopenharmony_ci         if (!bsearch(&w[2], b->interface_ids, b->interface_ids_count, 4, cmp_uint32_t))
2402bf215546Sopenharmony_ci            break;
2403bf215546Sopenharmony_ci      }
2404bf215546Sopenharmony_ci
2405bf215546Sopenharmony_ci      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer);
2406bf215546Sopenharmony_ci      struct vtn_value *initializer = count > 4 ? vtn_untyped_value(b, w[4]) : NULL;
2407bf215546Sopenharmony_ci
2408bf215546Sopenharmony_ci      vtn_create_variable(b, val, ptr_type, storage_class, initializer);
2409bf215546Sopenharmony_ci
2410bf215546Sopenharmony_ci      break;
2411bf215546Sopenharmony_ci   }
2412bf215546Sopenharmony_ci
2413bf215546Sopenharmony_ci   case SpvOpConstantSampler: {
2414bf215546Sopenharmony_ci      /* Synthesize a pointer-to-sampler type, create a variable of that type,
2415bf215546Sopenharmony_ci       * and give the variable a constant initializer with the sampler params */
2416bf215546Sopenharmony_ci      struct vtn_type *sampler_type = vtn_value(b, w[1], vtn_value_type_type)->type;
2417bf215546Sopenharmony_ci      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer);
2418bf215546Sopenharmony_ci
2419bf215546Sopenharmony_ci      struct vtn_type *ptr_type = rzalloc(b, struct vtn_type);
2420bf215546Sopenharmony_ci      ptr_type = rzalloc(b, struct vtn_type);
2421bf215546Sopenharmony_ci      ptr_type->base_type = vtn_base_type_pointer;
2422bf215546Sopenharmony_ci      ptr_type->deref = sampler_type;
2423bf215546Sopenharmony_ci      ptr_type->storage_class = SpvStorageClassUniform;
2424bf215546Sopenharmony_ci
2425bf215546Sopenharmony_ci      ptr_type->type = nir_address_format_to_glsl_type(
2426bf215546Sopenharmony_ci         vtn_mode_to_address_format(b, vtn_variable_mode_function));
2427bf215546Sopenharmony_ci
2428bf215546Sopenharmony_ci      vtn_create_variable(b, val, ptr_type, ptr_type->storage_class, NULL);
2429bf215546Sopenharmony_ci
2430bf215546Sopenharmony_ci      nir_variable *nir_var = val->pointer->var->var;
2431bf215546Sopenharmony_ci      nir_var->data.sampler.is_inline_sampler = true;
2432bf215546Sopenharmony_ci      nir_var->data.sampler.addressing_mode = w[3];
2433bf215546Sopenharmony_ci      nir_var->data.sampler.normalized_coordinates = w[4];
2434bf215546Sopenharmony_ci      nir_var->data.sampler.filter_mode = w[5];
2435bf215546Sopenharmony_ci
2436bf215546Sopenharmony_ci      break;
2437bf215546Sopenharmony_ci   }
2438bf215546Sopenharmony_ci
2439bf215546Sopenharmony_ci   case SpvOpAccessChain:
2440bf215546Sopenharmony_ci   case SpvOpPtrAccessChain:
2441bf215546Sopenharmony_ci   case SpvOpInBoundsAccessChain:
2442bf215546Sopenharmony_ci   case SpvOpInBoundsPtrAccessChain: {
2443bf215546Sopenharmony_ci      struct vtn_access_chain *chain = vtn_access_chain_create(b, count - 4);
2444bf215546Sopenharmony_ci      enum gl_access_qualifier access = 0;
2445bf215546Sopenharmony_ci      chain->ptr_as_array = (opcode == SpvOpPtrAccessChain || opcode == SpvOpInBoundsPtrAccessChain);
2446bf215546Sopenharmony_ci
2447bf215546Sopenharmony_ci      unsigned idx = 0;
2448bf215546Sopenharmony_ci      for (int i = 4; i < count; i++) {
2449bf215546Sopenharmony_ci         struct vtn_value *link_val = vtn_untyped_value(b, w[i]);
2450bf215546Sopenharmony_ci         if (link_val->value_type == vtn_value_type_constant) {
2451bf215546Sopenharmony_ci            chain->link[idx].mode = vtn_access_mode_literal;
2452bf215546Sopenharmony_ci            chain->link[idx].id = vtn_constant_int(b, w[i]);
2453bf215546Sopenharmony_ci         } else {
2454bf215546Sopenharmony_ci            chain->link[idx].mode = vtn_access_mode_id;
2455bf215546Sopenharmony_ci            chain->link[idx].id = w[i];
2456bf215546Sopenharmony_ci         }
2457bf215546Sopenharmony_ci
2458bf215546Sopenharmony_ci         /* Workaround for https://gitlab.freedesktop.org/mesa/mesa/-/issues/3406 */
2459bf215546Sopenharmony_ci         vtn_foreach_decoration(b, link_val, ptr_nonuniform_workaround_cb, &access);
2460bf215546Sopenharmony_ci
2461bf215546Sopenharmony_ci         idx++;
2462bf215546Sopenharmony_ci      }
2463bf215546Sopenharmony_ci
2464bf215546Sopenharmony_ci      struct vtn_type *ptr_type = vtn_get_type(b, w[1]);
2465bf215546Sopenharmony_ci
2466bf215546Sopenharmony_ci      struct vtn_pointer *base = vtn_pointer(b, w[3]);
2467bf215546Sopenharmony_ci
2468bf215546Sopenharmony_ci      chain->in_bounds = (opcode == SpvOpInBoundsAccessChain || opcode == SpvOpInBoundsPtrAccessChain);
2469bf215546Sopenharmony_ci
2470bf215546Sopenharmony_ci      /* Workaround for https://gitlab.freedesktop.org/mesa/mesa/-/issues/3406 */
2471bf215546Sopenharmony_ci      access |= base->access & ACCESS_NON_UNIFORM;
2472bf215546Sopenharmony_ci
2473bf215546Sopenharmony_ci      struct vtn_pointer *ptr = vtn_pointer_dereference(b, base, chain);
2474bf215546Sopenharmony_ci      ptr->ptr_type = ptr_type;
2475bf215546Sopenharmony_ci      ptr->access |= access;
2476bf215546Sopenharmony_ci      vtn_push_pointer(b, w[2], ptr);
2477bf215546Sopenharmony_ci      break;
2478bf215546Sopenharmony_ci   }
2479bf215546Sopenharmony_ci
2480bf215546Sopenharmony_ci   case SpvOpCopyMemory: {
2481bf215546Sopenharmony_ci      struct vtn_value *dest_val = vtn_pointer_value(b, w[1]);
2482bf215546Sopenharmony_ci      struct vtn_value *src_val = vtn_pointer_value(b, w[2]);
2483bf215546Sopenharmony_ci      struct vtn_pointer *dest = vtn_value_to_pointer(b, dest_val);
2484bf215546Sopenharmony_ci      struct vtn_pointer *src = vtn_value_to_pointer(b, src_val);
2485bf215546Sopenharmony_ci
2486bf215546Sopenharmony_ci      vtn_assert_types_equal(b, opcode, dest_val->type->deref,
2487bf215546Sopenharmony_ci                                        src_val->type->deref);
2488bf215546Sopenharmony_ci
2489bf215546Sopenharmony_ci      unsigned idx = 3, dest_alignment, src_alignment;
2490bf215546Sopenharmony_ci      SpvMemoryAccessMask dest_access, src_access;
2491bf215546Sopenharmony_ci      SpvScope dest_scope, src_scope;
2492bf215546Sopenharmony_ci      vtn_get_mem_operands(b, w, count, &idx, &dest_access, &dest_alignment,
2493bf215546Sopenharmony_ci                           &dest_scope, &src_scope);
2494bf215546Sopenharmony_ci      if (!vtn_get_mem_operands(b, w, count, &idx, &src_access, &src_alignment,
2495bf215546Sopenharmony_ci                                NULL, &src_scope)) {
2496bf215546Sopenharmony_ci         src_alignment = dest_alignment;
2497bf215546Sopenharmony_ci         src_access = dest_access;
2498bf215546Sopenharmony_ci      }
2499bf215546Sopenharmony_ci      src = vtn_align_pointer(b, src, src_alignment);
2500bf215546Sopenharmony_ci      dest = vtn_align_pointer(b, dest, dest_alignment);
2501bf215546Sopenharmony_ci
2502bf215546Sopenharmony_ci      vtn_emit_make_visible_barrier(b, src_access, src_scope, src->mode);
2503bf215546Sopenharmony_ci
2504bf215546Sopenharmony_ci      vtn_variable_copy(b, dest, src,
2505bf215546Sopenharmony_ci                        spv_access_to_gl_access(dest_access),
2506bf215546Sopenharmony_ci                        spv_access_to_gl_access(src_access));
2507bf215546Sopenharmony_ci
2508bf215546Sopenharmony_ci      vtn_emit_make_available_barrier(b, dest_access, dest_scope, dest->mode);
2509bf215546Sopenharmony_ci      break;
2510bf215546Sopenharmony_ci   }
2511bf215546Sopenharmony_ci
2512bf215546Sopenharmony_ci   case SpvOpCopyMemorySized: {
2513bf215546Sopenharmony_ci      struct vtn_value *dest_val = vtn_pointer_value(b, w[1]);
2514bf215546Sopenharmony_ci      struct vtn_value *src_val = vtn_pointer_value(b, w[2]);
2515bf215546Sopenharmony_ci      nir_ssa_def *size = vtn_get_nir_ssa(b, w[3]);
2516bf215546Sopenharmony_ci      struct vtn_pointer *dest = vtn_value_to_pointer(b, dest_val);
2517bf215546Sopenharmony_ci      struct vtn_pointer *src = vtn_value_to_pointer(b, src_val);
2518bf215546Sopenharmony_ci
2519bf215546Sopenharmony_ci      unsigned idx = 4, dest_alignment, src_alignment;
2520bf215546Sopenharmony_ci      SpvMemoryAccessMask dest_access, src_access;
2521bf215546Sopenharmony_ci      SpvScope dest_scope, src_scope;
2522bf215546Sopenharmony_ci      vtn_get_mem_operands(b, w, count, &idx, &dest_access, &dest_alignment,
2523bf215546Sopenharmony_ci                           &dest_scope, &src_scope);
2524bf215546Sopenharmony_ci      if (!vtn_get_mem_operands(b, w, count, &idx, &src_access, &src_alignment,
2525bf215546Sopenharmony_ci                                NULL, &src_scope)) {
2526bf215546Sopenharmony_ci         src_alignment = dest_alignment;
2527bf215546Sopenharmony_ci         src_access = dest_access;
2528bf215546Sopenharmony_ci      }
2529bf215546Sopenharmony_ci      src = vtn_align_pointer(b, src, src_alignment);
2530bf215546Sopenharmony_ci      dest = vtn_align_pointer(b, dest, dest_alignment);
2531bf215546Sopenharmony_ci
2532bf215546Sopenharmony_ci      vtn_emit_make_visible_barrier(b, src_access, src_scope, src->mode);
2533bf215546Sopenharmony_ci
2534bf215546Sopenharmony_ci      nir_memcpy_deref_with_access(&b->nb,
2535bf215546Sopenharmony_ci                                   vtn_pointer_to_deref(b, dest),
2536bf215546Sopenharmony_ci                                   vtn_pointer_to_deref(b, src),
2537bf215546Sopenharmony_ci                                   size,
2538bf215546Sopenharmony_ci                                   spv_access_to_gl_access(dest_access),
2539bf215546Sopenharmony_ci                                   spv_access_to_gl_access(src_access));
2540bf215546Sopenharmony_ci
2541bf215546Sopenharmony_ci      vtn_emit_make_available_barrier(b, dest_access, dest_scope, dest->mode);
2542bf215546Sopenharmony_ci      break;
2543bf215546Sopenharmony_ci   }
2544bf215546Sopenharmony_ci
2545bf215546Sopenharmony_ci   case SpvOpLoad: {
2546bf215546Sopenharmony_ci      struct vtn_type *res_type = vtn_get_type(b, w[1]);
2547bf215546Sopenharmony_ci      struct vtn_value *src_val = vtn_value(b, w[3], vtn_value_type_pointer);
2548bf215546Sopenharmony_ci      struct vtn_pointer *src = vtn_value_to_pointer(b, src_val);
2549bf215546Sopenharmony_ci
2550bf215546Sopenharmony_ci      vtn_assert_types_equal(b, opcode, res_type, src_val->type->deref);
2551bf215546Sopenharmony_ci
2552bf215546Sopenharmony_ci      unsigned idx = 4, alignment;
2553bf215546Sopenharmony_ci      SpvMemoryAccessMask access;
2554bf215546Sopenharmony_ci      SpvScope scope;
2555bf215546Sopenharmony_ci      vtn_get_mem_operands(b, w, count, &idx, &access, &alignment, NULL, &scope);
2556bf215546Sopenharmony_ci      src = vtn_align_pointer(b, src, alignment);
2557bf215546Sopenharmony_ci
2558bf215546Sopenharmony_ci      vtn_emit_make_visible_barrier(b, access, scope, src->mode);
2559bf215546Sopenharmony_ci
2560bf215546Sopenharmony_ci      vtn_push_ssa_value(b, w[2], vtn_variable_load(b, src, spv_access_to_gl_access(access)));
2561bf215546Sopenharmony_ci      break;
2562bf215546Sopenharmony_ci   }
2563bf215546Sopenharmony_ci
2564bf215546Sopenharmony_ci   case SpvOpStore: {
2565bf215546Sopenharmony_ci      struct vtn_value *dest_val = vtn_pointer_value(b, w[1]);
2566bf215546Sopenharmony_ci      struct vtn_pointer *dest = vtn_value_to_pointer(b, dest_val);
2567bf215546Sopenharmony_ci      struct vtn_value *src_val = vtn_untyped_value(b, w[2]);
2568bf215546Sopenharmony_ci
2569bf215546Sopenharmony_ci      /* OpStore requires us to actually have a storage type */
2570bf215546Sopenharmony_ci      vtn_fail_if(dest->type->type == NULL,
2571bf215546Sopenharmony_ci                  "Invalid destination type for OpStore");
2572bf215546Sopenharmony_ci
2573bf215546Sopenharmony_ci      if (glsl_get_base_type(dest->type->type) == GLSL_TYPE_BOOL &&
2574bf215546Sopenharmony_ci          glsl_get_base_type(src_val->type->type) == GLSL_TYPE_UINT) {
2575bf215546Sopenharmony_ci         /* Early versions of GLSLang would use uint types for UBOs/SSBOs but
2576bf215546Sopenharmony_ci          * would then store them to a local variable as bool.  Work around
2577bf215546Sopenharmony_ci          * the issue by doing an implicit conversion.
2578bf215546Sopenharmony_ci          *
2579bf215546Sopenharmony_ci          * https://github.com/KhronosGroup/glslang/issues/170
2580bf215546Sopenharmony_ci          * https://bugs.freedesktop.org/show_bug.cgi?id=104424
2581bf215546Sopenharmony_ci          */
2582bf215546Sopenharmony_ci         vtn_warn("OpStore of value of type OpTypeInt to a pointer to type "
2583bf215546Sopenharmony_ci                  "OpTypeBool.  Doing an implicit conversion to work around "
2584bf215546Sopenharmony_ci                  "the problem.");
2585bf215546Sopenharmony_ci         struct vtn_ssa_value *bool_ssa =
2586bf215546Sopenharmony_ci            vtn_create_ssa_value(b, dest->type->type);
2587bf215546Sopenharmony_ci         bool_ssa->def = nir_i2b(&b->nb, vtn_ssa_value(b, w[2])->def);
2588bf215546Sopenharmony_ci         vtn_variable_store(b, bool_ssa, dest, 0);
2589bf215546Sopenharmony_ci         break;
2590bf215546Sopenharmony_ci      }
2591bf215546Sopenharmony_ci
2592bf215546Sopenharmony_ci      vtn_assert_types_equal(b, opcode, dest_val->type->deref, src_val->type);
2593bf215546Sopenharmony_ci
2594bf215546Sopenharmony_ci      unsigned idx = 3, alignment;
2595bf215546Sopenharmony_ci      SpvMemoryAccessMask access;
2596bf215546Sopenharmony_ci      SpvScope scope;
2597bf215546Sopenharmony_ci      vtn_get_mem_operands(b, w, count, &idx, &access, &alignment, &scope, NULL);
2598bf215546Sopenharmony_ci      dest = vtn_align_pointer(b, dest, alignment);
2599bf215546Sopenharmony_ci
2600bf215546Sopenharmony_ci      struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]);
2601bf215546Sopenharmony_ci      vtn_variable_store(b, src, dest, spv_access_to_gl_access(access));
2602bf215546Sopenharmony_ci
2603bf215546Sopenharmony_ci      vtn_emit_make_available_barrier(b, access, scope, dest->mode);
2604bf215546Sopenharmony_ci      break;
2605bf215546Sopenharmony_ci   }
2606bf215546Sopenharmony_ci
2607bf215546Sopenharmony_ci   case SpvOpArrayLength: {
2608bf215546Sopenharmony_ci      struct vtn_pointer *ptr = vtn_pointer(b, w[3]);
2609bf215546Sopenharmony_ci      const uint32_t field = w[4];
2610bf215546Sopenharmony_ci
2611bf215546Sopenharmony_ci      vtn_fail_if(ptr->type->base_type != vtn_base_type_struct,
2612bf215546Sopenharmony_ci                  "OpArrayLength must take a pointer to a structure type");
2613bf215546Sopenharmony_ci      vtn_fail_if(field != ptr->type->length - 1 ||
2614bf215546Sopenharmony_ci                  ptr->type->members[field]->base_type != vtn_base_type_array,
2615bf215546Sopenharmony_ci                  "OpArrayLength must reference the last memeber of the "
2616bf215546Sopenharmony_ci                  "structure and that must be an array");
2617bf215546Sopenharmony_ci
2618bf215546Sopenharmony_ci      if (b->options->use_deref_buffer_array_length) {
2619bf215546Sopenharmony_ci         struct vtn_access_chain chain = {
2620bf215546Sopenharmony_ci            .length = 1,
2621bf215546Sopenharmony_ci            .link = {
2622bf215546Sopenharmony_ci               { .mode = vtn_access_mode_literal, .id = field },
2623bf215546Sopenharmony_ci            }
2624bf215546Sopenharmony_ci         };
2625bf215546Sopenharmony_ci         struct vtn_pointer *array = vtn_pointer_dereference(b, ptr, &chain);
2626bf215546Sopenharmony_ci
2627bf215546Sopenharmony_ci         nir_ssa_def *array_length =
2628bf215546Sopenharmony_ci            nir_build_deref_buffer_array_length(&b->nb, 32,
2629bf215546Sopenharmony_ci                                                vtn_pointer_to_ssa(b, array),
2630bf215546Sopenharmony_ci                                                .access=ptr->access | ptr->type->access);
2631bf215546Sopenharmony_ci
2632bf215546Sopenharmony_ci         vtn_push_nir_ssa(b, w[2], array_length);
2633bf215546Sopenharmony_ci      } else {
2634bf215546Sopenharmony_ci         const uint32_t offset = ptr->type->offsets[field];
2635bf215546Sopenharmony_ci         const uint32_t stride = ptr->type->members[field]->stride;
2636bf215546Sopenharmony_ci
2637bf215546Sopenharmony_ci         if (!ptr->block_index) {
2638bf215546Sopenharmony_ci            struct vtn_access_chain chain = {
2639bf215546Sopenharmony_ci               .length = 0,
2640bf215546Sopenharmony_ci            };
2641bf215546Sopenharmony_ci            ptr = vtn_pointer_dereference(b, ptr, &chain);
2642bf215546Sopenharmony_ci            vtn_assert(ptr->block_index);
2643bf215546Sopenharmony_ci         }
2644bf215546Sopenharmony_ci
2645bf215546Sopenharmony_ci         nir_ssa_def *buf_size = nir_get_ssbo_size(&b->nb, ptr->block_index,
2646bf215546Sopenharmony_ci                                                   .access=ptr->access | ptr->type->access);
2647bf215546Sopenharmony_ci
2648bf215546Sopenharmony_ci         /* array_length = max(buffer_size - offset, 0) / stride */
2649bf215546Sopenharmony_ci         nir_ssa_def *array_length =
2650bf215546Sopenharmony_ci            nir_udiv_imm(&b->nb,
2651bf215546Sopenharmony_ci                         nir_usub_sat(&b->nb,
2652bf215546Sopenharmony_ci                                      buf_size,
2653bf215546Sopenharmony_ci                                      nir_imm_int(&b->nb, offset)),
2654bf215546Sopenharmony_ci                         stride);
2655bf215546Sopenharmony_ci
2656bf215546Sopenharmony_ci         vtn_push_nir_ssa(b, w[2], array_length);
2657bf215546Sopenharmony_ci      }
2658bf215546Sopenharmony_ci      break;
2659bf215546Sopenharmony_ci   }
2660bf215546Sopenharmony_ci
2661bf215546Sopenharmony_ci   case SpvOpConvertPtrToU: {
2662bf215546Sopenharmony_ci      struct vtn_type *u_type = vtn_get_type(b, w[1]);
2663bf215546Sopenharmony_ci      struct vtn_type *ptr_type = vtn_get_value_type(b, w[3]);
2664bf215546Sopenharmony_ci
2665bf215546Sopenharmony_ci      vtn_fail_if(ptr_type->base_type != vtn_base_type_pointer ||
2666bf215546Sopenharmony_ci                  ptr_type->type == NULL,
2667bf215546Sopenharmony_ci                  "OpConvertPtrToU can only be used on physical pointers");
2668bf215546Sopenharmony_ci
2669bf215546Sopenharmony_ci      vtn_fail_if(u_type->base_type != vtn_base_type_vector &&
2670bf215546Sopenharmony_ci                  u_type->base_type != vtn_base_type_scalar,
2671bf215546Sopenharmony_ci                  "OpConvertPtrToU can only be used to cast to a vector or "
2672bf215546Sopenharmony_ci                  "scalar type");
2673bf215546Sopenharmony_ci
2674bf215546Sopenharmony_ci      /* The pointer will be converted to an SSA value automatically */
2675bf215546Sopenharmony_ci      nir_ssa_def *ptr = vtn_get_nir_ssa(b, w[3]);
2676bf215546Sopenharmony_ci      nir_ssa_def *u = nir_sloppy_bitcast(&b->nb, ptr, u_type->type);
2677bf215546Sopenharmony_ci      vtn_push_nir_ssa(b, w[2], u);
2678bf215546Sopenharmony_ci      break;
2679bf215546Sopenharmony_ci   }
2680bf215546Sopenharmony_ci
2681bf215546Sopenharmony_ci   case SpvOpConvertUToPtr: {
2682bf215546Sopenharmony_ci      struct vtn_type *ptr_type = vtn_get_type(b, w[1]);
2683bf215546Sopenharmony_ci      struct vtn_type *u_type = vtn_get_value_type(b, w[3]);
2684bf215546Sopenharmony_ci
2685bf215546Sopenharmony_ci      vtn_fail_if(ptr_type->base_type != vtn_base_type_pointer ||
2686bf215546Sopenharmony_ci                  ptr_type->type == NULL,
2687bf215546Sopenharmony_ci                  "OpConvertUToPtr can only be used on physical pointers");
2688bf215546Sopenharmony_ci
2689bf215546Sopenharmony_ci      vtn_fail_if(u_type->base_type != vtn_base_type_vector &&
2690bf215546Sopenharmony_ci                  u_type->base_type != vtn_base_type_scalar,
2691bf215546Sopenharmony_ci                  "OpConvertUToPtr can only be used to cast from a vector or "
2692bf215546Sopenharmony_ci                  "scalar type");
2693bf215546Sopenharmony_ci
2694bf215546Sopenharmony_ci      nir_ssa_def *u = vtn_get_nir_ssa(b, w[3]);
2695bf215546Sopenharmony_ci      nir_ssa_def *ptr = nir_sloppy_bitcast(&b->nb, u, ptr_type->type);
2696bf215546Sopenharmony_ci      vtn_push_pointer(b, w[2], vtn_pointer_from_ssa(b, ptr, ptr_type));
2697bf215546Sopenharmony_ci      break;
2698bf215546Sopenharmony_ci   }
2699bf215546Sopenharmony_ci
2700bf215546Sopenharmony_ci   case SpvOpGenericCastToPtrExplicit: {
2701bf215546Sopenharmony_ci      struct vtn_type *dst_type = vtn_get_type(b, w[1]);
2702bf215546Sopenharmony_ci      struct vtn_type *src_type = vtn_get_value_type(b, w[3]);
2703bf215546Sopenharmony_ci      SpvStorageClass storage_class = w[4];
2704bf215546Sopenharmony_ci
2705bf215546Sopenharmony_ci      vtn_fail_if(dst_type->base_type != vtn_base_type_pointer ||
2706bf215546Sopenharmony_ci                  dst_type->storage_class != storage_class,
2707bf215546Sopenharmony_ci                  "Result type of an SpvOpGenericCastToPtrExplicit must be "
2708bf215546Sopenharmony_ci                  "an OpTypePointer. Its Storage Class must match the "
2709bf215546Sopenharmony_ci                  "storage class specified in the instruction");
2710bf215546Sopenharmony_ci
2711bf215546Sopenharmony_ci      vtn_fail_if(src_type->base_type != vtn_base_type_pointer ||
2712bf215546Sopenharmony_ci                  src_type->deref->id != dst_type->deref->id,
2713bf215546Sopenharmony_ci                  "Source pointer of an SpvOpGenericCastToPtrExplicit must "
2714bf215546Sopenharmony_ci                  "have a type of OpTypePointer whose Type is the same as "
2715bf215546Sopenharmony_ci                  "the Type of Result Type");
2716bf215546Sopenharmony_ci
2717bf215546Sopenharmony_ci      vtn_fail_if(src_type->storage_class != SpvStorageClassGeneric,
2718bf215546Sopenharmony_ci                  "Source pointer of an SpvOpGenericCastToPtrExplicit must "
2719bf215546Sopenharmony_ci                  "point to the Generic Storage Class.");
2720bf215546Sopenharmony_ci
2721bf215546Sopenharmony_ci      vtn_fail_if(storage_class != SpvStorageClassWorkgroup &&
2722bf215546Sopenharmony_ci                  storage_class != SpvStorageClassCrossWorkgroup &&
2723bf215546Sopenharmony_ci                  storage_class != SpvStorageClassFunction,
2724bf215546Sopenharmony_ci                  "Storage must be one of the following literal values from "
2725bf215546Sopenharmony_ci                  "Storage Class: Workgroup, CrossWorkgroup, or Function.");
2726bf215546Sopenharmony_ci
2727bf215546Sopenharmony_ci      nir_deref_instr *src_deref = vtn_nir_deref(b, w[3]);
2728bf215546Sopenharmony_ci
2729bf215546Sopenharmony_ci      nir_variable_mode nir_mode;
2730bf215546Sopenharmony_ci      enum vtn_variable_mode mode =
2731bf215546Sopenharmony_ci         vtn_storage_class_to_mode(b, storage_class, dst_type->deref, &nir_mode);
2732bf215546Sopenharmony_ci      nir_address_format addr_format = vtn_mode_to_address_format(b, mode);
2733bf215546Sopenharmony_ci
2734bf215546Sopenharmony_ci      nir_ssa_def *null_value =
2735bf215546Sopenharmony_ci         nir_build_imm(&b->nb, nir_address_format_num_components(addr_format),
2736bf215546Sopenharmony_ci                               nir_address_format_bit_size(addr_format),
2737bf215546Sopenharmony_ci                               nir_address_format_null_value(addr_format));
2738bf215546Sopenharmony_ci
2739bf215546Sopenharmony_ci      nir_ssa_def *valid = nir_build_deref_mode_is(&b->nb, 1, &src_deref->dest.ssa, nir_mode);
2740bf215546Sopenharmony_ci      vtn_push_nir_ssa(b, w[2], nir_bcsel(&b->nb, valid,
2741bf215546Sopenharmony_ci                                                  &src_deref->dest.ssa,
2742bf215546Sopenharmony_ci                                                  null_value));
2743bf215546Sopenharmony_ci      break;
2744bf215546Sopenharmony_ci   }
2745bf215546Sopenharmony_ci
2746bf215546Sopenharmony_ci   case SpvOpGenericPtrMemSemantics: {
2747bf215546Sopenharmony_ci      struct vtn_type *dst_type = vtn_get_type(b, w[1]);
2748bf215546Sopenharmony_ci      struct vtn_type *src_type = vtn_get_value_type(b, w[3]);
2749bf215546Sopenharmony_ci
2750bf215546Sopenharmony_ci      vtn_fail_if(dst_type->base_type != vtn_base_type_scalar ||
2751bf215546Sopenharmony_ci                  dst_type->type != glsl_uint_type(),
2752bf215546Sopenharmony_ci                  "Result type of an SpvOpGenericPtrMemSemantics must be "
2753bf215546Sopenharmony_ci                  "an OpTypeInt with 32-bit Width and 0 Signedness.");
2754bf215546Sopenharmony_ci
2755bf215546Sopenharmony_ci      vtn_fail_if(src_type->base_type != vtn_base_type_pointer ||
2756bf215546Sopenharmony_ci                  src_type->storage_class != SpvStorageClassGeneric,
2757bf215546Sopenharmony_ci                  "Source pointer of an SpvOpGenericPtrMemSemantics must "
2758bf215546Sopenharmony_ci                  "point to the Generic Storage Class");
2759bf215546Sopenharmony_ci
2760bf215546Sopenharmony_ci      nir_deref_instr *src_deref = vtn_nir_deref(b, w[3]);
2761bf215546Sopenharmony_ci
2762bf215546Sopenharmony_ci      nir_ssa_def *global_bit =
2763bf215546Sopenharmony_ci         nir_bcsel(&b->nb, nir_build_deref_mode_is(&b->nb, 1, &src_deref->dest.ssa,
2764bf215546Sopenharmony_ci                                                   nir_var_mem_global),
2765bf215546Sopenharmony_ci                   nir_imm_int(&b->nb, SpvMemorySemanticsCrossWorkgroupMemoryMask),
2766bf215546Sopenharmony_ci                   nir_imm_int(&b->nb, 0));
2767bf215546Sopenharmony_ci
2768bf215546Sopenharmony_ci      nir_ssa_def *shared_bit =
2769bf215546Sopenharmony_ci         nir_bcsel(&b->nb, nir_build_deref_mode_is(&b->nb, 1, &src_deref->dest.ssa,
2770bf215546Sopenharmony_ci                                                   nir_var_mem_shared),
2771bf215546Sopenharmony_ci                   nir_imm_int(&b->nb, SpvMemorySemanticsWorkgroupMemoryMask),
2772bf215546Sopenharmony_ci                   nir_imm_int(&b->nb, 0));
2773bf215546Sopenharmony_ci
2774bf215546Sopenharmony_ci      vtn_push_nir_ssa(b, w[2], nir_iand(&b->nb, global_bit, shared_bit));
2775bf215546Sopenharmony_ci      break;
2776bf215546Sopenharmony_ci   }
2777bf215546Sopenharmony_ci
2778bf215546Sopenharmony_ci   case SpvOpSubgroupBlockReadINTEL: {
2779bf215546Sopenharmony_ci      struct vtn_type *res_type = vtn_get_type(b, w[1]);
2780bf215546Sopenharmony_ci      nir_deref_instr *src = vtn_nir_deref(b, w[3]);
2781bf215546Sopenharmony_ci
2782bf215546Sopenharmony_ci      nir_intrinsic_instr *load =
2783bf215546Sopenharmony_ci         nir_intrinsic_instr_create(b->nb.shader,
2784bf215546Sopenharmony_ci                                    nir_intrinsic_load_deref_block_intel);
2785bf215546Sopenharmony_ci      load->src[0] = nir_src_for_ssa(&src->dest.ssa);
2786bf215546Sopenharmony_ci      nir_ssa_dest_init_for_type(&load->instr, &load->dest,
2787bf215546Sopenharmony_ci                                 res_type->type, NULL);
2788bf215546Sopenharmony_ci      load->num_components = load->dest.ssa.num_components;
2789bf215546Sopenharmony_ci      nir_builder_instr_insert(&b->nb, &load->instr);
2790bf215546Sopenharmony_ci
2791bf215546Sopenharmony_ci      vtn_push_nir_ssa(b, w[2], &load->dest.ssa);
2792bf215546Sopenharmony_ci      break;
2793bf215546Sopenharmony_ci   }
2794bf215546Sopenharmony_ci
2795bf215546Sopenharmony_ci   case SpvOpSubgroupBlockWriteINTEL: {
2796bf215546Sopenharmony_ci      nir_deref_instr *dest = vtn_nir_deref(b, w[1]);
2797bf215546Sopenharmony_ci      nir_ssa_def *data = vtn_ssa_value(b, w[2])->def;
2798bf215546Sopenharmony_ci
2799bf215546Sopenharmony_ci      nir_intrinsic_instr *store =
2800bf215546Sopenharmony_ci         nir_intrinsic_instr_create(b->nb.shader,
2801bf215546Sopenharmony_ci                                    nir_intrinsic_store_deref_block_intel);
2802bf215546Sopenharmony_ci      store->src[0] = nir_src_for_ssa(&dest->dest.ssa);
2803bf215546Sopenharmony_ci      store->src[1] = nir_src_for_ssa(data);
2804bf215546Sopenharmony_ci      store->num_components = data->num_components;
2805bf215546Sopenharmony_ci      nir_builder_instr_insert(&b->nb, &store->instr);
2806bf215546Sopenharmony_ci      break;
2807bf215546Sopenharmony_ci   }
2808bf215546Sopenharmony_ci
2809bf215546Sopenharmony_ci   case SpvOpConvertUToAccelerationStructureKHR: {
2810bf215546Sopenharmony_ci      struct vtn_type *as_type = vtn_get_type(b, w[1]);
2811bf215546Sopenharmony_ci      struct vtn_type *u_type = vtn_get_value_type(b, w[3]);
2812bf215546Sopenharmony_ci      vtn_fail_if(!((u_type->base_type == vtn_base_type_vector &&
2813bf215546Sopenharmony_ci                     u_type->type == glsl_vector_type(GLSL_TYPE_UINT, 2)) ||
2814bf215546Sopenharmony_ci                    (u_type->base_type == vtn_base_type_scalar &&
2815bf215546Sopenharmony_ci                     u_type->type == glsl_uint64_t_type())),
2816bf215546Sopenharmony_ci                  "OpConvertUToAccelerationStructure may only be used to "
2817bf215546Sopenharmony_ci                  "cast from a 64-bit scalar integer or a 2-component vector "
2818bf215546Sopenharmony_ci                  "of 32-bit integers");
2819bf215546Sopenharmony_ci      vtn_fail_if(as_type->base_type != vtn_base_type_accel_struct,
2820bf215546Sopenharmony_ci                  "The result type of an OpConvertUToAccelerationStructure "
2821bf215546Sopenharmony_ci                  "must be OpTypeAccelerationStructure");
2822bf215546Sopenharmony_ci
2823bf215546Sopenharmony_ci      nir_ssa_def *u = vtn_get_nir_ssa(b, w[3]);
2824bf215546Sopenharmony_ci      vtn_push_nir_ssa(b, w[2], nir_sloppy_bitcast(&b->nb, u, as_type->type));
2825bf215546Sopenharmony_ci      break;
2826bf215546Sopenharmony_ci   }
2827bf215546Sopenharmony_ci
2828bf215546Sopenharmony_ci   default:
2829bf215546Sopenharmony_ci      vtn_fail_with_opcode("Unhandled opcode", opcode);
2830bf215546Sopenharmony_ci   }
2831bf215546Sopenharmony_ci}
2832