[Mesa-dev] [PATCH 20/22] nir/spirv: physical pointer support

Karol Herbst kherbst at redhat.com
Tue Nov 13 15:48:24 UTC 2018


this adds support for pointers from CL kernels. The basic idea here is to be
able to start a deref chain from a random ssa value and vice versa.

changes summed up:
1. derefs can start from a deref_cast
2. new ptr_as_array deref type to offset a pointer
3. derefs can end with a ssa_from_deref intrinsic

One problem with this implementation is, that we don't track if a deref points
to a value or a pointer, allthough shouldn't cause any problem at runtime as a
pointer gets fed into a load or ssa_from_deref.

What annoys me more is that we need to keep track of the original SSA value we
started the pointer from. For graphics that's most of the time a variable or
something we can base the pointer on, but for kernels we usually start from a
plain SSA value.

Currently I reuse the UBO offset variable to keep track of the initial ssa
value, but it's hacky. Most bits of the patch feels rather hacky, but it is
much smaller than what we had with the fat ptr approach and I don't have to add
a new phys_pointer value type, which made things a lot easier.

Signed-off-by: Karol Herbst <kherbst at redhat.com>
---
 src/compiler/nir/nir.c                        |  4 +-
 src/compiler/nir/nir.h                        |  9 ++
 src/compiler/nir/nir_builder.h                | 37 +++++++-
 src/compiler/nir/nir_clone.c                  |  1 +
 src/compiler/nir/nir_deref.c                  | 26 +++++-
 src/compiler/nir/nir_instr_set.c              |  2 +
 src/compiler/nir/nir_intrinsics.py            |  7 ++
 src/compiler/nir/nir_loop_analyze.c           |  2 +-
 src/compiler/nir/nir_lower_indirect_derefs.c  |  6 +-
 src/compiler/nir/nir_lower_io.c               | 79 +++++++++++-----
 .../nir/nir_lower_io_arrays_to_elements.c     |  4 +-
 src/compiler/nir/nir_lower_locals_to_regs.c   |  9 +-
 src/compiler/nir/nir_lower_var_copies.c       |  3 +-
 src/compiler/nir/nir_lower_vars_to_ssa.c      | 12 ++-
 src/compiler/nir/nir_opt_copy_propagate.c     |  2 +-
 src/compiler/nir/nir_opt_dead_write_vars.c    |  4 +-
 src/compiler/nir/nir_print.c                  |  6 +-
 src/compiler/nir/nir_propagate_invariant.c    |  2 +
 src/compiler/nir/nir_remove_dead_variables.c  |  2 +
 src/compiler/nir/nir_serialize.c              |  2 +
 src/compiler/nir/nir_split_vars.c             |  4 +-
 src/compiler/nir/nir_validate.c               | 17 +++-
 src/compiler/spirv/spirv_to_nir.c             | 28 +++++-
 src/compiler/spirv/vtn_cfg.c                  |  3 +-
 src/compiler/spirv/vtn_private.h              |  1 +
 src/compiler/spirv/vtn_variables.c            | 90 +++++++++++++++----
 26 files changed, 296 insertions(+), 66 deletions(-)

diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c
index ca258b7c80e..66648885ec7 100644
--- a/src/compiler/nir/nir.c
+++ b/src/compiler/nir/nir.c
@@ -463,7 +463,7 @@ nir_deref_instr_create(nir_shader *shader, nir_deref_type deref_type)
    if (deref_type != nir_deref_type_var)
       src_init(&instr->parent);
 
-   if (deref_type == nir_deref_type_array)
+   if (nir_deref_is_array(instr))
       src_init(&instr->arr.index);
 
    dest_init(&instr->dest);
@@ -1069,7 +1069,7 @@ visit_deref_instr_src(nir_deref_instr *instr,
          return false;
    }
 
-   if (instr->deref_type == nir_deref_type_array) {
+   if (nir_deref_is_array(instr)) {
       if (!visit_src(&instr->arr.index, cb, state))
          return false;
    }
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
index 35f2ec02c31..40f5a0e4e06 100644
--- a/src/compiler/nir/nir.h
+++ b/src/compiler/nir/nir.h
@@ -990,6 +990,7 @@ typedef enum {
    nir_deref_type_array_wildcard,
    nir_deref_type_struct,
    nir_deref_type_cast,
+   nir_deref_type_ptr_as_array,
 } nir_deref_type;
 
 typedef struct {
@@ -1014,6 +1015,7 @@ typedef struct {
 
    /** Additional deref parameters */
    union {
+      /** used for deref_array and deref_ptr_as_array */
       struct {
          nir_src index;
       } arr;
@@ -1068,6 +1070,13 @@ bool nir_deref_instr_has_indirect(nir_deref_instr *instr);
 
 bool nir_deref_instr_remove_if_unused(nir_deref_instr *instr);
 
+static inline bool
+nir_deref_is_array(const nir_deref_instr *instr)
+{
+   return instr->deref_type == nir_deref_type_array ||
+          instr->deref_type == nir_deref_type_ptr_as_array;
+}
+
 typedef struct {
    nir_instr instr;
 
diff --git a/src/compiler/nir/nir_builder.h b/src/compiler/nir/nir_builder.h
index 57f0a188c46..428c6b4fd78 100644
--- a/src/compiler/nir/nir_builder.h
+++ b/src/compiler/nir/nir_builder.h
@@ -623,6 +623,7 @@ nir_ssa_for_alu_src(nir_builder *build, nir_alu_instr *instr, unsigned srcn)
 static inline nir_deref_instr *
 nir_build_deref_var(nir_builder *build, nir_variable *var)
 {
+   unsigned ptr_size = build->shader->ptr_size ? build->shader->ptr_size : 32;
    nir_deref_instr *deref =
       nir_deref_instr_create(build->shader, nir_deref_type_var);
 
@@ -630,7 +631,7 @@ nir_build_deref_var(nir_builder *build, nir_variable *var)
    deref->type = var->type;
    deref->var = var;
 
-   nir_ssa_dest_init(&deref->instr, &deref->dest, 1, 32, NULL);
+   nir_ssa_dest_init(&deref->instr, &deref->dest, 1, ptr_size, NULL);
 
    nir_builder_instr_insert(build, &deref->instr);
 
@@ -662,6 +663,27 @@ nir_build_deref_array(nir_builder *build, nir_deref_instr *parent,
    return deref;
 }
 
+static inline nir_deref_instr *
+nir_build_deref_ptr_as_array(nir_builder *build, nir_deref_instr *parent,
+                             nir_ssa_def *index, const struct glsl_type *type)
+{
+   nir_deref_instr *deref =
+      nir_deref_instr_create(build->shader, nir_deref_type_ptr_as_array);
+
+   deref->mode = parent->mode;
+   deref->type = type;
+   deref->parent = nir_src_for_ssa(&parent->dest.ssa);
+   deref->arr.index = nir_src_for_ssa(index);
+
+   nir_ssa_dest_init(&deref->instr, &deref->dest,
+                     parent->dest.ssa.num_components,
+                     parent->dest.ssa.bit_size, NULL);
+
+   nir_builder_instr_insert(build, &deref->instr);
+
+   return deref;
+}
+
 static inline nir_deref_instr *
 nir_build_deref_array_wildcard(nir_builder *build, nir_deref_instr *parent)
 {
@@ -793,6 +815,19 @@ nir_load_deref(nir_builder *build, nir_deref_instr *deref)
    return &load->dest.ssa;
 }
 
+static inline nir_ssa_def*
+nir_ssa_from_deref(nir_builder *build, nir_deref_instr *deref,
+                   const struct glsl_type *type)
+{
+   nir_intrinsic_instr *ssa =
+      nir_intrinsic_instr_create(build->shader, nir_intrinsic_ssa_from_deref);
+   ssa->num_components = glsl_get_vector_elements(type);
+   ssa->src[0] = nir_src_for_ssa(&deref->dest.ssa);
+   nir_ssa_dest_init_for_type(&ssa->instr, &ssa->dest, type, NULL);
+   nir_builder_instr_insert(build, &ssa->instr);
+   return &ssa->dest.ssa;
+}
+
 static inline void
 nir_store_deref(nir_builder *build, nir_deref_instr *deref,
                 nir_ssa_def *value, unsigned writemask)
diff --git a/src/compiler/nir/nir_clone.c b/src/compiler/nir/nir_clone.c
index d47d3e8cb72..5f4ba1c4559 100644
--- a/src/compiler/nir/nir_clone.c
+++ b/src/compiler/nir/nir_clone.c
@@ -311,6 +311,7 @@ clone_deref_instr(clone_state *state, const nir_deref_instr *deref)
       break;
 
    case nir_deref_type_array:
+   case nir_deref_type_ptr_as_array:
       __clone_src(state, &nderef->instr,
                   &nderef->arr.index, &deref->arr.index);
       break;
diff --git a/src/compiler/nir/nir_deref.c b/src/compiler/nir/nir_deref.c
index 4a2e81956d1..e882fd04276 100644
--- a/src/compiler/nir/nir_deref.c
+++ b/src/compiler/nir/nir_deref.c
@@ -70,7 +70,8 @@ nir_deref_path_init(nir_deref_path *path,
 done:
    assert(head == path->path);
    assert(tail == head + count);
-   assert((*head)->deref_type == nir_deref_type_var);
+   assert((*head)->deref_type == nir_deref_type_var ||
+          (*head)->deref_type == nir_deref_type_cast);
    assert(*tail == NULL);
 }
 
@@ -111,7 +112,7 @@ nir_deref_instr_has_indirect(nir_deref_instr *instr)
       if (instr->deref_type == nir_deref_type_cast)
          return true;
 
-      if (instr->deref_type == nir_deref_type_array &&
+      if (nir_deref_is_array(instr) &&
           !nir_src_is_const(instr->arr.index))
          return true;
 
@@ -256,6 +257,9 @@ nir_fixup_deref_modes(nir_shader *shader)
 
             nir_deref_instr *deref = nir_instr_as_deref(instr);
 
+            if (deref->deref_type == nir_deref_type_cast)
+               continue;
+
             nir_variable_mode parent_mode;
             if (deref->deref_type == nir_deref_type_var) {
                parent_mode = deref->var->data.mode;
@@ -279,6 +283,20 @@ nir_compare_deref_paths(nir_deref_path *a_path,
    if (a_path->path[0]->var != b_path->path[0]->var)
       return 0;
 
+   /* first compare root element */
+   if (a_path->path[0]->deref_type != b_path->path[0]->deref_type)
+      return 0;
+
+   if (a_path->path[0]->deref_type == nir_deref_type_var &&
+       a_path->path[0]->var != b_path->path[0]->var)
+         return 0;
+
+   if (a_path->path[0]->deref_type == nir_deref_type_cast &&
+       !nir_srcs_equal(a_path->path[0]->parent, b_path->path[0]->parent))
+         return 0;
+
+   /* TODO: path[0] could be within the other path */
+
    /* Start off assuming they fully compare.  We ignore equality for now.  In
     * the end, we'll determine that by containment.
     */
@@ -368,8 +386,8 @@ nir_compare_derefs(nir_deref_instr *a, nir_deref_instr *b)
    nir_deref_path a_path, b_path;
    nir_deref_path_init(&a_path, a, NULL);
    nir_deref_path_init(&b_path, b, NULL);
-   assert(a_path.path[0]->deref_type == nir_deref_type_var);
-   assert(b_path.path[0]->deref_type == nir_deref_type_var);
+   assert(a_path.path[0]->deref_type == nir_deref_type_var || a_path.path[0]->deref_type == nir_deref_type_cast);
+   assert(b_path.path[0]->deref_type == nir_deref_type_var || b_path.path[0]->deref_type == nir_deref_type_cast);
 
    nir_deref_compare_result result = nir_compare_deref_paths(&a_path, &b_path);
 
diff --git a/src/compiler/nir/nir_instr_set.c b/src/compiler/nir/nir_instr_set.c
index 19771fcd9dd..68df08d0c47 100644
--- a/src/compiler/nir/nir_instr_set.c
+++ b/src/compiler/nir/nir_instr_set.c
@@ -96,6 +96,7 @@ hash_deref(uint32_t hash, const nir_deref_instr *instr)
       break;
 
    case nir_deref_type_array:
+   case nir_deref_type_ptr_as_array:
       hash = hash_src(hash, &instr->arr.index);
       break;
 
@@ -344,6 +345,7 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2)
          break;
 
       case nir_deref_type_array:
+      case nir_deref_type_ptr_as_array:
          if (!nir_srcs_equal(deref1->arr.index, deref2->arr.index))
             return false;
          break;
diff --git a/src/compiler/nir/nir_intrinsics.py b/src/compiler/nir/nir_intrinsics.py
index 6bcce81b14e..0869f03ff3c 100644
--- a/src/compiler/nir/nir_intrinsics.py
+++ b/src/compiler/nir/nir_intrinsics.py
@@ -136,6 +136,7 @@ intrinsic("load_param", dest_comp=0, indices=[PARAM_IDX], flags=[CAN_ELIMINATE])
 intrinsic("load_deref", dest_comp=0, src_comp=[1], flags=[CAN_ELIMINATE])
 intrinsic("store_deref", src_comp=[1, 0], indices=[WRMASK])
 intrinsic("copy_deref", src_comp=[1, 1])
+intrinsic("ssa_from_deref", dest_comp=0, src_comp=[1], flags=[CAN_ELIMINATE])
 
 # Interpolation of input.  The interp_deref_at* intrinsics are similar to the
 # load_var intrinsic acting on a shader input except that they interpolate the
@@ -581,6 +582,9 @@ load("shared", 1, [BASE], [CAN_ELIMINATE])
 load("push_constant", 1, [BASE, RANGE], [CAN_ELIMINATE, CAN_REORDER])
 # src[] = { offset }. const_index[] = { base, range }
 load("constant", 1, [BASE, RANGE], [CAN_ELIMINATE, CAN_REORDER])
+# src[] = { address }. No const_index
+load("global", 1, flags=[CAN_ELIMINATE])
+load("private", 1, flags=[CAN_ELIMINATE])
 
 # Stores work the same way as loads, except now the first source is the value
 # to store and the second (and possibly third) source specify where to store
@@ -599,3 +603,6 @@ store("per_vertex_output", 3, [BASE, WRMASK, COMPONENT])
 store("ssbo", 3, [WRMASK, ACCESS])
 # src[] = { value, offset }. const_index[] = { base, write_mask }
 store("shared", 2, [BASE, WRMASK])
+# src[] = { value, address }. const_index[] = { write_mask }
+store("global", 2, [WRMASK])
+store("private", 2, [WRMASK])
diff --git a/src/compiler/nir/nir_loop_analyze.c b/src/compiler/nir/nir_loop_analyze.c
index 9c3fd2f286f..40931086df3 100644
--- a/src/compiler/nir/nir_loop_analyze.c
+++ b/src/compiler/nir/nir_loop_analyze.c
@@ -628,7 +628,7 @@ force_unroll_array_access(loop_info_state *state, nir_shader *ns,
                           nir_deref_instr *deref)
 {
    for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
-      if (d->deref_type != nir_deref_type_array)
+      if (!nir_deref_is_array(d))
          continue;
 
       assert(d->arr.index.is_ssa);
diff --git a/src/compiler/nir/nir_lower_indirect_derefs.c b/src/compiler/nir/nir_lower_indirect_derefs.c
index 897a0620872..f42422d3745 100644
--- a/src/compiler/nir/nir_lower_indirect_derefs.c
+++ b/src/compiler/nir/nir_lower_indirect_derefs.c
@@ -50,7 +50,7 @@ emit_indirect_load_store_deref(nir_builder *b, nir_intrinsic_instr *orig_instr,
       nir_ssa_def *then_dest, *else_dest;
 
       nir_deref_instr *deref = *deref_arr;
-      assert(deref->deref_type == nir_deref_type_array);
+      assert(nir_deref_is_array(deref));
 
       nir_push_if(b, nir_ilt(b, deref->arr.index.ssa, nir_imm_int(b, mid)));
       emit_indirect_load_store_deref(b, orig_instr, parent, deref_arr,
@@ -73,7 +73,7 @@ emit_load_store_deref(nir_builder *b, nir_intrinsic_instr *orig_instr,
 {
    for (; *deref_arr; deref_arr++) {
       nir_deref_instr *deref = *deref_arr;
-      if (deref->deref_type == nir_deref_type_array &&
+      if (nir_deref_is_array(deref) &&
           !nir_src_is_const(deref->arr.index)) {
          int length = glsl_get_length(parent->type);
 
@@ -136,7 +136,7 @@ lower_indirect_derefs_block(nir_block *block, nir_builder *b,
       bool has_indirect = false;
       nir_deref_instr *base = deref;
       while (base->deref_type != nir_deref_type_var) {
-         if (base->deref_type == nir_deref_type_array &&
+         if (nir_deref_is_array(base) &&
              !nir_src_is_const(base->arr.index))
             has_indirect = true;
 
diff --git a/src/compiler/nir/nir_lower_io.c b/src/compiler/nir/nir_lower_io.c
index 292baf9e4fc..02e3027b337 100644
--- a/src/compiler/nir/nir_lower_io.c
+++ b/src/compiler/nir/nir_lower_io.c
@@ -108,8 +108,10 @@ get_io_offset(nir_deref_instr *deref, nir_ssa_def **vertex_index,
       state->mm->type_align : default_type_align;
    nir_deref_path path;
    nir_deref_path_init(&path, deref, NULL);
+   unsigned ptr_size = b->shader->ptr_size ? b->shader->ptr_size : 32;
 
-   assert(path.path[0]->deref_type == nir_deref_type_var);
+   nir_deref_instr *parent = path.path[0];
+   assert(parent->deref_type == nir_deref_type_var || parent->deref_type == nir_deref_type_cast);
    nir_deref_instr **p = &path.path[1];
 
    /* For per-vertex input arrays (i.e. geometry shader inputs), keep the
@@ -121,7 +123,7 @@ get_io_offset(nir_deref_instr *deref, nir_ssa_def **vertex_index,
       p++;
    }
 
-   if (path.path[0]->var->data.compact) {
+   if (path.path[0]->var && path.path[0]->var->data.compact) {
       assert((*p)->deref_type == nir_deref_type_array);
       assert(glsl_type_is_scalar((*p)->type));
 
@@ -134,15 +136,19 @@ get_io_offset(nir_deref_instr *deref, nir_ssa_def **vertex_index,
    }
 
    /* Just emit code and let constant-folding go to town */
-   nir_ssa_def *offset = nir_imm_int(b, 0);
+   nir_ssa_def *offset;
+   if (parent->deref_type == nir_deref_type_var)
+      offset = nir_imm_intN_t(b, 0, ptr_size);
+   else
+      offset = nir_ssa_for_src(b, parent->parent, 1);
 
    for (; *p; p++) {
-      if ((*p)->deref_type == nir_deref_type_array) {
+      if (nir_deref_is_array(*p)) {
          unsigned size = type_size((*p)->type);
+         nir_ssa_def *src = nir_ssa_for_src(b, (*p)->arr.index, 1);
 
          nir_ssa_def *mul =
-            nir_imul(b, nir_imm_int(b, size),
-                     nir_ssa_for_src(b, (*p)->arr.index, 1));
+            nir_imul(b, nir_imm_intN_t(b, size, src->bit_size), src);
 
          offset = nir_iadd(b, offset, mul);
       } else if ((*p)->deref_type == nir_deref_type_struct) {
@@ -156,7 +162,9 @@ get_io_offset(nir_deref_instr *deref, nir_ssa_def **vertex_index,
             field_offset = align(field_offset, type_align(field_type));
             field_offset += type_size(field_type);
          }
-         offset = nir_iadd(b, offset, nir_imm_int(b, field_offset));
+         offset = nir_iadd(b, offset, nir_imm_intN_t(b, field_offset, offset->bit_size));
+      } else if ((*p)->deref_type == nir_deref_type_cast) {
+         continue;
       } else {
          unreachable("Unsupported deref type");
       }
@@ -170,10 +178,10 @@ get_io_offset(nir_deref_instr *deref, nir_ssa_def **vertex_index,
 static nir_intrinsic_instr *
 lower_load(nir_intrinsic_instr *intrin, struct lower_io_state *state,
            nir_ssa_def *vertex_index, nir_variable *var, nir_ssa_def *offset,
-           unsigned component)
+           unsigned component, nir_variable_mode mode_no_var)
 {
    const nir_shader *nir = state->builder.shader;
-   nir_variable_mode mode = var->data.mode;
+   nir_variable_mode mode = var ? var->data.mode : mode_no_var;
    nir_ssa_def *barycentric = NULL;
 
    nir_intrinsic_op op;
@@ -211,6 +219,9 @@ lower_load(nir_intrinsic_instr *intrin, struct lower_io_state *state,
    case nir_var_shared:
       op = nir_intrinsic_load_shared;
       break;
+   case nir_var_global:
+      op = nir_intrinsic_load_global;
+      break;
    default:
       unreachable("Unknown variable mode");
    }
@@ -219,7 +230,9 @@ lower_load(nir_intrinsic_instr *intrin, struct lower_io_state *state,
       nir_intrinsic_instr_create(state->builder.shader, op);
    load->num_components = intrin->num_components;
 
-   nir_intrinsic_set_base(load, var->data.driver_location);
+   if (mode != nir_var_global)
+      nir_intrinsic_set_base(load, var->data.driver_location);
+
    if (mode == nir_var_shader_in || mode == nir_var_shader_out)
       nir_intrinsic_set_component(load, component);
 
@@ -242,13 +255,15 @@ lower_load(nir_intrinsic_instr *intrin, struct lower_io_state *state,
 static nir_intrinsic_instr *
 lower_store(nir_intrinsic_instr *intrin, struct lower_io_state *state,
             nir_ssa_def *vertex_index, nir_variable *var, nir_ssa_def *offset,
-            unsigned component)
+            unsigned component, nir_variable_mode mode_no_var)
 {
-   nir_variable_mode mode = var->data.mode;
+   nir_variable_mode mode = var ? var->data.mode : mode_no_var;
 
    nir_intrinsic_op op;
    if (mode == nir_var_shared) {
       op = nir_intrinsic_store_shared;
+   } else if (mode == nir_var_global) {
+      op = nir_intrinsic_store_global;
    } else {
       assert(mode == nir_var_shader_out);
       op = vertex_index ? nir_intrinsic_store_per_vertex_output :
@@ -261,7 +276,8 @@ lower_store(nir_intrinsic_instr *intrin, struct lower_io_state *state,
 
    nir_src_copy(&store->src[0], &intrin->src[1], store);
 
-   nir_intrinsic_set_base(store, var->data.driver_location);
+   if (mode != nir_var_global)
+      nir_intrinsic_set_base(store, var->data.driver_location);
 
    if (mode == nir_var_shader_out)
       nir_intrinsic_set_component(store, component);
@@ -276,6 +292,13 @@ lower_store(nir_intrinsic_instr *intrin, struct lower_io_state *state,
    return store;
 }
 
+static nir_ssa_def *
+lower_ssa_from_deref(nir_intrinsic_instr *intrin, struct lower_io_state *state,
+                     nir_ssa_def *offset, unsigned component)
+{
+   return offset;
+}
+
 static nir_intrinsic_instr *
 lower_atomic(nir_intrinsic_instr *intrin, struct lower_io_state *state,
              nir_variable *var, nir_ssa_def *offset)
@@ -327,7 +350,7 @@ lower_interpolate_at(nir_intrinsic_instr *intrin, struct lower_io_state *state,
 
    /* Ignore interpolateAt() for flat variables - flat is flat. */
    if (var->data.interpolation == INTERP_MODE_FLAT)
-      return lower_load(intrin, state, NULL, var, offset, component);
+      return lower_load(intrin, state, NULL, var, offset, component, nir_var_shader_in);
 
    nir_intrinsic_op bary_op;
    switch (intrin->intrinsic) {
@@ -389,6 +412,7 @@ nir_lower_io_block(nir_block *block,
       switch (intrin->intrinsic) {
       case nir_intrinsic_load_deref:
       case nir_intrinsic_store_deref:
+      case nir_intrinsic_ssa_from_deref:
       case nir_intrinsic_deref_atomic_add:
       case nir_intrinsic_deref_atomic_imin:
       case nir_intrinsic_deref_atomic_umin:
@@ -419,7 +443,7 @@ nir_lower_io_block(nir_block *block,
       nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
 
       nir_variable *var = nir_deref_instr_get_variable(deref);
-      nir_variable_mode mode = var->data.mode;
+      nir_variable_mode mode = var ? var->data.mode : deref->mode;
 
       if ((state->modes & mode) == 0)
          continue;
@@ -427,16 +451,17 @@ nir_lower_io_block(nir_block *block,
       if (mode != nir_var_shader_in &&
           mode != nir_var_shader_out &&
           mode != nir_var_shared &&
-          mode != nir_var_uniform)
+          mode != nir_var_uniform &&
+          mode != nir_var_global)
          continue;
 
       b->cursor = nir_before_instr(instr);
 
-      const bool per_vertex = nir_is_per_vertex_io(var, b->shader->info.stage);
+      const bool per_vertex = var ? nir_is_per_vertex_io(var, b->shader->info.stage) : false;
 
       nir_ssa_def *offset;
       nir_ssa_def *vertex_index = NULL;
-      unsigned component_offset = var->data.location_frac;
+      unsigned component_offset = var ? var->data.location_frac : 0;
 
       offset = get_io_offset(deref, per_vertex ? &vertex_index : NULL,
                              state, &component_offset);
@@ -446,14 +471,28 @@ nir_lower_io_block(nir_block *block,
       switch (intrin->intrinsic) {
       case nir_intrinsic_load_deref:
          replacement = lower_load(intrin, state, vertex_index, var, offset,
-                                  component_offset);
+                                  component_offset, mode);
          break;
 
       case nir_intrinsic_store_deref:
          replacement = lower_store(intrin, state, vertex_index, var, offset,
-                                   component_offset);
+                                   component_offset, mode);
          break;
 
+      case nir_intrinsic_ssa_from_deref: {
+         nir_ssa_def *def = lower_ssa_from_deref(intrin, state, offset,
+                                            component_offset);
+         if (intrin->dest.is_ssa) {
+            nir_ssa_def_rewrite_uses(&intrin->dest.ssa, nir_src_for_ssa(def));
+         } else {
+            // TODO
+//            nir_dest_copy(&replacement->dest, &intrin->dest, &intrin->instr);
+         }
+         nir_instr_remove(&intrin->instr);
+         progress = true;
+         continue;
+      }
+
       case nir_intrinsic_deref_atomic_add:
       case nir_intrinsic_deref_atomic_imin:
       case nir_intrinsic_deref_atomic_umin:
diff --git a/src/compiler/nir/nir_lower_io_arrays_to_elements.c b/src/compiler/nir/nir_lower_io_arrays_to_elements.c
index f0bc487d6be..1ab908560e5 100644
--- a/src/compiler/nir/nir_lower_io_arrays_to_elements.c
+++ b/src/compiler/nir/nir_lower_io_arrays_to_elements.c
@@ -52,7 +52,7 @@ get_io_offset(nir_builder *b, nir_deref_instr *deref, nir_variable *var,
 
    unsigned offset = 0;
    for (; *p; p++) {
-      if ((*p)->deref_type == nir_deref_type_array) {
+      if (nir_deref_is_array(*p)) {
          /* must not be indirect dereference */
          unsigned index = nir_src_as_uint((*p)->arr.index);
 
@@ -191,7 +191,7 @@ deref_has_indirect(nir_builder *b, nir_variable *var, nir_deref_path *path)
    }
 
    for (; *p; p++) {
-      if ((*p)->deref_type != nir_deref_type_array)
+      if (!nir_deref_is_array(*p))
          continue;
 
       if (!nir_src_is_const((*p)->arr.index))
diff --git a/src/compiler/nir/nir_lower_locals_to_regs.c b/src/compiler/nir/nir_lower_locals_to_regs.c
index 773b7fde6d0..d4a0fc9ff53 100644
--- a/src/compiler/nir/nir_lower_locals_to_regs.c
+++ b/src/compiler/nir/nir_lower_locals_to_regs.c
@@ -54,6 +54,7 @@ hash_deref(const void *void_deref)
          return _mesa_fnv32_1a_accumulate(hash, deref->var);
 
       case nir_deref_type_array:
+      case nir_deref_type_ptr_as_array:
          continue; /* Do nothing */
 
       case nir_deref_type_struct:
@@ -155,20 +156,22 @@ get_deref_reg_src(nir_deref_instr *deref, struct locals_to_regs_state *state)
          src.reg.base_offset += nir_src_as_uint(d->arr.index) *
                                 inner_array_size;
       } else {
+         nir_ssa_def *src1 = nir_ssa_for_src(b, d->arr.index, 1);
+
          if (src.reg.indirect) {
             assert(src.reg.base_offset == 0);
          } else {
             src.reg.indirect = ralloc(b->shader, nir_src);
             *src.reg.indirect =
-               nir_src_for_ssa(nir_imm_int(b, src.reg.base_offset));
+               nir_src_for_ssa(nir_imm_intN_t(b, src.reg.base_offset, src1->bit_size));
             src.reg.base_offset = 0;
          }
 
          assert(src.reg.indirect->is_ssa);
          src.reg.indirect->ssa =
             nir_iadd(b, src.reg.indirect->ssa,
-                        nir_imul(b, nir_ssa_for_src(b, d->arr.index, 1),
-                                    nir_imm_int(b, inner_array_size)));
+                        nir_imul(b, src1,
+                                 nir_imm_intN_t(b, inner_array_size, src1->bit_size)));
       }
 
       inner_array_size *= glsl_get_length(nir_deref_instr_parent(d)->type);
diff --git a/src/compiler/nir/nir_lower_var_copies.c b/src/compiler/nir/nir_lower_var_copies.c
index e72f7efcecb..6fd0e432c47 100644
--- a/src/compiler/nir/nir_lower_var_copies.c
+++ b/src/compiler/nir/nir_lower_var_copies.c
@@ -65,6 +65,7 @@ emit_deref_copy_load_store(nir_builder *b,
    }
 
    if (dst_deref_arr || src_deref_arr) {
+      unsigned ptr_size = b->shader->ptr_size ? b->shader->ptr_size : 32;
       assert(dst_deref_arr && src_deref_arr);
       assert((*dst_deref_arr)->deref_type == nir_deref_type_array_wildcard);
       assert((*src_deref_arr)->deref_type == nir_deref_type_array_wildcard);
@@ -75,7 +76,7 @@ emit_deref_copy_load_store(nir_builder *b,
       assert(length > 0);
 
       for (unsigned i = 0; i < length; i++) {
-         nir_ssa_def *index = nir_imm_int(b, i);
+         nir_ssa_def *index = nir_imm_intN_t(b, i, ptr_size);
          emit_deref_copy_load_store(b,
                                     nir_build_deref_array(b, dst_deref, index),
                                     dst_deref_arr + 1,
diff --git a/src/compiler/nir/nir_lower_vars_to_ssa.c b/src/compiler/nir/nir_lower_vars_to_ssa.c
index 8e517a78957..b294a00b26d 100644
--- a/src/compiler/nir/nir_lower_vars_to_ssa.c
+++ b/src/compiler/nir/nir_lower_vars_to_ssa.c
@@ -161,14 +161,19 @@ get_deref_node_recur(nir_deref_instr *deref,
 
       return parent->children[deref->strct.index];
 
+   case nir_deref_type_ptr_as_array:
+      return parent;
+
    case nir_deref_type_array: {
       if (nir_src_is_const(deref->arr.index)) {
+         const struct glsl_type *parent_type = deref->deref_type == nir_deref_type_array ? parent->type : deref->type;
          uint32_t index = nir_src_as_uint(deref->arr.index);
          /* This is possible if a loop unrolls and generates an
           * out-of-bounds offset.  We need to handle this at least
           * somewhat gracefully.
           */
-         if (index >= glsl_get_length(parent->type))
+         assert(glsl_type_is_array(parent_type));
+         if (index >= glsl_get_length(parent_type))
             return NULL;
 
          if (parent->children[index] == NULL) {
@@ -197,6 +202,9 @@ get_deref_node_recur(nir_deref_instr *deref,
 
       return parent->wildcard;
 
+   case nir_deref_type_cast:
+      return parent->children[0];
+
    default:
       unreachable("Invalid deref type");
    }
@@ -250,6 +258,7 @@ foreach_deref_node_worker(struct deref_node *node, nir_deref_instr **path,
       }
       return;
 
+   case nir_deref_type_ptr_as_array:
    case nir_deref_type_array: {
       uint32_t index = nir_src_as_uint((*path)->arr.index);
 
@@ -314,6 +323,7 @@ path_may_be_aliased_node(struct deref_node *node, nir_deref_instr **path,
          return false;
       }
 
+   case nir_deref_type_ptr_as_array:
    case nir_deref_type_array: {
       if (!nir_src_is_const((*path)->arr.index))
          return true;
diff --git a/src/compiler/nir/nir_opt_copy_propagate.c b/src/compiler/nir/nir_opt_copy_propagate.c
index 189d544979b..a3e7bd18e47 100644
--- a/src/compiler/nir/nir_opt_copy_propagate.c
+++ b/src/compiler/nir/nir_opt_copy_propagate.c
@@ -246,7 +246,7 @@ copy_prop_instr(nir_instr *instr)
             progress = true;
       }
 
-      if (deref->deref_type == nir_deref_type_array) {
+      if (nir_deref_is_array(deref)) {
          while (copy_prop_src(&deref->arr.index, instr, NULL, 1))
             progress = true;
       }
diff --git a/src/compiler/nir/nir_opt_dead_write_vars.c b/src/compiler/nir/nir_opt_dead_write_vars.c
index 0fbbe63f436..ec61e1fad51 100644
--- a/src/compiler/nir/nir_opt_dead_write_vars.c
+++ b/src/compiler/nir/nir_opt_dead_write_vars.c
@@ -79,10 +79,10 @@ update_unused_writes(struct util_dynarray *unused_writes,
    bool progress = false;
 
    /* This pass assumes that destination of copies and stores are derefs that
-    * end in a vector or scalar (it is OK to have wildcards or indirects for
+    * end in a vector, scalar or struct (it is OK to have wildcards or indirects for
     * arrays).
     */
-   assert(glsl_type_is_vector_or_scalar(dst->type));
+   assert(glsl_type_is_vector_or_scalar(dst->type) || glsl_type_is_struct(dst->type));
 
    /* Find writes that are unused and can be removed. */
    util_dynarray_foreach_reverse(unused_writes, struct write_entry, entry) {
diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c
index 2fb041039c6..e60a2eba25b 100644
--- a/src/compiler/nir/nir_print.c
+++ b/src/compiler/nir/nir_print.c
@@ -586,7 +586,8 @@ print_deref_link(nir_deref_instr *instr, bool whole_chain, print_state *state)
               glsl_get_struct_elem_name(parent->type, instr->strct.index));
       break;
 
-   case nir_deref_type_array: {
+   case nir_deref_type_array:
+   case nir_deref_type_ptr_as_array: {
       nir_const_value *const_index = nir_src_as_const_value(instr->arr.index);
       if (const_index) {
          fprintf(fp, "[%u]", const_index->u32[0]);
@@ -628,6 +629,9 @@ print_deref_instr(nir_deref_instr *instr, print_state *state)
    case nir_deref_type_cast:
       fprintf(fp, " = deref_cast ");
       break;
+   case nir_deref_type_ptr_as_array:
+      fprintf(fp, " = deref_ptr_as_array ");
+      break;
    default:
       unreachable("Invalid deref instruction type");
    }
diff --git a/src/compiler/nir/nir_propagate_invariant.c b/src/compiler/nir/nir_propagate_invariant.c
index eb858f50f03..3477dc31f78 100644
--- a/src/compiler/nir/nir_propagate_invariant.c
+++ b/src/compiler/nir/nir_propagate_invariant.c
@@ -71,6 +71,8 @@ add_var(nir_variable *var, struct set *invariants)
 static bool
 var_is_invariant(nir_variable *var, struct set * invariants)
 {
+   if (!var)
+      return false;
    return var->data.invariant || _mesa_set_search(invariants, var);
 }
 
diff --git a/src/compiler/nir/nir_remove_dead_variables.c b/src/compiler/nir/nir_remove_dead_variables.c
index d09e823c517..8ddb8a8a98f 100644
--- a/src/compiler/nir/nir_remove_dead_variables.c
+++ b/src/compiler/nir/nir_remove_dead_variables.c
@@ -107,6 +107,8 @@ remove_dead_var_writes(nir_shader *shader, struct set *live)
                nir_variable_mode parent_mode;
                if (deref->deref_type == nir_deref_type_var)
                   parent_mode = deref->var->data.mode;
+               else if (!nir_deref_instr_parent(deref))
+                  parent_mode = deref->mode;
                else
                   parent_mode = nir_deref_instr_parent(deref)->mode;
 
diff --git a/src/compiler/nir/nir_serialize.c b/src/compiler/nir/nir_serialize.c
index 5ec6972b02a..1aad7437d60 100644
--- a/src/compiler/nir/nir_serialize.c
+++ b/src/compiler/nir/nir_serialize.c
@@ -438,6 +438,7 @@ write_deref(write_ctx *ctx, const nir_deref_instr *deref)
       break;
 
    case nir_deref_type_array:
+   case nir_deref_type_ptr_as_array:
       write_src(ctx, &deref->arr.index);
       break;
 
@@ -475,6 +476,7 @@ read_deref(read_ctx *ctx)
       break;
 
    case nir_deref_type_array:
+   case nir_deref_type_ptr_as_array:
       read_src(ctx, &deref->arr.index, &deref->instr);
       break;
 
diff --git a/src/compiler/nir/nir_split_vars.c b/src/compiler/nir/nir_split_vars.c
index 9d1a096268c..97f9ed2910e 100644
--- a/src/compiler/nir/nir_split_vars.c
+++ b/src/compiler/nir/nir_split_vars.c
@@ -395,7 +395,7 @@ mark_array_deref_used(nir_deref_instr *deref,
     */
    for (unsigned i = 0; i < info->num_levels; i++) {
       nir_deref_instr *p = path.path[i + 1];
-      if (p->deref_type == nir_deref_type_array &&
+      if (nir_deref_is_array(p) &&
           !nir_src_is_const(p->arr.index))
          info->levels[i].split = false;
    }
@@ -1369,7 +1369,7 @@ shrink_vec_var_access_impl(nir_function_impl *impl,
              */
             if (deref->deref_type == nir_deref_type_var) {
                deref->type = deref->var->type;
-            } else if (deref->deref_type == nir_deref_type_array ||
+            } else if (nir_deref_is_array(deref) ||
                        deref->deref_type == nir_deref_type_array_wildcard) {
                nir_deref_instr *parent = nir_deref_instr_parent(deref);
                assert(glsl_type_is_array(parent->type) ||
diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c
index 62893cad87e..7808383c72d 100644
--- a/src/compiler/nir/nir_validate.c
+++ b/src/compiler/nir/nir_validate.c
@@ -136,6 +136,7 @@ validate_reg_src(nir_src *src, validate_state *state,
                  unsigned bit_size, unsigned num_components)
 {
    validate_assert(state, src->reg.reg != NULL);
+   unsigned ptr_size = state->shader->ptr_size ? state->shader->ptr_size : 32;
 
    struct hash_entry *entry;
    entry = _mesa_hash_table_search(state->regs, src->reg.reg);
@@ -171,7 +172,7 @@ validate_reg_src(nir_src *src, validate_state *state,
       validate_assert(state, (src->reg.indirect->is_ssa ||
               src->reg.indirect->reg.indirect == NULL) &&
              "only one level of indirection allowed");
-      validate_src(src->reg.indirect, state, 32, 1);
+      validate_src(src->reg.indirect, state, ptr_size, 1);
    }
 }
 
@@ -464,10 +465,20 @@ validate_deref_instr(nir_deref_instr *instr, validate_state *state)
          validate_assert(state,
             instr->type == glsl_get_array_element(parent->type));
 
-         if (instr->deref_type == nir_deref_type_array)
-            validate_src(&instr->arr.index, state, 32, 1);
+         if (nir_deref_is_array(instr))
+            validate_src(&instr->arr.index, state, 0, 1);
          break;
 
+      case nir_deref_type_ptr_as_array: {
+         /* parent can only be deref_casts with no parent */
+//         nir_deref_instr *parent = nir_deref_instr_parent(instr);
+//         validate_assert(state, parent);
+//         validate_assert(state, parent->deref_type == nir_deref_type_cast);
+//         validate_assert(state, !nir_deref_instr_parent(parent));
+         validate_src(&instr->arr.index, state, 0, 1);
+         break;
+      }
+
       default:
          unreachable("Invalid deref instruction type");
       }
diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index dbac3b2e052..8c341e9c1fa 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -1221,6 +1221,17 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
       val->type->storage_class = storage_class;
       val->type->deref = deref_type;
 
+      /* in kernel mode all pointers are sized according to the addressing
+       * model
+       */
+      if (b->kernel_mode) {
+         if (b->shader->ptr_size == 64)
+            val->type->type = glsl_uint64_t_type();
+         else
+            val->type->type = glsl_uint_type();
+         break;
+      }
+
       if (storage_class == SpvStorageClassUniform ||
           storage_class == SpvStorageClassStorageBuffer) {
          /* These can actually be stored to nir_variables and used as SSA
@@ -3894,6 +3905,7 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpAccessChain:
    case SpvOpPtrAccessChain:
    case SpvOpInBoundsAccessChain:
+   case SpvOpInBoundsPtrAccessChain:
    case SpvOpArrayLength:
       vtn_handle_variables(b, opcode, w, count);
       break;
@@ -4349,17 +4361,29 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
       nir_call_instr *call = nir_call_instr_create(b->nb.shader, entry_point);
 
       for (unsigned i = 0; i < entry_point->num_params; ++i) {
+         struct vtn_type *type = b->entry_point->func->type->params[i];
+         bool is_fake_ptr = type->base_type == vtn_base_type_pointer && type->storage_class == SpvStorageClassFunction;
+
          /* input variable */
          nir_variable *in_var = rzalloc(b->nb.shader, nir_variable);
          in_var->data.mode = nir_var_shader_in;
          in_var->data.read_only = true;
          in_var->data.location = i;
-         in_var->type = b->entry_point->func->type->params[i]->type;
+         if (is_fake_ptr)
+            in_var->type = type->deref->type;
+         else
+            in_var->type = type->type;
 
          nir_shader_add_variable(b->nb.shader, in_var);
          b->nb.shader->num_inputs++;
 
-         call->params[i] = nir_src_for_ssa(nir_load_var(&b->nb, in_var));
+         if (is_fake_ptr) {
+            nir_variable *copy_var = nir_local_variable_create(main_entry_point->impl, in_var->type, in_var->name);
+            nir_copy_var(&b->nb, copy_var, in_var);
+            call->params[i] = nir_src_for_ssa(&nir_build_deref_var(&b->nb, copy_var)->dest.ssa);
+         } else {
+            call->params[i] = nir_src_for_ssa(nir_load_var(&b->nb, in_var));
+         }
       }
 
       nir_builder_instr_insert(&b->nb, &call->instr);
diff --git a/src/compiler/spirv/vtn_cfg.c b/src/compiler/spirv/vtn_cfg.c
index 726f717e8d5..925ba34e0ad 100644
--- a/src/compiler/spirv/vtn_cfg.c
+++ b/src/compiler/spirv/vtn_cfg.c
@@ -236,6 +236,7 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
 {
    switch (opcode) {
    case SpvOpFunction: {
+      unsigned ptr_size = b->kernel_mode ? b->shader->ptr_size : 32;
       vtn_assert(b->func == NULL);
       b->func = rzalloc(b, struct vtn_function);
 
@@ -270,7 +271,7 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
       if (func_type->return_type->base_type != vtn_base_type_void) {
          /* The return value is a regular pointer */
          func->params[idx++] = (nir_parameter) {
-            .num_components = 1, .bit_size = 32,
+            .num_components = 1, .bit_size = ptr_size,
          };
       }
 
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 4dec2b66ff0..8ccebaabef9 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -398,6 +398,7 @@ enum vtn_access_mode {
 struct vtn_access_link {
    enum vtn_access_mode mode;
    uint32_t id;
+   struct vtn_type *type;
 };
 
 struct vtn_access_chain {
diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c
index 7896e58f7e5..20838998596 100644
--- a/src/compiler/spirv/vtn_variables.c
+++ b/src/compiler/spirv/vtn_variables.c
@@ -29,6 +29,12 @@
 #include "spirv_info.h"
 #include "nir_deref.h"
 
+static enum vtn_variable_mode
+vtn_storage_class_to_mode(struct vtn_builder *b,
+                          SpvStorageClass class,
+                          struct vtn_type *interface_type,
+                          nir_variable_mode *nir_mode_out);
+
 static struct vtn_access_chain *
 vtn_access_chain_create(struct vtn_builder *b, unsigned length)
 {
@@ -88,14 +94,19 @@ vtn_access_chain_pointer_dereference(struct vtn_builder *b,
 {
    struct vtn_access_chain *chain =
       vtn_access_chain_extend(b, base->chain, deref_chain->length);
-   struct vtn_type *type = base->type;
+   struct vtn_type *type;
    enum gl_access_qualifier access = base->access;
 
    /* OpPtrAccessChain is only allowed on things which support variable
     * pointers.  For everything else, the client is expected to just pass us
     * the right access chain.
     */
-   vtn_assert(!deref_chain->ptr_as_array);
+   vtn_assert(!deref_chain->ptr_as_array || b->kernel_mode);
+
+   if (deref_chain->ptr_as_array)
+      type = base->ptr_type;
+   else
+      type = base->type;
 
    unsigned start = base->chain ? base->chain->length : 0;
    for (unsigned i = 0; i < deref_chain->length; i++) {
@@ -104,10 +115,14 @@ vtn_access_chain_pointer_dereference(struct vtn_builder *b,
       if (glsl_type_is_struct(type->type)) {
          vtn_assert(deref_chain->link[i].mode == vtn_access_mode_literal);
          type = type->members[deref_chain->link[i].id];
+      } else if (deref_chain->ptr_as_array) {
+         type = type->deref;
       } else {
          type = type->array_element;
       }
 
+      chain->link[start + i].type = type;
+
       access |= type->access;
    }
 
@@ -118,6 +133,7 @@ vtn_access_chain_pointer_dereference(struct vtn_builder *b,
    ptr->deref = base->deref;
    ptr->chain = chain;
    ptr->access = access;
+   ptr->offset = base->offset;
 
    return ptr;
 }
@@ -360,7 +376,7 @@ vtn_pointer_dereference(struct vtn_builder *b,
                         struct vtn_pointer *base,
                         struct vtn_access_chain *deref_chain)
 {
-   if (vtn_pointer_uses_ssa_offset(b, base)) {
+   if (vtn_pointer_uses_ssa_offset(b, base) && !b->kernel_mode) {
       return vtn_ssa_offset_pointer_dereference(b, base, deref_chain);
    } else {
       return vtn_access_chain_pointer_dereference(b, base, deref_chain);
@@ -416,32 +432,64 @@ vtn_pointer_to_deref(struct vtn_builder *b, struct vtn_pointer *ptr)
    nir_deref_instr *tail;
    if (ptr->deref) {
       tail = ptr->deref;
-   } else {
-      assert(ptr->var && ptr->var->var);
+   } else if (ptr->var) {
+      vtn_assert(ptr->var->var);
       tail = nir_build_deref_var(&b->nb, ptr->var->var);
+   } else {
+      vtn_assert(b->kernel_mode);
+      nir_variable_mode mode;
+      const struct glsl_type *type;
+
+      if (ptr->chain)
+         type = ptr->chain->link[0].type->type;
+      else
+         type = ptr->type->type;
+
+      vtn_storage_class_to_mode(b, ptr->ptr_type->storage_class, NULL, &mode);
+      tail = nir_build_deref_cast(&b->nb, ptr->offset, mode, type);
    }
 
-   /* Raw variable access */
    if (!ptr->chain)
       return tail;
 
    struct vtn_access_chain *chain = ptr->chain;
    vtn_assert(chain);
 
-   for (unsigned i = 0; i < chain->length; i++) {
-      if (glsl_type_is_struct(tail->type)) {
-         vtn_assert(chain->link[i].mode == vtn_access_mode_literal);
+   unsigned i = 0;
+   if (b->kernel_mode) {
+      /* local are special and we just ignore the first deref at 0 */
+      nir_ssa_def *index;
+      if (tail->mode == nir_var_local) {
+         vtn_assert(chain->link[0].mode == vtn_access_mode_literal);
+         vtn_assert(chain->link[0].id == 0);
+      } else {
+         if (chain->link[0].mode == vtn_access_mode_literal) {
+            index = nir_imm_intN_t(&b->nb, chain->link[0].id, b->shader->ptr_size ? b->shader->ptr_size : 32);
+         } else {
+            vtn_assert(chain->link[0].mode == vtn_access_mode_id);
+            index = vtn_ssa_value(b, chain->link[0].id)->def;
+         }
+         tail = nir_build_deref_ptr_as_array(&b->nb, tail, index, chain->link[0].type->type);
+      }
+      i++;
+   }
+
+   for (; i < chain->length; i++) {
+      if (glsl_type_is_struct(tail->type) && chain->link[i].mode == vtn_access_mode_literal) {
          unsigned idx = chain->link[i].id;
          tail = nir_build_deref_struct(&b->nb, tail, idx);
       } else {
          nir_ssa_def *index;
          if (chain->link[i].mode == vtn_access_mode_literal) {
-            index = nir_imm_int(&b->nb, chain->link[i].id);
+            index = nir_imm_intN_t(&b->nb, chain->link[i].id, b->shader->ptr_size ? b->shader->ptr_size : 32);
          } else {
             vtn_assert(chain->link[i].mode == vtn_access_mode_id);
             index = vtn_ssa_value(b, chain->link[i].id)->def;
          }
-         tail = nir_build_deref_array(&b->nb, tail, index);
+         if (glsl_type_is_array(tail->type))
+            tail = nir_build_deref_array(&b->nb, tail, index);
+         else
+            tail = nir_build_deref_ptr_as_array(&b->nb, tail, index, chain->link[i].type->type);
       }
    }
 
@@ -878,7 +926,7 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load,
    case GLSL_TYPE_FLOAT:
    case GLSL_TYPE_FLOAT16:
    case GLSL_TYPE_BOOL:
-   case GLSL_TYPE_DOUBLE:
+   case GLSL_TYPE_DOUBLE: {
       /* At this point, we have a scalar, vector, or matrix so we know that
        * there cannot be any structure splitting still in the way.  By
        * stopping at the matrix level rather than the vector level, we
@@ -891,6 +939,7 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load,
          vtn_local_store(b, *inout, vtn_pointer_to_deref(b, ptr));
       }
       return;
+   }
 
    case GLSL_TYPE_ARRAY:
    case GLSL_TYPE_STRUCT: {
@@ -1616,7 +1665,11 @@ vtn_pointer_to_ssa(struct vtn_builder *b, struct vtn_pointer *ptr)
          return ptr->offset;
       }
    } else {
-      return &vtn_pointer_to_deref(b, ptr)->dest.ssa;
+      nir_deref_instr *deref = vtn_pointer_to_deref(b, ptr);
+
+      if (b->kernel_mode)
+         return nir_ssa_from_deref(&b->nb, deref, ptr->ptr_type->type);
+      return &deref->dest.ssa;
    }
 }
 
@@ -1624,7 +1677,9 @@ struct vtn_pointer *
 vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
                      struct vtn_type *ptr_type)
 {
-   vtn_assert(ssa->num_components <= 2 && ssa->bit_size == 32);
+   vtn_assert(ssa->num_components <= 2 &&
+      ((!b->kernel_mode && ssa->bit_size == 32) ||
+       (b->kernel_mode && ssa->bit_size == b->shader->ptr_size)));
    vtn_assert(ptr_type->base_type == vtn_base_type_pointer);
 
    struct vtn_type *interface_type = ptr_type->deref;
@@ -1646,6 +1701,7 @@ vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
       ptr->block_index = nir_channel(&b->nb, ssa, 0);
       ptr->offset = nir_channel(&b->nb, ssa, 1);
    } else if (ptr->mode == vtn_variable_mode_workgroup ||
+              ptr->mode == vtn_variable_mode_cross_workgroup ||
               ptr->mode == vtn_variable_mode_push_constant) {
       /* This pointer type needs to have actual storage */
       vtn_assert(ptr_type->type);
@@ -1926,9 +1982,11 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
 
    case SpvOpAccessChain:
    case SpvOpPtrAccessChain:
-   case SpvOpInBoundsAccessChain: {
+   case SpvOpInBoundsAccessChain:
+   case SpvOpInBoundsPtrAccessChain: {
       struct vtn_access_chain *chain = vtn_access_chain_create(b, count - 4);
-      chain->ptr_as_array = (opcode == SpvOpPtrAccessChain);
+      chain->ptr_as_array = (opcode == SpvOpPtrAccessChain) ||
+                            (opcode == SpvOpInBoundsPtrAccessChain);
 
       unsigned idx = 0;
       for (int i = 4; i < count; i++) {
-- 
2.19.1



More information about the mesa-dev mailing list