[Mesa-dev] [PATCH 17/18] nir/spirv: Use real pointer types

Jason Ekstrand jason at jlekstrand.net
Thu Jun 29 17:33:39 UTC 2017


---
 src/compiler/spirv/spirv_to_nir.c  | 23 +++++++++++++++++------
 src/compiler/spirv/vtn_cfg.c       | 12 ++++++++++--
 src/compiler/spirv/vtn_private.h   | 18 ++++++++++++++++++
 src/compiler/spirv/vtn_variables.c | 13 ++++++++++---
 4 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index cc3ba0d..462b049 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -421,6 +421,7 @@ vtn_type_copy(struct vtn_builder *b, struct vtn_type *src)
    case vtn_base_type_vector:
    case vtn_base_type_matrix:
    case vtn_base_type_array:
+   case vtn_base_type_pointer:
    case vtn_base_type_image:
    case vtn_base_type_sampler:
       /* Nothing more to do */
@@ -858,13 +859,17 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
       break;
    }
 
-   case SpvOpTypePointer:
-      /* FIXME:  For now, we'll just do the really lame thing and return
-       * the same type.  The validator should ensure that the proper number
-       * of dereferences happen
-       */
-      val->type = vtn_value(b, w[3], vtn_value_type_type)->type;
+   case SpvOpTypePointer: {
+      SpvStorageClass storage_class = w[2];
+      struct vtn_type *deref_type =
+         vtn_value(b, w[3], vtn_value_type_type)->type;
+
+      val->type->base_type = vtn_base_type_pointer;
+      val->type->type = NULL;
+      val->type->storage_class = storage_class;
+      val->type->deref = deref_type;
       break;
+   }
 
    case SpvOpTypeImage: {
       val->type->base_type = vtn_base_type_image;
@@ -956,6 +961,12 @@ vtn_null_constant(struct vtn_builder *b, const struct glsl_type *type)
 {
    nir_constant *c = rzalloc(b, nir_constant);
 
+   /* For pointers and other typeless things, we have to return something but
+    * it doesn't matter what.
+    */
+   if (!type)
+      return c;
+
    switch (glsl_get_base_type(type)) {
    case GLSL_TYPE_INT:
    case GLSL_TYPE_UINT:
diff --git a/src/compiler/spirv/vtn_cfg.c b/src/compiler/spirv/vtn_cfg.c
index dc429e6..83e77e2 100644
--- a/src/compiler/spirv/vtn_cfg.c
+++ b/src/compiler/spirv/vtn_cfg.c
@@ -52,7 +52,11 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
       func->num_params = func_type->length;
       func->params = ralloc_array(b->shader, nir_parameter, func->num_params);
       for (unsigned i = 0; i < func->num_params; i++) {
-         func->params[i].type = func_type->params[i]->type;
+         if (func_type->params[i]->base_type == vtn_base_type_pointer) {
+            func->params[i].type = func_type->params[i]->deref->type;
+         } else {
+            func->params[i].type = func_type->params[i]->type;
+         }
 
          /* TODO: We could do something smarter here. */
          func->params[i].param_type = nir_parameter_inout;
@@ -73,11 +77,15 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
 
    case SpvOpFunctionParameter: {
       struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type;
+      if (type->base_type == vtn_base_type_pointer) {
+         type = type->deref;
+         assert(type->base_type != vtn_base_type_pointer);
+      }
 
       assert(b->func_param_idx < b->func->impl->num_params);
       nir_variable *param = b->func->impl->params[b->func_param_idx++];
 
-      assert(param->type == type->type);
+      assert(type->type == param->type);
 
       struct vtn_variable *vtn_var = rzalloc(b, struct vtn_variable);
       vtn_var->type = type;
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 4972b55..446d9fa 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -203,6 +203,7 @@ enum vtn_base_type {
    vtn_base_type_matrix,
    vtn_base_type_array,
    vtn_base_type_struct,
+   vtn_base_type_pointer,
    vtn_base_type_image,
    vtn_base_type_sampler,
    vtn_base_type_function,
@@ -260,6 +261,15 @@ struct vtn_type {
          bool builtin_block:1;
       };
 
+      /* Members for pointer types */
+      struct {
+         /* For pointers, the vtn_type for dereferenced type */
+         struct vtn_type *deref;
+
+         /* Storage class for pointers */
+         SpvStorageClass storage_class;
+      };
+
       /* Members for image types */
       struct {
          /* For images, indicates whether it's sampled or storage */
@@ -327,6 +337,14 @@ struct vtn_pointer {
    /** The dereferenced type of this pointer */
    struct vtn_type *type;
 
+   /** The pointer type of this pointer
+    *
+    * This may be NULL for some temporary pointers constructed as part of a
+    * large load, store, or copy.  It MUST be valid for all pointers which are
+    * stored as SPIR-V SSA values.
+    */
+   struct vtn_type *ptr_type;
+
    /** The referenced variable, if known
     *
     * This field may be NULL if the pointer uses a (block_index, offset) pair
diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c
index d26863b..12504f4 100644
--- a/src/compiler/spirv/vtn_variables.c
+++ b/src/compiler/spirv/vtn_variables.c
@@ -1457,9 +1457,13 @@ is_per_vertex_inout(const struct vtn_variable *var, gl_shader_stage stage)
 
 static void
 vtn_create_variable(struct vtn_builder *b, struct vtn_value *val,
-                    struct vtn_type *type, SpvStorageClass storage_class,
+                    struct vtn_type *ptr_type, SpvStorageClass storage_class,
                     nir_constant *initializer)
 {
+   assert(ptr_type->base_type == vtn_base_type_pointer);
+   struct vtn_type *type = ptr_type->deref;
+   assert(type->base_type != vtn_base_type_pointer);
+
    struct vtn_type *without_array = type;
    while(glsl_type_is_array(without_array->type))
       without_array = without_array->array_element;
@@ -1492,6 +1496,7 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val,
    assert(val->value_type == vtn_value_type_pointer);
    val->pointer = rzalloc(b, struct vtn_pointer);
    val->pointer->type = type;
+   val->pointer->ptr_type = ptr_type;
    val->pointer->mode = mode;
 
    struct vtn_variable *var = rzalloc(b, struct vtn_variable);
@@ -1664,7 +1669,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
    }
 
    case SpvOpVariable: {
-      struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type;
+      struct vtn_type *ptr_type = vtn_value(b, w[1], vtn_value_type_type)->type;
 
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer);
 
@@ -1673,7 +1678,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       if (count > 4)
          initializer = vtn_value(b, w[4], vtn_value_type_constant)->constant;
 
-      vtn_create_variable(b, val, type, storage_class, initializer);
+      vtn_create_variable(b, val, ptr_type, storage_class, initializer);
       break;
    }
 
@@ -1695,6 +1700,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          idx++;
       }
 
+      struct vtn_type *ptr_type = vtn_value(b, w[1], vtn_value_type_type)->type;
       struct vtn_value *base_val = vtn_untyped_value(b, w[3]);
       if (base_val->value_type == vtn_value_type_sampled_image) {
          /* This is rather insane.  SPIR-V allows you to use OpSampledImage
@@ -1715,6 +1721,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          struct vtn_value *val =
             vtn_push_value(b, w[2], vtn_value_type_pointer);
          val->pointer = vtn_pointer_dereference(b, base_val->pointer, chain);
+         val->pointer->ptr_type = ptr_type;
       }
       break;
    }
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list