Merge branch 'wip/nir-vtn' into vulkan
authorConnor Abbott <cwabbott0@gmail.com>
Fri, 26 Jun 2015 19:14:05 +0000 (12:14 -0700)
committerConnor Abbott <cwabbott0@gmail.com>
Fri, 26 Jun 2015 19:14:05 +0000 (12:14 -0700)
Adds composites and matrix multiplication, plus some control flow fixes.

1  2 
src/glsl/nir/spirv_to_nir.c

  #include "spirv_to_nir_private.h"
  #include "nir_vla.h"
  
- nir_ssa_def *
- vtn_ssa_value(struct vtn_builder *b, uint32_t value_id)
+ static struct vtn_ssa_value *
+ vtn_const_ssa_value(struct vtn_builder *b, nir_constant *constant,
+                     const struct glsl_type *type)
  {
-    struct vtn_value *val = vtn_untyped_value(b, value_id);
-    switch (val->value_type) {
-    case vtn_value_type_constant: {
-       assert(glsl_type_is_vector_or_scalar(val->type));
-       unsigned num_components = glsl_get_vector_elements(val->type);
-       nir_load_const_instr *load =
-          nir_load_const_instr_create(b->shader, num_components);
+    struct hash_entry *entry = _mesa_hash_table_search(b->const_table, constant);
+    if (entry)
+       return entry->data;
+    struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
+    val->type = type;
+    switch (glsl_get_base_type(type)) {
+    case GLSL_TYPE_INT:
+    case GLSL_TYPE_UINT:
+    case GLSL_TYPE_BOOL:
+    case GLSL_TYPE_FLOAT:
+    case GLSL_TYPE_DOUBLE:
+       if (glsl_type_is_vector_or_scalar(type)) {
+          unsigned num_components = glsl_get_vector_elements(val->type);
+          nir_load_const_instr *load =
+             nir_load_const_instr_create(b->shader, num_components);
+          for (unsigned i = 0; i < num_components; i++)
+             load->value.u[i] = constant->value.u[i];
+          nir_instr_insert_before_cf_list(&b->impl->body, &load->instr);
+          val->def = &load->def;
+       } else {
+          assert(glsl_type_is_matrix(type));
+          unsigned rows = glsl_get_vector_elements(val->type);
+          unsigned columns = glsl_get_matrix_columns(val->type);
+          val->elems = ralloc_array(b, struct vtn_ssa_value *, columns);
  
-       for (unsigned i = 0; i < num_components; i++)
-          load->value.u[0] = val->constant->value.u[0];
+          for (unsigned i = 0; i < columns; i++) {
+             struct vtn_ssa_value *col_val = rzalloc(b, struct vtn_ssa_value);
+             col_val->type = glsl_get_column_type(val->type);
+             nir_load_const_instr *load =
+                nir_load_const_instr_create(b->shader, rows);
  
-       nir_builder_instr_insert(&b->nb, &load->instr);
-       return &load->def;
+             for (unsigned j = 0; j < rows; j++)
+                load->value.u[j] = constant->value.u[rows * i + j];
+             nir_instr_insert_before_cf_list(&b->impl->body, &load->instr);
+             col_val->def = &load->def;
+             val->elems[i] = col_val;
+          }
+       }
+       break;
+    case GLSL_TYPE_ARRAY: {
+       unsigned elems = glsl_get_length(val->type);
+       val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+       const struct glsl_type *elem_type = glsl_get_array_element(val->type);
+       for (unsigned i = 0; i < elems; i++)
+          val->elems[i] = vtn_const_ssa_value(b, constant->elements[i],
+                                              elem_type);
+       break;
+    }
+    case GLSL_TYPE_STRUCT: {
+       unsigned elems = glsl_get_length(val->type);
+       val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+       for (unsigned i = 0; i < elems; i++) {
+          const struct glsl_type *elem_type =
+             glsl_get_struct_field(val->type, i);
+          val->elems[i] = vtn_const_ssa_value(b, constant->elements[i],
+                                              elem_type);
+       }
+       break;
     }
  
+    default:
+       unreachable("bad constant type");
+    }
+    return val;
+ }
+ struct vtn_ssa_value *
+ vtn_ssa_value(struct vtn_builder *b, uint32_t value_id)
+ {
+    struct vtn_value *val = vtn_untyped_value(b, value_id);
+    switch (val->value_type) {
+    case vtn_value_type_constant:
+       return vtn_const_ssa_value(b, val->constant, val->type);
     case vtn_value_type_ssa:
        return val->ssa;
     default:
@@@ -415,75 -485,6 +485,75 @@@ var_decoration_cb(struct vtn_builder *b
        var->data.explicit_binding = true;
        var->data.binding = dec->literals[0];
        break;
 +   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");
 +      }
 +      break;
 +   case SpvDecorationNoStaticUse:
 +      /* This can safely be ignored */
 +      break;
     case SpvDecorationBlock:
     case SpvDecorationBufferBlock:
     case SpvDecorationRowMajor:
     case SpvDecorationNonreadable:
     case SpvDecorationUniform:
        /* This is really nice but we have no use for it right now. */
 -   case SpvDecorationNoStaticUse:
     case SpvDecorationCPacked:
     case SpvDecorationSaturatedConversion:
     case SpvDecorationStream:
 -   case SpvDecorationDescriptorSet:
     case SpvDecorationOffset:
     case SpvDecorationAlignment:
     case SpvDecorationXfbBuffer:
     case SpvDecorationStride:
 -   case SpvDecorationBuiltIn:
     case SpvDecorationFuncParamAttr:
     case SpvDecorationFPRoundingMode:
     case SpvDecorationFPFastMathMode:
     case SpvDecorationLinkageAttributes:
     case SpvDecorationSpecId:
+       break;
     default:
        unreachable("Unhandled variable decoration");
     }
  }
  
+ static struct vtn_ssa_value *
+ _vtn_variable_load(struct vtn_builder *b,
+                    nir_deref_var *src_deref, nir_deref *src_deref_tail)
+ {
+    struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
+    val->type = src_deref_tail->type;
+    /* 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.
+     */
+    nir_deref *old_child = src_deref_tail->child;
+    if (glsl_type_is_vector_or_scalar(val->type)) {
+       nir_intrinsic_instr *load =
+          nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
+       load->variables[0] =
+          nir_deref_as_var(nir_copy_deref(load, &src_deref->deref));
+       load->num_components = glsl_get_vector_elements(val->type);
+       nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, NULL);
+       nir_builder_instr_insert(&b->nb, &load->instr);
+       if (src_deref->var->data.mode == nir_var_uniform &&
+           glsl_get_base_type(val->type) == GLSL_TYPE_BOOL) {
+          /* Uniform boolean loads need to be fixed up since they're defined
+           * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE.
+           */
+          val->def = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0));
+       } else {
+          val->def = &load->dest.ssa;
+       }
+    } else if (glsl_get_base_type(val->type) == GLSL_TYPE_ARRAY ||
+               glsl_type_is_matrix(val->type)) {
+       unsigned elems = glsl_get_length(val->type);
+       val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+       nir_deref_array *deref = nir_deref_array_create(b);
+       deref->deref_array_type = nir_deref_array_type_direct;
+       deref->deref.type = glsl_get_array_element(val->type);
+       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);
+       }
+    } else {
+       assert(glsl_get_base_type(val->type) == GLSL_TYPE_STRUCT);
+       unsigned elems = glsl_get_length(val->type);
+       val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+       nir_deref_struct *deref = nir_deref_struct_create(b, 0);
+       src_deref_tail->child = &deref->deref;
+       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);
+       }
+    }
+    src_deref_tail->child = old_child;
+    return val;
+ }
+ static void
+ _vtn_variable_store(struct vtn_builder *b, nir_deref_var *dest_deref,
+                     nir_deref *dest_deref_tail, struct vtn_ssa_value *src)
+ {
+    nir_deref *old_child = dest_deref_tail->child;
+    if (glsl_type_is_vector_or_scalar(src->type)) {
+       nir_intrinsic_instr *store =
+          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->src[0] = nir_src_for_ssa(src->def);
+       nir_builder_instr_insert(&b->nb, &store->instr);
+    } else if (glsl_get_base_type(src->type) == GLSL_TYPE_ARRAY ||
+               glsl_type_is_matrix(src->type)) {
+       unsigned elems = glsl_get_length(src->type);
+       nir_deref_array *deref = nir_deref_array_create(b);
+       deref->deref_array_type = nir_deref_array_type_direct;
+       deref->deref.type = glsl_get_array_element(src->type);
+       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]);
+       }
+    } else {
+       assert(glsl_get_base_type(src->type) == GLSL_TYPE_STRUCT);
+       unsigned elems = glsl_get_length(src->type);
+       nir_deref_struct *deref = nir_deref_struct_create(b, 0);
+       dest_deref_tail->child = &deref->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]);
+       }
+    }
+    dest_deref_tail->child = old_child;
+ }
+ /*
+  * Gets the NIR-level deref tail, which may have as a child an array deref
+  * selecting which component due to OpAccessChain supporting per-component
+  * indexing in SPIR-V.
+  */
+ static nir_deref *
+ get_deref_tail(nir_deref_var *deref)
+ {
+    nir_deref *cur = &deref->deref;
+    while (!glsl_type_is_vector_or_scalar(cur->type) && cur->child)
+       cur = cur->child;
+    return cur;
+ }
+ static nir_ssa_def *vtn_vector_extract(struct vtn_builder *b,
+                                        nir_ssa_def *src, unsigned index);
+ static nir_ssa_def *vtn_vector_extract_dynamic(struct vtn_builder *b,
+                                                nir_ssa_def *src,
+                                                nir_ssa_def *index);
+ static struct vtn_ssa_value *
+ vtn_variable_load(struct vtn_builder *b, nir_deref_var *src)
+ {
+    nir_deref *src_tail = get_deref_tail(src);
+    struct vtn_ssa_value *val = _vtn_variable_load(b, src, src_tail);
+    if (src_tail->child) {
+       nir_deref_array *vec_deref = nir_deref_as_array(src_tail->child);
+       assert(vec_deref->deref.child == NULL);
+       val->type = vec_deref->deref.type;
+       if (vec_deref->deref_array_type == nir_deref_array_type_direct)
+          val->def = vtn_vector_extract(b, val->def, vec_deref->base_offset);
+       else
+          val->def = vtn_vector_extract_dynamic(b, val->def,
+                                                vec_deref->indirect.ssa);
+    }
+    return val;
+ }
+ static nir_ssa_def * vtn_vector_insert(struct vtn_builder *b,
+                                        nir_ssa_def *src, nir_ssa_def *insert,
+                                        unsigned index);
+ static nir_ssa_def * vtn_vector_insert_dynamic(struct vtn_builder *b,
+                                                nir_ssa_def *src,
+                                                nir_ssa_def *insert,
+                                                nir_ssa_def *index);
+ static void
+ vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
+                    nir_deref_var *dest)
+ {
+    nir_deref *dest_tail = get_deref_tail(dest);
+    if (dest_tail->child) {
+       struct vtn_ssa_value *val = _vtn_variable_load(b, dest, 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)
+          val->def = vtn_vector_insert(b, val->def, src->def,
+                                       deref->base_offset);
+       else
+          val->def = vtn_vector_insert_dynamic(b, val->def, src->def,
+                                               deref->indirect.ssa);
+       _vtn_variable_store(b, dest, dest_tail, val);
+    } else {
+       _vtn_variable_store(b, dest, dest_tail, src);
+    }
+ }
+ static void
+ vtn_variable_copy(struct vtn_builder *b, nir_deref_var *src,
+                   nir_deref_var *dest)
+ {
+    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);
+    } else {
+       nir_intrinsic_instr *copy =
+          nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
+       copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref));
+       copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref));
+       nir_builder_instr_insert(&b->nb, &copy->instr);
+    }
+ }
  static void
  vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
                       const uint32_t *w, unsigned count)
        var->name = ralloc_strdup(var, val->name);
  
        switch ((SpvStorageClass)w[3]) {
 +      case SpvStorageClassUniform:
        case SpvStorageClassUniformConstant:
           var->data.mode = nir_var_uniform;
           var->data.read_only = true;
 +         var->interface_type = type;
           break;
        case SpvStorageClassInput:
           var->data.mode = nir_var_shader_in;
        case SpvStorageClassFunction:
           var->data.mode = nir_var_local;
           break;
 -      case SpvStorageClassUniform:
        case SpvStorageClassWorkgroupLocal:
        case SpvStorageClassWorkgroupGlobal:
        case SpvStorageClassGeneric:
              vtn_value(b, w[4], vtn_value_type_constant)->constant;
        }
  
 -      if (var->data.mode == nir_var_local) {
 -         exec_list_push_tail(&b->impl->locals, &var->node);
 -      } else {
 -         exec_list_push_tail(&b->shader->globals, &var->node);
 -      }
 -
 -      val->deref = nir_deref_var_create(b->shader, var);
 +      val->deref = nir_deref_var_create(b, var);
  
        vtn_foreach_decoration(b, val, var_decoration_cb, var);
 +
 +      if (b->execution_model == SpvExecutionModelFragment &&
 +          var->data.mode == nir_var_shader_out) {
 +         var->data.location += FRAG_RESULT_DATA0;
 +      } else if (b->execution_model == SpvExecutionModelVertex &&
 +                 var->data.mode == nir_var_shader_in) {
 +         var->data.location += VERT_ATTRIB_GENERIC0;
 +      } else if (var->data.mode == nir_var_shader_in ||
 +                 var->data.mode == nir_var_shader_out) {
 +         var->data.location += VARYING_SLOT_VAR0;
 +      }
 +
 +      switch (var->data.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_global:
 +         exec_list_push_tail(&b->shader->globals, &var->node);
 +         break;
 +      case nir_var_local:
 +         exec_list_push_tail(&b->impl->locals, &var->node);
 +         break;
 +      case nir_var_uniform:
 +         exec_list_push_tail(&b->shader->uniforms, &var->node);
 +         break;
 +      case nir_var_system_value:
 +         exec_list_push_tail(&b->shader->system_values, &var->node);
 +         break;
 +      }
        break;
     }
  
                 assert(idx_val->value_type == vtn_value_type_ssa);
                 deref_arr->deref_array_type = nir_deref_array_type_indirect;
                 deref_arr->base_offset = 0;
-                deref_arr->indirect = nir_src_for_ssa(vtn_ssa_value(b, w[1]));
+                deref_arr->indirect =
+                   nir_src_for_ssa(vtn_ssa_value(b, w[1])->def);
              }
              tail->child = &deref_arr->deref;
              break;
        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;
  
-       nir_intrinsic_instr *copy =
-          nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
-       copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref));
-       copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref));
-       nir_builder_instr_insert(&b->nb, &copy->instr);
+       vtn_variable_copy(b, src, dest);
        break;
     }
  
           return;
        }
  
-       assert(glsl_type_is_vector_or_scalar(src_type));
        struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
-       nir_intrinsic_instr *load =
-          nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
-       load->variables[0] = nir_deref_as_var(nir_copy_deref(load, &src->deref));
-       load->num_components = glsl_get_vector_elements(src_type);
-       nir_ssa_dest_init(&load->instr, &load->dest, load->num_components,
-                         val->name);
-       nir_builder_instr_insert(&b->nb, &load->instr);
-       val->type = src_type;
-       if (src->var->data.mode == nir_var_uniform &&
-           glsl_get_base_type(src_type) == GLSL_TYPE_BOOL) {
-          /* Uniform boolean loads need to be fixed up since they're defined
-           * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE.
-           */
-          val->ssa = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0));
-       } else {
-          val->ssa = &load->dest.ssa;
-       }
+       val->ssa = vtn_variable_load(b, src);
        break;
     }
  
     case SpvOpStore: {
        nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref;
-       const struct glsl_type *dest_type = nir_deref_tail(&dest->deref)->type;
-       struct vtn_value *src_val = vtn_untyped_value(b, w[2]);
-       if (src_val->value_type == vtn_value_type_ssa) {
-          assert(glsl_type_is_vector_or_scalar(dest_type));
-          nir_intrinsic_instr *store =
-             nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
-          store->src[0] = nir_src_for_ssa(src_val->ssa);
-          store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest->deref));
-          store->num_components = glsl_get_vector_elements(dest_type);
-          nir_builder_instr_insert(&b->nb, &store->instr);
-       } else {
-          assert(src_val->value_type == vtn_value_type_constant);
-          nir_variable *const_tmp = rzalloc(b->shader, nir_variable);
-          const_tmp->type = dest_type;
-          const_tmp->name = "const_temp";
-          const_tmp->data.mode = nir_var_local;
-          const_tmp->data.read_only = true;
-          exec_list_push_tail(&b->impl->locals, &const_tmp->node);
-          nir_intrinsic_instr *copy =
-             nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
-          copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref));
-          copy->variables[1] = nir_deref_var_create(copy, const_tmp);
-          nir_builder_instr_insert(&b->nb, &copy->instr);
-       }
+       struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]);
+       vtn_variable_store(b, src, dest);
        break;
     }
  
@@@ -767,7 -893,7 +986,7 @@@ static nir_tex_sr
  vtn_tex_src(struct vtn_builder *b, unsigned index, nir_tex_src_type type)
  {
     nir_tex_src src;
-    src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa);
+    src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa->def);
     src.src_type = type;
     return src;
  }
@@@ -804,13 -930,15 +1023,16 @@@ vtn_handle_texture(struct vtn_builder *
     case SpvOpTextureGather:
     case SpvOpTextureGatherOffset:
     case SpvOpTextureGatherOffsets:
-    case SpvOpTextureQueryLod:
+    case SpvOpTextureQueryLod: {
        /* All these types have the coordinate as their first real argument */
-       coord_components = glsl_get_vector_elements(b->values[w[4]].type);
-       p->src = nir_src_for_ssa(vtn_ssa_value(b, w[4]));
 -      struct vtn_value *coord = vtn_value(b, w[4], vtn_value_type_ssa);
++      struct vtn_ssa_value *coord = vtn_ssa_value(b, w[4]);
+       coord_components = glsl_get_vector_elements(coord->type);
 -      p->src = nir_src_for_ssa(coord->ssa->def);
++      p->src = nir_src_for_ssa(coord->def);
        p->src_type = nir_tex_src_coord;
        p++;
        break;
+    }
++
     default:
        break;
     }
     instr->is_array = glsl_sampler_type_is_array(sampler_type);
     instr->is_shadow = glsl_sampler_type_is_shadow(sampler_type);
  
 -   instr->sampler = sampler;
 +   instr->sampler = nir_deref_as_var(nir_copy_deref(instr, &sampler->deref));
  
     nir_ssa_dest_init(&instr->instr, &instr->dest, 4, NULL);
-    val->ssa = &instr->dest.ssa;
+    val->ssa->def = &instr->dest.ssa;
+    val->ssa->type = val->type;
  
     nir_builder_instr_insert(&b->nb, &instr->instr);
  }
  
+ static struct vtn_ssa_value *
+ vtn_create_ssa_value(struct vtn_builder *b, const struct glsl_type *type)
+ {
+    struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
+    val->type = type;
+    
+    if (!glsl_type_is_vector_or_scalar(type)) {
+       unsigned elems = glsl_get_length(type);
+       val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+       for (unsigned i = 0; i < elems; i++) {
+          const struct glsl_type *child_type;
+          switch (glsl_get_base_type(type)) {
+          case GLSL_TYPE_INT:
+          case GLSL_TYPE_UINT:
+          case GLSL_TYPE_BOOL:
+          case GLSL_TYPE_FLOAT:
+          case GLSL_TYPE_DOUBLE:
+             child_type = glsl_get_column_type(type);
+             break;
+          case GLSL_TYPE_ARRAY:
+             child_type = glsl_get_array_element(type);
+             break;
+          case GLSL_TYPE_STRUCT:
+             child_type = glsl_get_struct_field(type, i);
+             break;
+          default:
+             unreachable("unkown base type");
+          }
+          val->elems[i] = vtn_create_ssa_value(b, child_type);
+       }
+    }
+    return val;
+ }
+ static nir_alu_instr *
+ create_vec(void *mem_ctx, unsigned num_components)
+ {
+    nir_op op;
+    switch (num_components) {
+    case 1: op = nir_op_fmov; break;
+    case 2: op = nir_op_vec2; break;
+    case 3: op = nir_op_vec3; break;
+    case 4: op = nir_op_vec4; break;
+    default: unreachable("bad vector size");
+    }
+    nir_alu_instr *vec = nir_alu_instr_create(mem_ctx, op);
+    nir_ssa_dest_init(&vec->instr, &vec->dest.dest, num_components, NULL);
+    return vec;
+ }
+ static struct vtn_ssa_value *
+ vtn_transpose(struct vtn_builder *b, struct vtn_ssa_value *src)
+ {
+    if (src->transposed)
+       return src->transposed;
+    struct vtn_ssa_value *dest =
+       vtn_create_ssa_value(b, glsl_transposed_type(src->type));
+    for (unsigned i = 0; i < glsl_get_matrix_columns(dest->type); i++) {
+       nir_alu_instr *vec = create_vec(b, glsl_get_matrix_columns(src->type));
+       if (glsl_type_is_vector_or_scalar(src->type)) {
+           vec->src[0].src = nir_src_for_ssa(src->def);
+           vec->src[0].swizzle[0] = i;
+       } else {
+          for (unsigned j = 0; j < glsl_get_matrix_columns(src->type); j++) {
+             vec->src[j].src = nir_src_for_ssa(src->elems[j]->def);
+             vec->src[j].swizzle[0] = i;
+          }
+       }
+       nir_builder_instr_insert(&b->nb, &vec->instr);
+       dest->elems[i]->def = &vec->dest.dest.ssa;
+    }
+    dest->transposed = src;
+    return dest;
+ }
+ /*
+  * Normally, column vectors in SPIR-V correspond to a single NIR SSA
+  * definition. But for matrix multiplies, we want to do one routine for
+  * multiplying a matrix by a matrix and then pretend that vectors are matrices
+  * with one column. So we "wrap" these things, and unwrap the result before we
+  * send it off.
+  */
+ static struct vtn_ssa_value *
+ vtn_wrap_matrix(struct vtn_builder *b, struct vtn_ssa_value *val)
+ {
+    if (val == NULL)
+       return NULL;
+    if (glsl_type_is_matrix(val->type))
+       return val;
+    struct vtn_ssa_value *dest = rzalloc(b, struct vtn_ssa_value);
+    dest->type = val->type;
+    dest->elems = ralloc_array(b, struct vtn_ssa_value *, 1);
+    dest->elems[0] = val;
+    return dest;
+ }
+ static struct vtn_ssa_value *
+ vtn_unwrap_matrix(struct vtn_ssa_value *val)
+ {
+    if (glsl_type_is_matrix(val->type))
+          return val;
+    return val->elems[0];
+ }
+ static struct vtn_ssa_value *
+ vtn_matrix_multiply(struct vtn_builder *b,
+                     struct vtn_ssa_value *_src0, struct vtn_ssa_value *_src1)
+ {
+    struct vtn_ssa_value *src0 = vtn_wrap_matrix(b, _src0);
+    struct vtn_ssa_value *src1 = vtn_wrap_matrix(b, _src1);
+    struct vtn_ssa_value *src0_transpose = vtn_wrap_matrix(b, _src0->transposed);
+    struct vtn_ssa_value *src1_transpose = vtn_wrap_matrix(b, _src1->transposed);
+    unsigned src0_rows = glsl_get_vector_elements(src0->type);
+    unsigned src0_columns = glsl_get_matrix_columns(src0->type);
+    unsigned src1_columns = glsl_get_matrix_columns(src1->type);
+    struct vtn_ssa_value *dest =
+       vtn_create_ssa_value(b, glsl_matrix_type(glsl_get_base_type(src0->type),
+                                                src0_rows, src1_columns));
+    dest = vtn_wrap_matrix(b, dest);
+    bool transpose_result = false;
+    if (src0_transpose && src1_transpose) {
+       /* transpose(A) * transpose(B) = transpose(B * A) */
+       src1 = src0_transpose;
+       src0 = src1_transpose;
+       src0_transpose = NULL;
+       src1_transpose = NULL;
+       transpose_result = true;
+    }
+    if (src0_transpose && !src1_transpose &&
+        glsl_get_base_type(src0->type) == GLSL_TYPE_FLOAT) {
+       /* We already have the rows of src0 and the columns of src1 available,
+        * so we can just take the dot product of each row with each column to
+        * get the result.
+        */
+       for (unsigned i = 0; i < src1_columns; i++) {
+          nir_alu_instr *vec = create_vec(b, src0_rows);
+          for (unsigned j = 0; j < src0_rows; j++) {
+             vec->src[j].src =
+                nir_src_for_ssa(nir_fdot(&b->nb, src0_transpose->elems[j]->def,
+                                         src1->elems[i]->def));
+          }
+          nir_builder_instr_insert(&b->nb, &vec->instr);
+          dest->elems[i]->def = &vec->dest.dest.ssa;
+       }
+    } else {
+       /* We don't handle the case where src1 is transposed but not src0, since
+        * the general case only uses individual components of src1 so the
+        * optimizer should chew through the transpose we emitted for src1.
+        */
+       for (unsigned i = 0; i < src1_columns; i++) {
+          /* dest[i] = sum(src0[j] * src1[i][j] for all j) */
+          dest->elems[i]->def =
+             nir_fmul(&b->nb, src0->elems[0]->def,
+                      vtn_vector_extract(b, src1->elems[i]->def, 0));
+          for (unsigned j = 1; j < src0_columns; j++) {
+             dest->elems[i]->def =
+                nir_fadd(&b->nb, dest->elems[i]->def,
+                         nir_fmul(&b->nb, src0->elems[j]->def,
+                                  vtn_vector_extract(b,
+                                                     src1->elems[i]->def, j)));
+          }
+       }
+    }
+    
+    dest = vtn_unwrap_matrix(dest);
+    if (transpose_result)
+       dest = vtn_transpose(b, dest);
+    return dest;
+ }
+ static struct vtn_ssa_value *
+ vtn_mat_times_scalar(struct vtn_builder *b,
+                      struct vtn_ssa_value *mat,
+                      nir_ssa_def *scalar)
+ {
+    struct vtn_ssa_value *dest = vtn_create_ssa_value(b, mat->type);
+    for (unsigned i = 0; i < glsl_get_matrix_columns(mat->type); i++) {
+       if (glsl_get_base_type(mat->type) == GLSL_TYPE_FLOAT)
+          dest->elems[i]->def = nir_fmul(&b->nb, mat->elems[i]->def, scalar);
+       else
+          dest->elems[i]->def = nir_imul(&b->nb, mat->elems[i]->def, scalar);
+    }
+    return dest;
+ }
  static void
  vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode,
                        const uint32_t *w, unsigned count)
  {
-    unreachable("Matrix math not handled");
+    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+    val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+    switch (opcode) {
+    case SpvOpTranspose: {
+       struct vtn_ssa_value *src = vtn_ssa_value(b, w[3]);
+       val->ssa = vtn_transpose(b, src);
+       break;
+    }
+    case SpvOpOuterProduct: {
+       struct vtn_ssa_value *src0 = vtn_ssa_value(b, w[3]);
+       struct vtn_ssa_value *src1 = vtn_ssa_value(b, w[4]);
+       val->ssa = vtn_matrix_multiply(b, src0, vtn_transpose(b, src1));
+       break;
+    }
+    case SpvOpMatrixTimesScalar: {
+       struct vtn_ssa_value *mat = vtn_ssa_value(b, w[3]);
+       struct vtn_ssa_value *scalar = vtn_ssa_value(b, w[4]);
+       if (mat->transposed) {
+          val->ssa = vtn_transpose(b, vtn_mat_times_scalar(b, mat->transposed,
+                                                           scalar->def));
+       } else {
+          val->ssa = vtn_mat_times_scalar(b, mat, scalar->def);
+       }
+       break;
+    }
+    case SpvOpVectorTimesMatrix:
+    case SpvOpMatrixTimesVector:
+    case SpvOpMatrixTimesMatrix: {
+       struct vtn_ssa_value *src0 = vtn_ssa_value(b, w[3]);
+       struct vtn_ssa_value *src1 = vtn_ssa_value(b, w[4]);
+       val->ssa = vtn_matrix_multiply(b, src0, src1);
+       break;
+    }
+    default: unreachable("unknown matrix opcode");
+    }
  }
  
  static void
@@@ -895,12 -1277,13 +1371,13 @@@ vtn_handle_alu(struct vtn_builder *b, S
  {
     struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
     val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+    val->ssa = vtn_create_ssa_value(b, val->type);
  
     /* Collect the various SSA sources */
     unsigned num_inputs = count - 3;
     nir_ssa_def *src[4];
     for (unsigned i = 0; i < num_inputs; i++)
-       src[i] = vtn_ssa_value(b, w[i + 3]);
+       src[i] = vtn_ssa_value(b, w[i + 3])->def;
  
     /* Indicates that the first two arguments should be swapped.  This is
      * used for implementing greater-than and less-than-or-equal.
     case SpvOpDPdxCoarse:   op = nir_op_fddx_coarse;   break;
     case SpvOpDPdyCoarse:   op = nir_op_fddy_coarse;   break;
     case SpvOpFwidth:
-       val->ssa = nir_fadd(&b->nb,
-                           nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])),
-                           nir_fabs(&b->nb, nir_fddx(&b->nb, src[1])));
+       val->ssa->def = nir_fadd(&b->nb,
+                                nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])),
+                                nir_fabs(&b->nb, nir_fddx(&b->nb, src[1])));
        return;
     case SpvOpFwidthFine:
-       val->ssa = nir_fadd(&b->nb,
-                           nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])),
-                           nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1])));
+       val->ssa->def = nir_fadd(&b->nb,
+                                nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])),
+                                nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1])));
        return;
     case SpvOpFwidthCoarse:
-       val->ssa = nir_fadd(&b->nb,
-                           nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])),
-                           nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1])));
+       val->ssa->def = nir_fadd(&b->nb,
+                                nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])),
+                                nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1])));
        return;
  
     case SpvOpVectorTimesScalar:
        /* The builder will take care of splatting for us. */
-       val->ssa = nir_fmul(&b->nb, src[0], src[1]);
+       val->ssa->def = nir_fmul(&b->nb, src[0], src[1]);
        return;
  
     case SpvOpSRem:
     nir_alu_instr *instr = nir_alu_instr_create(b->shader, op);
     nir_ssa_dest_init(&instr->instr, &instr->dest.dest,
                       glsl_get_vector_elements(val->type), val->name);
-    val->ssa = &instr->dest.dest.ssa;
+    val->ssa->def = &instr->dest.dest.ssa;
  
     for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++)
        instr->src[i].src = nir_src_for_ssa(src[i]);
     nir_builder_instr_insert(&b->nb, &instr->instr);
  }
  
+ static nir_ssa_def *
+ vtn_vector_extract(struct vtn_builder *b, nir_ssa_def *src, unsigned index)
+ {
+    unsigned swiz[4] = { index };
+    return nir_swizzle(&b->nb, src, swiz, 1, true);
+ }
+ static nir_ssa_def *
+ vtn_vector_insert(struct vtn_builder *b, nir_ssa_def *src, nir_ssa_def *insert,
+                   unsigned index)
+ {
+    nir_alu_instr *vec = create_vec(b->shader, src->num_components);
+    for (unsigned i = 0; i < src->num_components; i++) {
+       if (i == index) {
+          vec->src[i].src = nir_src_for_ssa(insert);
+       } else {
+          vec->src[i].src = nir_src_for_ssa(src);
+          vec->src[i].swizzle[0] = i;
+       }
+    }
+    nir_builder_instr_insert(&b->nb, &vec->instr);
+    return &vec->dest.dest.ssa;
+ }
+ static nir_ssa_def *
+ vtn_vector_extract_dynamic(struct vtn_builder *b, nir_ssa_def *src,
+                            nir_ssa_def *index)
+ {
+    nir_ssa_def *dest = vtn_vector_extract(b, src, 0);
+    for (unsigned i = 1; i < src->num_components; i++)
+       dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)),
+                        vtn_vector_extract(b, src, i), dest);
+    return dest;
+ }
+ static nir_ssa_def *
+ vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src,
+                           nir_ssa_def *insert, nir_ssa_def *index)
+ {
+    nir_ssa_def *dest = vtn_vector_insert(b, src, insert, 0);
+    for (unsigned i = 1; i < src->num_components; i++)
+       dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)),
+                        vtn_vector_insert(b, src, insert, i), dest);
+    return dest;
+ }
+ static nir_ssa_def *
+ vtn_vector_shuffle(struct vtn_builder *b, unsigned num_components,
+                    nir_ssa_def *src0, nir_ssa_def *src1,
+                    const uint32_t *indices)
+ {
+    nir_alu_instr *vec = create_vec(b->shader, num_components);
+    nir_ssa_undef_instr *undef = nir_ssa_undef_instr_create(b->shader, 1);
+    nir_builder_instr_insert(&b->nb, &undef->instr);
+    for (unsigned i = 0; i < num_components; i++) {
+       uint32_t index = indices[i];
+       if (index == 0xffffffff) {
+          vec->src[i].src = nir_src_for_ssa(&undef->def);
+       } else if (index < src0->num_components) {
+          vec->src[i].src = nir_src_for_ssa(src0);
+          vec->src[i].swizzle[0] = index;
+       } else {
+          vec->src[i].src = nir_src_for_ssa(src1);
+          vec->src[i].swizzle[0] = index - src0->num_components;
+       }
+    }
+    nir_builder_instr_insert(&b->nb, &vec->instr);
+    return &vec->dest.dest.ssa;
+ }
+ /*
+  * Concatentates a number of vectors/scalars together to produce a vector
+  */
+ static nir_ssa_def *
+ vtn_vector_construct(struct vtn_builder *b, unsigned num_components,
+                      unsigned num_srcs, nir_ssa_def **srcs)
+ {
+    nir_alu_instr *vec = create_vec(b->shader, num_components);
+    unsigned dest_idx = 0;
+    for (unsigned i = 0; i < num_srcs; i++) {
+       nir_ssa_def *src = srcs[i];
+       for (unsigned j = 0; j < src->num_components; j++) {
+          vec->src[dest_idx].src = nir_src_for_ssa(src);
+          vec->src[dest_idx].swizzle[0] = j;
+          dest_idx++;
+       }
+    }
+    nir_builder_instr_insert(&b->nb, &vec->instr);
+    return &vec->dest.dest.ssa;
+ }
+ static struct vtn_ssa_value *
+ vtn_composite_copy(void *mem_ctx, struct vtn_ssa_value *src)
+ {
+    struct vtn_ssa_value *dest = rzalloc(mem_ctx, struct vtn_ssa_value);
+    dest->type = src->type;
+    if (glsl_type_is_vector_or_scalar(src->type)) {
+       dest->def = src->def;
+    } else {
+       unsigned elems = glsl_get_length(src->type);
+       dest->elems = ralloc_array(mem_ctx, struct vtn_ssa_value *, elems);
+       for (unsigned i = 0; i < elems; i++)
+          dest->elems[i] = vtn_composite_copy(mem_ctx, src->elems[i]);
+    }
+    return dest;
+ }
+ static struct vtn_ssa_value *
+ vtn_composite_insert(struct vtn_builder *b, struct vtn_ssa_value *src,
+                      struct vtn_ssa_value *insert, const uint32_t *indices,
+                      unsigned num_indices)
+ {
+    struct vtn_ssa_value *dest = vtn_composite_copy(b, src);
+    struct vtn_ssa_value *cur = dest;
+    unsigned i;
+    for (i = 0; i < num_indices - 1; i++) {
+       cur = cur->elems[indices[i]];
+    }
+    if (glsl_type_is_vector_or_scalar(cur->type)) {
+       /* According to the SPIR-V spec, OpCompositeInsert may work down to
+        * the component granularity. In that case, the last index will be
+        * the index to insert the scalar into the vector.
+        */
+       cur->def = vtn_vector_insert(b, cur->def, insert->def, indices[i]);
+    } else {
+       cur->elems[indices[i]] = insert;
+    }
+    return dest;
+ }
+ static struct vtn_ssa_value *
+ vtn_composite_extract(struct vtn_builder *b, struct vtn_ssa_value *src,
+                       const uint32_t *indices, unsigned num_indices)
+ {
+    struct vtn_ssa_value *cur = src;
+    for (unsigned i = 0; i < num_indices; i++) {
+       if (glsl_type_is_vector_or_scalar(cur->type)) {
+          assert(i == num_indices - 1);
+          /* According to the SPIR-V spec, OpCompositeExtract may work down to
+           * the component granularity. The last index will be the index of the
+           * vector to extract.
+           */
+          struct vtn_ssa_value *ret = rzalloc(b, struct vtn_ssa_value);
+          ret->type = glsl_scalar_type(glsl_get_base_type(cur->type));
+          ret->def = vtn_vector_extract(b, cur->def, indices[i]);
+          return ret;
+       }
+    }
+    return cur;
+ }
+ static void
+ vtn_handle_composite(struct vtn_builder *b, SpvOp opcode,
+                      const uint32_t *w, unsigned count)
+ {
+    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+    val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+    switch (opcode) {
+    case SpvOpVectorExtractDynamic:
+       val->ssa->def = vtn_vector_extract_dynamic(b, vtn_ssa_value(b, w[3])->def,
+                                                  vtn_ssa_value(b, w[4])->def);
+       break;
+    case SpvOpVectorInsertDynamic:
+       val->ssa->def = vtn_vector_insert_dynamic(b, vtn_ssa_value(b, w[3])->def,
+                                                 vtn_ssa_value(b, w[4])->def,
+                                                 vtn_ssa_value(b, w[5])->def);
+       break;
+    case SpvOpVectorShuffle:
+       val->ssa->def = vtn_vector_shuffle(b, glsl_get_vector_elements(val->type),
+                                          vtn_ssa_value(b, w[3])->def,
+                                          vtn_ssa_value(b, w[4])->def,
+                                          w + 5);
+       break;
+    case SpvOpCompositeConstruct: {
+       val->ssa = rzalloc(b, struct vtn_ssa_value);
+       unsigned elems = count - 3;
+       if (glsl_type_is_vector_or_scalar(val->type)) {
+          nir_ssa_def *srcs[4];
+          for (unsigned i = 0; i < elems; i++)
+             srcs[i] = vtn_ssa_value(b, w[3 + i])->def;
+          val->ssa->def =
+             vtn_vector_construct(b, glsl_get_vector_elements(val->type),
+                                  elems, srcs);
+       } else {
+          val->ssa->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+          for (unsigned i = 0; i < elems; i++)
+             val->ssa->elems[i] = vtn_ssa_value(b, w[3 + i]);
+       }
+       break;
+    }
+    case SpvOpCompositeExtract:
+       val->ssa = vtn_composite_extract(b, vtn_ssa_value(b, w[3]),
+                                        w + 4, count - 4);
+       break;
+    case SpvOpCompositeInsert:
+       val->ssa = vtn_composite_insert(b, vtn_ssa_value(b, w[4]),
+                                       vtn_ssa_value(b, w[3]),
+                                       w + 5, count - 5);
+       break;
+    case SpvOpCopyObject:
+       val->ssa = vtn_composite_copy(b, vtn_ssa_value(b, w[3]));
+       break;
+    default:
+       unreachable("unknown composite operation");
+    }
+    val->ssa->type = val->type;
+ }
+ static void
+ vtn_phi_node_init(struct vtn_builder *b, struct vtn_ssa_value *val)
+ {
+    if (glsl_type_is_vector_or_scalar(val->type)) {
+       nir_phi_instr *phi = nir_phi_instr_create(b->shader);
+       nir_ssa_dest_init(&phi->instr, &phi->dest,
+                         glsl_get_vector_elements(val->type), NULL);
+       exec_list_make_empty(&phi->srcs);
+       nir_builder_instr_insert(&b->nb, &phi->instr);
+       val->def = &phi->dest.ssa;
+    } else {
+       unsigned elems = glsl_get_length(val->type);
+       for (unsigned i = 0; i < elems; i++)
+          vtn_phi_node_init(b, val->elems[i]);
+    }
+ }
+ static struct vtn_ssa_value *
+ vtn_phi_node_create(struct vtn_builder *b, const struct glsl_type *type)
+ {
+    struct vtn_ssa_value *val = vtn_create_ssa_value(b, type);
+    vtn_phi_node_init(b, val);
+    return val;
+ }
+ static void
+ vtn_handle_phi_first_pass(struct vtn_builder *b, const uint32_t *w)
+ {
+    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+    val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+    val->ssa = vtn_phi_node_create(b, val->type);
+ }
+ static void
+ vtn_phi_node_add_src(struct vtn_ssa_value *phi, const nir_block *pred,
+                      struct vtn_ssa_value *val)
+ {
+    assert(phi->type == val->type);
+    if (glsl_type_is_vector_or_scalar(phi->type)) {
+       nir_phi_instr *phi_instr = nir_instr_as_phi(phi->def->parent_instr);
+       nir_phi_src *src = ralloc(phi_instr, nir_phi_src);
+       src->pred = (nir_block *) pred;
+       src->src = nir_src_for_ssa(val->def);
+       exec_list_push_tail(&phi_instr->srcs, &src->node);
+    } else {
+       unsigned elems = glsl_get_length(phi->type);
+       for (unsigned i = 0; i < elems; i++)
+          vtn_phi_node_add_src(phi->elems[i], pred, val->elems[i]);
+    }
+ }
+ static struct vtn_ssa_value *
+ vtn_get_phi_node_src(struct vtn_builder *b, nir_block *block,
+                      const struct glsl_type *type, const uint32_t *w,
+                      unsigned count)
+ {
+    struct hash_entry *entry = _mesa_hash_table_search(b->block_table, block);
+    if (entry) {
+       struct vtn_block *spv_block = entry->data;
+       for (unsigned off = 4; off < count; off += 2) {
+          if (spv_block == vtn_value(b, w[off], vtn_value_type_block)->block) {
+             return vtn_ssa_value(b, w[off - 1]);
+          }
+       }
+    }
+    nir_builder_insert_before_block(&b->nb, block);
+    struct vtn_ssa_value *phi = vtn_phi_node_create(b, type);
+    struct set_entry *entry2;
+    set_foreach(block->predecessors, entry2) {
+       nir_block *pred = (nir_block *) entry2->key;
+       struct vtn_ssa_value *val = vtn_get_phi_node_src(b, pred, type, w,
+                                                        count);
+       vtn_phi_node_add_src(phi, pred, val);
+    }
+    return phi;
+ }
+ static bool
+ vtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode,
+                            const uint32_t *w, unsigned count)
+ {
+    if (opcode == SpvOpLabel) {
+       b->block = vtn_value(b, w[1], vtn_value_type_block)->block;
+       return true;
+    }
+    if (opcode != SpvOpPhi)
+       return true;
+    struct vtn_ssa_value *phi = vtn_value(b, w[2], vtn_value_type_ssa)->ssa;
+    struct set_entry *entry;
+    set_foreach(b->block->block->predecessors, entry) {
+       nir_block *pred = (nir_block *) entry->key;
+       struct vtn_ssa_value *val = vtn_get_phi_node_src(b, pred, phi->type, w,
+                                                        count);
+       vtn_phi_node_add_src(phi, pred, val);
+    }
+    return true;
+ }
  static bool
  vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
                                  const uint32_t *w, unsigned count)
@@@ -1214,6 -1941,7 +2035,7 @@@ vtn_handle_first_cfg_pass_instruction(s
     }
  
     case SpvOpFunctionEnd:
+       b->func->end = w;
        b->func = NULL;
        break;
  
@@@ -1432,6 -2160,20 +2254,20 @@@ vtn_handle_body_instruction(struct vtn_
        vtn_handle_matrix_alu(b, opcode, w, count);
        break;
  
+    case SpvOpVectorExtractDynamic:
+    case SpvOpVectorInsertDynamic:
+    case SpvOpVectorShuffle:
+    case SpvOpCompositeConstruct:
+    case SpvOpCompositeExtract:
+    case SpvOpCompositeInsert:
+    case SpvOpCopyObject:
+       vtn_handle_composite(b, opcode, w, count);
+       break;
+    case SpvOpPhi:
+       vtn_handle_phi_first_pass(b, w);
+       break;
     default:
        unreachable("Unhandled opcode");
     }
@@@ -1446,20 -2188,11 +2282,11 @@@ vtn_walk_blocks(struct vtn_builder *b, 
  {
     struct vtn_block *block = start;
     while (block != end_block) {
-       if (block->block != NULL) {
-          /* We've already visited this block once before so this is a
-           * back-edge.  Back-edges are only allowed to point to a loop
-           * merge.
-           */
-          assert(block == cont_block);
-          return;
-       }
        if (block->merge_op == SpvOpLoopMerge) {
           /* This is the jump into a loop. */
-          cont_block = block;
-          break_block = vtn_value(b, block->merge_block_id,
-                                  vtn_value_type_block)->block;
+          struct vtn_block *new_cont_block = block;
+          struct vtn_block *new_break_block =
+             vtn_value(b, block->merge_block_id, vtn_value_type_block)->block;
  
           nir_loop *loop = nir_loop_create(b->shader);
           nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node);
           block->merge_op = SpvOpNop;
  
           nir_builder_insert_after_cf_list(&b->nb, &loop->body);
-          vtn_walk_blocks(b, block, break_block, cont_block, NULL);
+          vtn_walk_blocks(b, block, new_break_block, new_cont_block, NULL);
  
           nir_builder_insert_after_cf_list(&b->nb, old_list);
-          block = break_block;
+          block = new_break_block;
           continue;
        }
  
        vtn_foreach_instruction(b, block->label, block->branch,
                                vtn_handle_body_instruction);
  
+       nir_cf_node *cur_cf_node =
+          exec_node_data(nir_cf_node, exec_list_get_tail(b->nb.cf_node_list),
+                         node);
+       nir_block *cur_block = nir_cf_node_as_block(cur_cf_node);
+       _mesa_hash_table_insert(b->block_table, cur_block, block);
        switch (branch_op) {
        case SpvOpBranch: {
           struct vtn_block *branch_block =
  
              return;
           } else if (branch_block == end_block) {
+             /* We're branching to the merge block of an if, since for loops
+              * and functions end_block == NULL, so we're done here.
+              */
              return;
           } else {
+             /* We're branching to another block, and according to the rules,
+              * we can only branch to another block with one predecessor (so
+              * we're the only one jumping to it) so we can just process it
+              * next.
+              */
              block = branch_block;
              continue;
           }
              vtn_value(b, w[3], vtn_value_type_block)->block;
  
           nir_if *if_stmt = nir_if_create(b->shader);
-          if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1]));
+          if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])->def);
           nir_cf_node_insert_end(b->nb.cf_node_list, &if_stmt->cf_node);
  
           if (then_block == break_block) {
                                             &jump->instr);
              block = then_block;
           } else {
-             /* Conventional if statement */
+             /* According to the rules we're branching to two blocks that don't
+              * have any other predecessors, so we can handle this as a
+              * conventional if.
+              */
              assert(block->merge_op == SpvOpSelectionMerge);
              struct vtn_block *merge_block =
                 vtn_value(b, block->merge_block_id, vtn_value_type_block)->block;
@@@ -1652,9 -2402,15 +2496,15 @@@ spirv_to_nir(const uint32_t *words, siz
  
     foreach_list_typed(struct vtn_function, func, node, &b->functions) {
        b->impl = nir_function_impl_create(func->overload);
+       b->const_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
+                                                _mesa_key_pointer_equal);
+       b->block_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
+                                                _mesa_key_pointer_equal);
        nir_builder_init(&b->nb, b->impl);
        nir_builder_insert_after_cf_list(&b->nb, &b->impl->body);
        vtn_walk_blocks(b, func->start_block, NULL, NULL, NULL);
+       vtn_foreach_instruction(b, func->start_block->label, func->end,
+                               vtn_handle_phi_second_pass);
     }
  
     ralloc_free(b);