nir/spirv: fix some bugs
[mesa.git] / src / glsl / nir / spirv_to_nir.c
index 41182a7003eadcaeae3cb85374716d1a6317b281..ec26111930a73865354a22693036a2076d7e914f 100644 (file)
@@ -184,17 +184,20 @@ _foreach_decoration_helper(struct vtn_builder *b,
                            struct vtn_value *value,
                            vtn_decoration_foreach_cb cb, void *data)
 {
+   int new_member = member;
+
    for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) {
       if (dec->member >= 0) {
          assert(member == -1);
-         member = dec->member;
+         new_member = dec->member;
       }
 
       if (dec->group) {
          assert(dec->group->value_type == vtn_value_type_decoration_group);
-         _foreach_decoration_helper(b, base_value, member, dec->group, cb, data);
+         _foreach_decoration_helper(b, base_value, new_member, dec->group,
+                                    cb, data);
       } else {
-         cb(b, base_value, member, dec, data);
+         cb(b, base_value, new_member, dec, data);
       }
    }
 }
@@ -268,12 +271,64 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
    }
 }
 
+struct member_decoration_ctx {
+   struct glsl_struct_field *fields;
+   struct vtn_type *type;
+};
+
+/* does a shallow copy of a vtn_type */
+
+static struct vtn_type *
+vtn_type_copy(struct vtn_builder *b, struct vtn_type *src)
+{
+   struct vtn_type *dest = ralloc(b, struct vtn_type);
+   dest->type = src->type;
+   dest->is_builtin = src->is_builtin;
+   if (src->is_builtin)
+      dest->builtin = src->builtin;
+
+   if (!glsl_type_is_vector_or_scalar(src->type)) {
+      switch (glsl_get_base_type(src->type)) {
+      case GLSL_TYPE_ARRAY:
+         dest->array_element = src->array_element;
+         dest->stride = src->stride;
+         break;
+
+      case GLSL_TYPE_INT:
+      case GLSL_TYPE_UINT:
+      case GLSL_TYPE_BOOL:
+      case GLSL_TYPE_FLOAT:
+      case GLSL_TYPE_DOUBLE:
+         /* matrices */
+         dest->row_major = src->row_major;
+         dest->stride = src->stride;
+         break;
+
+      case GLSL_TYPE_STRUCT: {
+         unsigned elems = glsl_get_length(src->type);
+
+         dest->members = ralloc_array(b, struct vtn_type *, elems);
+         memcpy(dest->members, src->members, elems * sizeof(struct vtn_type *));
+
+         dest->offsets = ralloc_array(b, unsigned, elems);
+         memcpy(dest->offsets, src->offsets, elems * sizeof(unsigned));
+         break;
+      }
+
+      default:
+         unreachable("unhandled type");
+      }
+   }
+
+   return dest;
+}
+
 static void
 struct_member_decoration_cb(struct vtn_builder *b,
                             struct vtn_value *val, int member,
-                            const struct vtn_decoration *dec, void *void_fields)
+                            const struct vtn_decoration *dec, void *void_ctx)
 {
-   struct glsl_struct_field *fields = void_fields;
+   struct member_decoration_ctx *ctx = void_ctx;
 
    if (member < 0)
       return;
@@ -284,22 +339,28 @@ struct_member_decoration_cb(struct vtn_builder *b,
    case SpvDecorationPrecisionHigh:
       break; /* FIXME: Do nothing with these for now. */
    case SpvDecorationSmooth:
-      fields[member].interpolation = INTERP_QUALIFIER_SMOOTH;
+      ctx->fields[member].interpolation = INTERP_QUALIFIER_SMOOTH;
       break;
    case SpvDecorationNoperspective:
-      fields[member].interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
+      ctx->fields[member].interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
       break;
    case SpvDecorationFlat:
-      fields[member].interpolation = INTERP_QUALIFIER_FLAT;
+      ctx->fields[member].interpolation = INTERP_QUALIFIER_FLAT;
       break;
    case SpvDecorationCentroid:
-      fields[member].centroid = true;
+      ctx->fields[member].centroid = true;
       break;
    case SpvDecorationSample:
-      fields[member].sample = true;
+      ctx->fields[member].sample = true;
       break;
    case SpvDecorationLocation:
-      fields[member].location = dec->literals[0];
+      ctx->fields[member].location = dec->literals[0];
+      break;
+   case SpvDecorationBuiltIn:
+      ctx->type->members[member] = vtn_type_copy(b,
+                                                 ctx->type->members[member]);
+      ctx->type->members[member]->is_builtin = true;
+      ctx->type->members[member]->builtin = dec->literals[0];
       break;
    default:
       unreachable("Unhandled member decoration");
@@ -340,14 +401,15 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
    }
 
    case SpvOpTypeMatrix: {
-      const struct glsl_type *base =
-         vtn_value(b, w[2], vtn_value_type_type)->type->type;
+      struct vtn_type *base =
+         vtn_value(b, w[2], vtn_value_type_type)->type;
       unsigned columns = w[3];
 
-      assert(glsl_type_is_vector(base));
-      val->type->type = glsl_matrix_type(glsl_get_base_type(base),
-                                         glsl_get_vector_elements(base),
+      assert(glsl_type_is_vector(base->type));
+      val->type->type = glsl_matrix_type(glsl_get_base_type(base->type),
+                                         glsl_get_vector_elements(base->type),
                                          columns);
+      val->type->array_element = base;
       val->type->row_major = false;
       val->type->stride = 0;
       return;
@@ -381,11 +443,16 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
          fields[i].stream = -1;
       }
 
-      vtn_foreach_decoration(b, val, struct_member_decoration_cb, fields);
+      struct member_decoration_ctx ctx = {
+         .fields = fields,
+         .type = val->type
+      };
+
+      vtn_foreach_decoration(b, val, struct_member_decoration_cb, &ctx);
 
       const char *name = val->name ? val->name : "struct";
 
-      val->type->type = glsl_struct_type(fields, count, name);
+      val->type->type = glsl_struct_type(fields, num_fields, name);
       return;
    }
 
@@ -518,6 +585,104 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
    }
 }
 
+static void
+vtn_get_builtin_location(SpvBuiltIn builtin, int *location,
+                         nir_variable_mode *mode)
+{
+   switch (builtin) {
+   case SpvBuiltInPosition:
+      *location = VARYING_SLOT_POS;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInPointSize:
+      *location = VARYING_SLOT_PSIZ;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInClipVertex:
+      *location = VARYING_SLOT_CLIP_VERTEX;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInClipDistance:
+      *location = VARYING_SLOT_CLIP_DIST0; /* XXX CLIP_DIST1? */
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInCullDistance:
+      /* XXX figure this out */
+      unreachable("unhandled builtin");
+   case SpvBuiltInVertexId:
+      *location = SYSTEM_VALUE_VERTEX_ID;
+      *mode = nir_var_system_value;
+      break;
+   case SpvBuiltInInstanceId:
+      *location = SYSTEM_VALUE_INSTANCE_ID;
+      *mode = nir_var_system_value;
+      break;
+   case SpvBuiltInPrimitiveId:
+      *location = VARYING_SLOT_PRIMITIVE_ID;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInInvocationId:
+      *location = SYSTEM_VALUE_INVOCATION_ID;
+      *mode = nir_var_system_value;
+      break;
+   case SpvBuiltInLayer:
+      *location = VARYING_SLOT_LAYER;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInTessLevelOuter:
+   case SpvBuiltInTessLevelInner:
+   case SpvBuiltInTessCoord:
+   case SpvBuiltInPatchVertices:
+      unreachable("no tessellation support");
+   case SpvBuiltInFragCoord:
+      *location = VARYING_SLOT_POS;
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInPointCoord:
+      *location = VARYING_SLOT_PNTC;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInFrontFacing:
+      *location = VARYING_SLOT_FACE;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInSampleId:
+      *location = SYSTEM_VALUE_SAMPLE_ID;
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInSamplePosition:
+      *location = SYSTEM_VALUE_SAMPLE_POS;
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInSampleMask:
+      *location = SYSTEM_VALUE_SAMPLE_MASK_IN; /* XXX out? */
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInFragColor:
+      *location = FRAG_RESULT_COLOR;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInFragDepth:
+      *location = FRAG_RESULT_DEPTH;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInHelperInvocation:
+      unreachable("unsupported builtin"); /* XXX */
+      break;
+   case SpvBuiltInNumWorkgroups:
+   case SpvBuiltInWorkgroupSize:
+      /* these are constants, need to be handled specially */
+      unreachable("unsupported builtin");
+   case SpvBuiltInWorkgroupId:
+   case SpvBuiltInLocalInvocationId:
+   case SpvBuiltInGlobalInvocationId:
+   case SpvBuiltInLocalInvocationIndex:
+      unreachable("no compute shader support");
+   default:
+      unreachable("unsupported builtin");
+   }
+}
+
 static void
 var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
                   const struct vtn_decoration *dec, void *void_var)
@@ -575,69 +740,16 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
    case SpvDecorationDescriptorSet:
       var->data.descriptor_set = dec->literals[0];
       break;
-   case SpvDecorationBuiltIn:
-      var->data.mode = nir_var_system_value;
-      var->data.read_only = true;
-      switch ((SpvBuiltIn)dec->literals[0]) {
-      case SpvBuiltInFrontFacing:
-         var->data.location = SYSTEM_VALUE_FRONT_FACE;
-         break;
-      case SpvBuiltInVertexId:
-         var->data.location = SYSTEM_VALUE_VERTEX_ID;
-         break;
-      case SpvBuiltInInstanceId:
-         var->data.location = SYSTEM_VALUE_INSTANCE_ID;
-         break;
-      case SpvBuiltInSampleId:
-         var->data.location = SYSTEM_VALUE_SAMPLE_ID;
-         break;
-      case SpvBuiltInSamplePosition:
-         var->data.location = SYSTEM_VALUE_SAMPLE_POS;
-         break;
-      case SpvBuiltInSampleMask:
-         var->data.location = SYSTEM_VALUE_SAMPLE_MASK_IN;
-         break;
-      case SpvBuiltInInvocationId:
-         var->data.location = SYSTEM_VALUE_INVOCATION_ID;
-         break;
-      case SpvBuiltInPrimitiveId:
-      case SpvBuiltInPosition:
-      case SpvBuiltInPointSize:
-      case SpvBuiltInClipVertex:
-      case SpvBuiltInClipDistance:
-      case SpvBuiltInCullDistance:
-      case SpvBuiltInLayer:
-      case SpvBuiltInViewportIndex:
-      case SpvBuiltInTessLevelOuter:
-      case SpvBuiltInTessLevelInner:
-      case SpvBuiltInTessCoord:
-      case SpvBuiltInPatchVertices:
-      case SpvBuiltInFragCoord:
-      case SpvBuiltInPointCoord:
-      case SpvBuiltInFragColor:
-      case SpvBuiltInFragDepth:
-      case SpvBuiltInHelperInvocation:
-      case SpvBuiltInNumWorkgroups:
-      case SpvBuiltInWorkgroupSize:
-      case SpvBuiltInWorkgroupId:
-      case SpvBuiltInLocalInvocationId:
-      case SpvBuiltInGlobalInvocationId:
-      case SpvBuiltInLocalInvocationIndex:
-      case SpvBuiltInWorkDim:
-      case SpvBuiltInGlobalSize:
-      case SpvBuiltInEnqueuedWorkgroupSize:
-      case SpvBuiltInGlobalOffset:
-      case SpvBuiltInGlobalLinearId:
-      case SpvBuiltInWorkgroupLinearId:
-      case SpvBuiltInSubgroupSize:
-      case SpvBuiltInSubgroupMaxSize:
-      case SpvBuiltInNumSubgroups:
-      case SpvBuiltInNumEnqueuedSubgroups:
-      case SpvBuiltInSubgroupId:
-      case SpvBuiltInSubgroupLocalInvocationId:
-         unreachable("Unhandled builtin enum");
-      }
+   case SpvDecorationBuiltIn: {
+      nir_variable_mode mode;
+      vtn_get_builtin_location(dec->literals[0], &var->data.location,
+                               &mode);
+      var->data.mode = mode;
+      if (mode == nir_var_shader_in || mode == nir_var_system_value)
+         var->data.read_only = true;
+      b->builtins[dec->literals[0]] = var;
       break;
+   }
    case SpvDecorationNoStaticUse:
       /* This can safely be ignored */
       break;
@@ -675,13 +787,93 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
    }
 }
 
+static nir_variable *
+get_builtin_variable(struct vtn_builder *b,
+                     const struct glsl_type *type,
+                     SpvBuiltIn builtin)
+{
+   nir_variable *var = b->builtins[builtin];
+
+   if (!var) {
+      var = ralloc(b->shader, nir_variable);
+      var->type = type;
+      
+      nir_variable_mode mode;
+      vtn_get_builtin_location(builtin, &var->data.location, &mode);
+      var->data.mode = mode;
+      var->name = ralloc_strdup(b->shader, "builtin");
+
+      switch (mode) {
+      case nir_var_shader_in:
+         exec_list_push_tail(&b->shader->inputs, &var->node);
+         break;
+      case nir_var_shader_out:
+         exec_list_push_tail(&b->shader->outputs, &var->node);
+         break;
+      case nir_var_system_value:
+         exec_list_push_tail(&b->shader->system_values, &var->node);
+         break;
+      default:
+         unreachable("bad builtin mode");
+      }
+
+      b->builtins[builtin] = var;
+   }
+
+   return var;
+}
+
+static void
+vtn_builtin_load(struct vtn_builder *b,
+                 struct vtn_ssa_value *val,
+                 SpvBuiltIn builtin)
+{
+   assert(glsl_type_is_vector_or_scalar(val->type));
+
+   nir_variable *var = get_builtin_variable(b, val->type, builtin);
+
+   nir_intrinsic_instr *load =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
+   nir_ssa_dest_init(&load->instr, &load->dest,
+                     glsl_get_vector_elements(val->type), NULL);
+
+   load->variables[0] = nir_deref_var_create(load, var);
+   load->num_components = glsl_get_vector_elements(val->type);
+   nir_builder_instr_insert(&b->nb, &load->instr);
+   val->def = &load->dest.ssa;
+}
+
+static void
+vtn_builtin_store(struct vtn_builder *b,
+                  struct vtn_ssa_value *val,
+                  SpvBuiltIn builtin)
+{
+   assert(glsl_type_is_vector_or_scalar(val->type));
+
+   nir_variable *var = get_builtin_variable(b, val->type, builtin);
+
+   nir_intrinsic_instr *store =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
+
+   store->variables[0] = nir_deref_var_create(store, var);
+   store->num_components = glsl_get_vector_elements(val->type);
+   store->src[0] = nir_src_for_ssa(val->def);
+   nir_builder_instr_insert(&b->nb, &store->instr);
+}
+
 static struct vtn_ssa_value *
 _vtn_variable_load(struct vtn_builder *b,
-                   nir_deref_var *src_deref, nir_deref *src_deref_tail)
+                   nir_deref_var *src_deref, struct vtn_type *src_type,
+                   nir_deref *src_deref_tail)
 {
    struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
    val->type = src_deref_tail->type;
 
+   if (src_type->is_builtin) {
+      vtn_builtin_load(b, val, src_type->builtin);
+      return val;
+   }
+
    /* The deref tail may contain a deref to select a component of a vector (in
     * other words, it might not be an actual tail) so we have to save it away
     * here since we overwrite it later.
@@ -718,7 +910,9 @@ _vtn_variable_load(struct vtn_builder *b,
       src_deref_tail->child = &deref->deref;
       for (unsigned i = 0; i < elems; i++) {
          deref->base_offset = i;
-         val->elems[i] = _vtn_variable_load(b, src_deref, &deref->deref);
+         val->elems[i] = _vtn_variable_load(b, src_deref,
+                                            src_type->array_element,
+                                            &deref->deref);
       }
    } else {
       assert(glsl_get_base_type(val->type) == GLSL_TYPE_STRUCT);
@@ -730,7 +924,9 @@ _vtn_variable_load(struct vtn_builder *b,
       for (unsigned i = 0; i < elems; i++) {
          deref->index = i;
          deref->deref.type = glsl_get_struct_field(val->type, i);
-         val->elems[i] = _vtn_variable_load(b, src_deref, &deref->deref);
+         val->elems[i] = _vtn_variable_load(b, src_deref,
+                                            src_type->members[i],
+                                            &deref->deref);
       }
    }
 
@@ -740,9 +936,15 @@ _vtn_variable_load(struct vtn_builder *b,
 }
 
 static void
-_vtn_variable_store(struct vtn_builder *b, nir_deref_var *dest_deref,
-                    nir_deref *dest_deref_tail, struct vtn_ssa_value *src)
+_vtn_variable_store(struct vtn_builder *b, struct vtn_type *dest_type,
+                    nir_deref_var *dest_deref, nir_deref *dest_deref_tail,
+                    struct vtn_ssa_value *src)
 {
+   if (dest_type->is_builtin) {
+      vtn_builtin_store(b, src, dest_type->builtin);
+      return;
+   }
+
    nir_deref *old_child = dest_deref_tail->child;
 
    if (glsl_type_is_vector_or_scalar(src->type)) {
@@ -750,6 +952,7 @@ _vtn_variable_store(struct vtn_builder *b, nir_deref_var *dest_deref,
          nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
       store->variables[0] =
          nir_deref_as_var(nir_copy_deref(store, &dest_deref->deref));
+      store->num_components = glsl_get_vector_elements(src->type);
       store->src[0] = nir_src_for_ssa(src->def);
 
       nir_builder_instr_insert(&b->nb, &store->instr);
@@ -763,7 +966,8 @@ _vtn_variable_store(struct vtn_builder *b, nir_deref_var *dest_deref,
       dest_deref_tail->child = &deref->deref;
       for (unsigned i = 0; i < elems; i++) {
          deref->base_offset = i;
-         _vtn_variable_store(b, dest_deref, &deref->deref, src->elems[i]);
+         _vtn_variable_store(b, dest_type->array_element, dest_deref,
+                             &deref->deref, src->elems[i]);
       }
    } else {
       assert(glsl_get_base_type(src->type) == GLSL_TYPE_STRUCT);
@@ -774,7 +978,8 @@ _vtn_variable_store(struct vtn_builder *b, nir_deref_var *dest_deref,
       for (unsigned i = 0; i < elems; i++) {
          deref->index = i;
          deref->deref.type = glsl_get_struct_field(src->type, i);
-         _vtn_variable_store(b, dest_deref, &deref->deref, src->elems[i]);
+         _vtn_variable_store(b, dest_type->members[i], dest_deref,
+                             &deref->deref, src->elems[i]);
       }
    }
 
@@ -805,10 +1010,11 @@ static nir_ssa_def *vtn_vector_extract_dynamic(struct vtn_builder *b,
                                                nir_ssa_def *index);
 
 static struct vtn_ssa_value *
-vtn_variable_load(struct vtn_builder *b, nir_deref_var *src)
+vtn_variable_load(struct vtn_builder *b, nir_deref_var *src,
+                  struct vtn_type *src_type)
 {
    nir_deref *src_tail = get_deref_tail(src);
-   struct vtn_ssa_value *val = _vtn_variable_load(b, src, src_tail);
+   struct vtn_ssa_value *val = _vtn_variable_load(b, src, src_type, src_tail);
 
    if (src_tail->child) {
       nir_deref_array *vec_deref = nir_deref_as_array(src_tail->child);
@@ -834,11 +1040,12 @@ static nir_ssa_def * vtn_vector_insert_dynamic(struct vtn_builder *b,
                                                nir_ssa_def *index);
 static void
 vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
-                   nir_deref_var *dest)
+                   nir_deref_var *dest, struct vtn_type *dest_type)
 {
    nir_deref *dest_tail = get_deref_tail(dest);
    if (dest_tail->child) {
-      struct vtn_ssa_value *val = _vtn_variable_load(b, dest, dest_tail);
+      struct vtn_ssa_value *val = _vtn_variable_load(b, dest, dest_type,
+                                                     dest_tail);
       nir_deref_array *deref = nir_deref_as_array(dest_tail->child);
       assert(deref->deref.child == NULL);
       if (deref->deref_array_type == nir_deref_array_type_direct)
@@ -847,22 +1054,22 @@ vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
       else
          val->def = vtn_vector_insert_dynamic(b, val->def, src->def,
                                               deref->indirect.ssa);
-      _vtn_variable_store(b, dest, dest_tail, val);
+      _vtn_variable_store(b, dest_type, dest, dest_tail, val);
    } else {
-      _vtn_variable_store(b, dest, dest_tail, src);
+      _vtn_variable_store(b, dest_type, dest, dest_tail, src);
    }
 }
 
 static void
 vtn_variable_copy(struct vtn_builder *b, nir_deref_var *src,
-                  nir_deref_var *dest)
+                  nir_deref_var *dest, struct vtn_type *type)
 {
    nir_deref *src_tail = get_deref_tail(src);
 
    if (src_tail->child) {
       assert(get_deref_tail(dest)->child);
-      struct vtn_ssa_value *val = vtn_variable_load(b, src);
-      vtn_variable_store(b, val, dest);
+      struct vtn_ssa_value *val = vtn_variable_load(b, src, type);
+      vtn_variable_store(b, val, dest, type);
    } else {
       nir_intrinsic_instr *copy =
          nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
@@ -879,13 +1086,13 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
 {
    switch (opcode) {
    case SpvOpVariable: {
-      const struct glsl_type *type =
-         vtn_value(b, w[1], vtn_value_type_type)->type->type;
+      struct vtn_type *type =
+         vtn_value(b, w[1], vtn_value_type_type)->type;
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref);
 
       nir_variable *var = ralloc(b->shader, nir_variable);
 
-      var->type = type;
+      var->type = type->type;
       var->name = ralloc_strdup(var, val->name);
 
       switch ((SpvStorageClass)w[3]) {
@@ -893,7 +1100,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       case SpvStorageClassUniformConstant:
          var->data.mode = nir_var_uniform;
          var->data.read_only = true;
-         var->interface_type = type;
+         var->interface_type = type->type;
          break;
       case SpvStorageClassInput:
          var->data.mode = nir_var_shader_in;
@@ -924,6 +1131,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       }
 
       val->deref = nir_deref_var_create(b, var);
+      val->deref_type = type;
 
       vtn_foreach_decoration(b, val, var_decoration_cb, var);
 
@@ -966,6 +1174,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref);
       nir_deref_var *base = vtn_value(b, w[3], vtn_value_type_deref)->deref;
       val->deref = nir_deref_as_var(nir_copy_deref(b, &base->deref));
+      val->deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 
       nir_deref *tail = &val->deref->deref;
       while (tail->child)
@@ -984,15 +1193,17 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          case GLSL_TYPE_BOOL:
          case GLSL_TYPE_ARRAY: {
             nir_deref_array *deref_arr = nir_deref_array_create(b);
-            if (base_type == GLSL_TYPE_ARRAY) {
-               deref_arr->deref.type = glsl_get_array_element(tail->type);
-            } else if (glsl_type_is_matrix(tail->type)) {
-               deref_arr->deref.type = glsl_get_column_type(tail->type);
+            if (base_type == GLSL_TYPE_ARRAY ||
+                glsl_type_is_matrix(tail->type)) {
+               val->deref_type = val->deref_type->array_element;
             } else {
                assert(glsl_type_is_vector(tail->type));
-               deref_arr->deref.type = glsl_scalar_type(base_type);
+               val->deref_type = ralloc(b, struct vtn_type);
+               val->deref_type->type = glsl_scalar_type(base_type);
             }
 
+            deref_arr->deref.type = val->deref_type->type;
+
             if (idx_val->value_type == vtn_value_type_constant) {
                unsigned idx = idx_val->constant->value.u[0];
                deref_arr->deref_array_type = nir_deref_array_type_direct;
@@ -1011,8 +1222,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          case GLSL_TYPE_STRUCT: {
             assert(idx_val->value_type == vtn_value_type_constant);
             unsigned idx = idx_val->constant->value.u[0];
+            val->deref_type = val->deref_type->members[idx];
             nir_deref_struct *deref_struct = nir_deref_struct_create(b, idx);
-            deref_struct->deref.type = glsl_get_struct_field(tail->type, idx);
+            deref_struct->deref.type = val->deref_type->type;
             tail->child = &deref_struct->deref;
             break;
          }
@@ -1027,29 +1239,34 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
    case SpvOpCopyMemory: {
       nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref;
       nir_deref_var *src = vtn_value(b, w[2], vtn_value_type_deref)->deref;
+      struct vtn_type *type =
+         vtn_value(b, w[1], vtn_value_type_deref)->deref_type;
 
-      vtn_variable_copy(b, src, dest);
+      vtn_variable_copy(b, src, dest, type);
       break;
    }
 
    case SpvOpLoad: {
       nir_deref_var *src = vtn_value(b, w[3], vtn_value_type_deref)->deref;
-      const struct glsl_type *src_type = nir_deref_tail(&src->deref)->type;
+      struct vtn_type *src_type =
+         vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 
-      if (glsl_get_base_type(src_type) == GLSL_TYPE_SAMPLER) {
+      if (glsl_get_base_type(src_type->type) == GLSL_TYPE_SAMPLER) {
          vtn_push_value(b, w[2], vtn_value_type_deref)->deref = src;
          return;
       }
 
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
-      val->ssa = vtn_variable_load(b, src);
+      val->ssa = vtn_variable_load(b, src, src_type);
       break;
    }
 
    case SpvOpStore: {
       nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref;
+      struct vtn_type *dest_type =
+         vtn_value(b, w[1], vtn_value_type_deref)->deref_type;
       struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]);
-      vtn_variable_store(b, src, dest);
+      vtn_variable_store(b, src, dest, dest_type);
       break;
    }
 
@@ -1244,6 +1461,7 @@ create_vec(void *mem_ctx, unsigned num_components)
 
    nir_alu_instr *vec = nir_alu_instr_create(mem_ctx, op);
    nir_ssa_dest_init(&vec->instr, &vec->dest.dest, num_components, NULL);
+   vec->dest.write_mask = (1 << num_components) - 1;
 
    return vec;
 }
@@ -1832,7 +2050,6 @@ vtn_handle_composite(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpCompositeConstruct: {
-      val->ssa = rzalloc(b, struct vtn_ssa_value);
       unsigned elems = count - 3;
       if (glsl_type_is_vector_or_scalar(type)) {
          nir_ssa_def *srcs[4];