Merge remote-tracking branch 'mesa-public/master' into vulkan
authorJason Ekstrand <jason.ekstrand@intel.com>
Mon, 31 Aug 2015 23:30:07 +0000 (16:30 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Mon, 31 Aug 2015 23:30:07 +0000 (16:30 -0700)
12 files changed:
1  2 
src/glsl/glsl_parser_extras.cpp
src/glsl/glsl_types.h
src/glsl/nir/nir.h
src/glsl/nir/nir_builder.h
src/glsl/nir/spirv_to_nir.c
src/mesa/drivers/dri/i965/brw_defines.h
src/mesa/drivers/dri/i965/brw_fs.cpp
src/mesa/drivers/dri/i965/brw_fs_nir.cpp
src/mesa/drivers/dri/i965/brw_nir.c
src/mesa/drivers/dri/i965/brw_vec4.cpp
src/mesa/drivers/dri/i965/intel_debug.c
src/mesa/main/mtypes.h

index ca772e8ab33683088ee25a7dc3d486fbdad4456f,939a03cb0d768d9b0923b130006c3815bf3ef53d..5c8f98b091d96f606e06807a584407a5912705b6
@@@ -87,8 -87,6 +87,8 @@@ _mesa_glsl_parse_state::_mesa_glsl_pars
  
     this->extensions = &ctx->Extensions;
  
 +   this->ARB_compute_shader_enable = true;
 +
     this->Const.MaxLights = ctx->Const.MaxLights;
     this->Const.MaxClipPlanes = ctx->Const.MaxClipPlanes;
     this->Const.MaxTextureUnits = ctx->Const.MaxTextureUnits;
@@@ -628,6 -626,7 +628,7 @@@ static const _mesa_glsl_extension _mesa
     EXT(OES_EGL_image_external,         false, true,      OES_EGL_image_external),
     EXT(OES_standard_derivatives,       false, true,      OES_standard_derivatives),
     EXT(OES_texture_3D,                 false, true,      EXT_texture3D),
+    EXT(OES_texture_storage_multisample_2d_array, false, true, ARB_texture_multisample),
  
     /* All other extensions go here, sorted alphabetically.
      */
diff --combined src/glsl/glsl_types.h
index 28e2e93a30565f07f96fa793b61e8ea8d702e5bb,02a398f6112effcd1f421965a9676f23fd0498fb..f7d000c028b7b38155887de26c981de87d07058b
@@@ -56,7 -56,6 +56,7 @@@ enum glsl_base_type 
     GLSL_TYPE_IMAGE,
     GLSL_TYPE_ATOMIC_UINT,
     GLSL_TYPE_STRUCT,
 +   GLSL_TYPE_FUNCTION,
     GLSL_TYPE_INTERFACE,
     GLSL_TYPE_ARRAY,
     GLSL_TYPE_VOID,
@@@ -180,7 -179,7 +180,7 @@@ struct glsl_type 
      */
     union {
        const struct glsl_type *array;            /**< Type of array elements. */
 -      const struct glsl_type *parameters;       /**< Parameters to function. */
 +      struct glsl_function_param *parameters;   /**< Parameters to function. */
        struct glsl_struct_field *structure;      /**< List of struct fields. */
     } fields;
  
                                                  enum glsl_interface_packing packing,
                                                  const char *block_name);
  
 +   /**
 +    * Get the instance of a function type
 +    */
 +   static const glsl_type *get_function_instance(const struct glsl_type *return_type,
 +                                                 const glsl_function_param *parameters,
 +                                                 unsigned num_params);
     /**
      * Get the instance of an subroutine type
      */
     const glsl_type *field_type(const char *name) const;
  
     /**
-     * Get the location of a filed within a record type
+     * Get the location of a field within a record type
      */
     int field_index(const char *name) const;
  
@@@ -696,10 -689,6 +696,10 @@@ private
     glsl_type(const glsl_struct_field *fields, unsigned num_fields,
             enum glsl_interface_packing packing, const char *name);
  
 +   /** Constructor for interface types */
 +   glsl_type(const glsl_type *return_type,
 +             const glsl_function_param *params, unsigned num_params);
 +
     /** Constructor for array types */
     glsl_type(const glsl_type *array, unsigned length);
  
     /** Hash table containing the known interface types. */
     static struct hash_table *interface_types;
  
 +   /** Hash table containing the known function types. */
 +   static struct hash_table *function_types;
 +
     /** Hash table containing the known subroutine types. */
     static struct hash_table *subroutine_types;
  
     /*@}*/
  };
  
 +#undef DECL_TYPE
 +#undef STRUCT_TYPE
 +#endif /* __cplusplus */
 +
  struct glsl_struct_field {
     const struct glsl_type *type;
     const char *name;
      */
     int stream;
  
 +#ifdef __cplusplus
     glsl_struct_field(const struct glsl_type *_type, const char *_name)
        : type(_type), name(_name), location(-1), interpolation(0), centroid(0),
          sample(0), matrix_layout(GLSL_MATRIX_LAYOUT_INHERITED), patch(0),
     {
        /* empty */
     }
 +#endif
 +};
 +
 +struct glsl_function_param {
 +   const struct glsl_type *type;
 +
 +   bool in;
 +   bool out;
  };
  
  static inline unsigned int
@@@ -829,4 -802,8 +829,4 @@@ glsl_align(unsigned int a, unsigned in
     return (a + align - 1) / align * align;
  }
  
 -#undef DECL_TYPE
 -#undef STRUCT_TYPE
 -#endif /* __cplusplus */
 -
  #endif /* GLSL_TYPES_H */
diff --combined src/glsl/nir/nir.h
index 8a2396422b9a0b58318b235fa8ef9976d9a8355c,9703372fcc0e6814bd33bea56646ec22a92fcc08..af9f6ebb5133e54c4b568eab93027b9b99571a8a
@@@ -301,7 -301,6 +301,7 @@@ typedef struct 
         *
         * For array types, this represents the binding point for the first element.
         */
 +      int descriptor_set;
        int binding;
  
        /**
@@@ -516,11 -515,7 +516,11 @@@ typedef struct nir_src 
     bool is_ssa;
  } nir_src;
  
 -#define NIR_SRC_INIT (nir_src) { { NULL } }
 +#ifdef __cplusplus
 +#  define NIR_SRC_INIT nir_src()
 +#else
 +#  define NIR_SRC_INIT (nir_src) { { NULL } }
 +#endif
  
  #define nir_foreach_use(reg_or_ssa_def, src) \
     list_for_each_entry(nir_src, src, &(reg_or_ssa_def)->uses, use_link)
@@@ -543,11 -538,7 +543,11 @@@ typedef struct 
     bool is_ssa;
  } nir_dest;
  
 -#define NIR_DEST_INIT (nir_dest) { { { NULL } } }
 +#ifdef __cplusplus
 +#  define NIR_DEST_INIT nir_dest()
 +#else
 +#  define NIR_DEST_INIT (nir_dest) { { { NULL } } }
 +#endif
  
  #define nir_foreach_def(reg, dest) \
     list_for_each_entry(nir_dest, dest, &(reg)->defs, reg.def_link)
@@@ -786,15 -777,6 +786,15 @@@ NIR_DEFINE_CAST(nir_deref_as_var, nir_d
  NIR_DEFINE_CAST(nir_deref_as_array, nir_deref, nir_deref_array, deref)
  NIR_DEFINE_CAST(nir_deref_as_struct, nir_deref, nir_deref_struct, deref)
  
 +/** Returns the tail of a deref chain */
 +static inline nir_deref *
 +nir_deref_tail(nir_deref *deref)
 +{
 +   while (deref->child)
 +      deref = deref->child;
 +   return deref;
 +}
 +
  typedef struct {
     nir_instr instr;
  
@@@ -989,9 -971,6 +989,9 @@@ typedef struct 
     /* gather component selector */
     unsigned component : 2;
  
 +   /* The descriptor set containing this texture */
 +   unsigned sampler_set;
 +
     /** The sampler index
      *
      * If this texture instruction has a nir_tex_src_sampler_offset source,
@@@ -1567,20 -1546,160 +1567,182 @@@ nir_deref *nir_copy_deref(void *mem_ctx
  nir_load_const_instr *
  nir_deref_get_const_initializer_load(nir_shader *shader, nir_deref_var *deref);
  
- void nir_instr_insert_before(nir_instr *instr, nir_instr *before);
- void nir_instr_insert_after(nir_instr *instr, nir_instr *after);
+ /**
+  * NIR Cursors and Instruction Insertion API
+  * @{
+  *
+  * A tiny struct representing a point to insert/extract instructions or
+  * control flow nodes.  Helps reduce the combinatorial explosion of possible
+  * points to insert/extract.
+  *
+  * \sa nir_control_flow.h
+  */
+ typedef enum {
+    nir_cursor_before_block,
+    nir_cursor_after_block,
+    nir_cursor_before_instr,
+    nir_cursor_after_instr,
+ } nir_cursor_option;
+ typedef struct {
+    nir_cursor_option option;
+    union {
+       nir_block *block;
+       nir_instr *instr;
+    };
+ } nir_cursor;
++static inline nir_block *
++nir_cursor_current_block(nir_cursor cursor)
++{
++   if (cursor.option == nir_cursor_before_instr ||
++       cursor.option == nir_cursor_after_instr) {
++      return cursor.instr->block;
++   } else {
++      return cursor.block;
++   }
++}
++
+ static inline nir_cursor
+ nir_before_block(nir_block *block)
+ {
+    nir_cursor cursor;
+    cursor.option = nir_cursor_before_block;
+    cursor.block = block;
+    return cursor;
+ }
+ static inline nir_cursor
+ nir_after_block(nir_block *block)
+ {
+    nir_cursor cursor;
+    cursor.option = nir_cursor_after_block;
+    cursor.block = block;
+    return cursor;
+ }
+ static inline nir_cursor
+ nir_before_instr(nir_instr *instr)
+ {
+    nir_cursor cursor;
+    cursor.option = nir_cursor_before_instr;
+    cursor.instr = instr;
+    return cursor;
+ }
+ static inline nir_cursor
+ nir_after_instr(nir_instr *instr)
+ {
+    nir_cursor cursor;
+    cursor.option = nir_cursor_after_instr;
+    cursor.instr = instr;
+    return cursor;
+ }
++static inline nir_cursor
++nir_after_block_before_jump(nir_block *block)
++{
++   nir_instr *last_instr = nir_block_last_instr(block);
++   if (last_instr && last_instr->type == nir_instr_type_jump) {
++      return nir_before_instr(last_instr);
++   } else {
++      return nir_after_block(block);
++   }
++}
++
+ static inline nir_cursor
+ nir_before_cf_node(nir_cf_node *node)
+ {
+    if (node->type == nir_cf_node_block)
+       return nir_before_block(nir_cf_node_as_block(node));
+    return nir_after_block(nir_cf_node_as_block(nir_cf_node_prev(node)));
+ }
+ static inline nir_cursor
+ nir_after_cf_node(nir_cf_node *node)
+ {
+    if (node->type == nir_cf_node_block)
+       return nir_after_block(nir_cf_node_as_block(node));
+    return nir_before_block(nir_cf_node_as_block(nir_cf_node_next(node)));
+ }
+ static inline nir_cursor
+ nir_before_cf_list(struct exec_list *cf_list)
+ {
+    nir_cf_node *first_node = exec_node_data(nir_cf_node,
+                                             exec_list_get_head(cf_list), node);
+    return nir_before_cf_node(first_node);
+ }
+ static inline nir_cursor
+ nir_after_cf_list(struct exec_list *cf_list)
+ {
+    nir_cf_node *last_node = exec_node_data(nir_cf_node,
+                                            exec_list_get_tail(cf_list), node);
+    return nir_after_cf_node(last_node);
+ }
  
- void nir_instr_insert_before_block(nir_block *block, nir_instr *before);
- void nir_instr_insert_after_block(nir_block *block, nir_instr *after);
+ /**
+  * Insert a NIR instruction at the given cursor.
+  *
+  * Note: This does not update the cursor.
+  */
+ void nir_instr_insert(nir_cursor cursor, nir_instr *instr);
  
- void nir_instr_insert_before_cf(nir_cf_node *node, nir_instr *before);
- void nir_instr_insert_after_cf(nir_cf_node *node, nir_instr *after);
+ static inline void
+ nir_instr_insert_before(nir_instr *instr, nir_instr *before)
+ {
+    nir_instr_insert(nir_before_instr(instr), before);
+ }
  
- void nir_instr_insert_before_cf_list(struct exec_list *list, nir_instr *before);
- void nir_instr_insert_after_cf_list(struct exec_list *list, nir_instr *after);
+ static inline void
+ nir_instr_insert_after(nir_instr *instr, nir_instr *after)
+ {
+    nir_instr_insert(nir_after_instr(instr), after);
+ }
+ static inline void
+ nir_instr_insert_before_block(nir_block *block, nir_instr *before)
+ {
+    nir_instr_insert(nir_before_block(block), before);
+ }
+ static inline void
+ nir_instr_insert_after_block(nir_block *block, nir_instr *after)
+ {
+    nir_instr_insert(nir_after_block(block), after);
+ }
+ static inline void
+ nir_instr_insert_before_cf(nir_cf_node *node, nir_instr *before)
+ {
+    nir_instr_insert(nir_before_cf_node(node), before);
+ }
+ static inline void
+ nir_instr_insert_after_cf(nir_cf_node *node, nir_instr *after)
+ {
+    nir_instr_insert(nir_after_cf_node(node), after);
+ }
+ static inline void
+ nir_instr_insert_before_cf_list(struct exec_list *list, nir_instr *before)
+ {
+    nir_instr_insert(nir_before_cf_list(list), before);
+ }
+ static inline void
+ nir_instr_insert_after_cf_list(struct exec_list *list, nir_instr *after)
+ {
+    nir_instr_insert(nir_after_cf_list(list), after);
+ }
  
  void nir_instr_remove(nir_instr *instr);
  
+ /** @} */
  typedef bool (*nir_foreach_ssa_def_cb)(nir_ssa_def *def, void *state);
  typedef bool (*nir_foreach_dest_cb)(nir_dest *dest, void *state);
  typedef bool (*nir_foreach_src_cb)(nir_src *src, void *state);
@@@ -1652,8 -1771,6 +1814,8 @@@ void nir_lower_global_vars_to_local(nir
  
  void nir_lower_locals_to_regs(nir_shader *shader);
  
 +void nir_lower_outputs_to_temporaries(nir_shader *shader);
 +
  void nir_assign_var_locations(struct exec_list *var_list,
                                unsigned *size,
                                int (*type_size)(const struct glsl_type *));
@@@ -1672,7 -1789,6 +1834,7 @@@ void nir_lower_phis_to_scalar(nir_shade
  
  void nir_lower_samplers(nir_shader *shader,
                          const struct gl_shader_program *shader_program);
 +void nir_lower_samplers_for_vk(nir_shader *shader);
  
  void nir_lower_system_values(nir_shader *shader);
  void nir_lower_tex_projector(nir_shader *shader);
index 7d449262585db7d2bfab6ef9f766a506d0c06f05,08b40f8ea7cf71a332ad4521f15b2fa01f17344d..3aa0efded3c90817bce9fad806e23847922dc34a
  #ifndef NIR_BUILDER_H
  #define NIR_BUILDER_H
  
+ #include "nir_control_flow.h"
  struct exec_list;
  
  typedef struct nir_builder {
-    struct exec_list *cf_node_list;
-    nir_block *before_block;
-    nir_block *after_block;
-    nir_instr *before_instr;
-    nir_instr *after_instr;
+    nir_cursor cursor;
  
     nir_shader *shader;
     nir_function_impl *impl;
@@@ -48,74 -44,19 +44,19 @@@ nir_builder_init(nir_builder *build, ni
  }
  
  static inline void
- nir_builder_insert_after_cf_list(nir_builder *build,
-                                  struct exec_list *cf_node_list)
- {
-    build->cf_node_list = cf_node_list;
-    build->before_block = NULL;
-    build->after_block = NULL;
-    build->before_instr = NULL;
-    build->after_instr = NULL;
- }
- static inline void
- nir_builder_insert_before_block(nir_builder *build,
-                                 nir_block *block)
- {
-    build->cf_node_list = NULL;
-    build->before_block = block;
-    build->after_block = NULL;
-    build->before_instr = NULL;
-    build->after_instr = NULL;
- }
- static inline void
- nir_builder_insert_after_block(nir_builder *build,
-                                 nir_block *block)
- {
-    build->cf_node_list = NULL;
-    build->before_block = NULL;
-    build->after_block = block;
-    build->before_instr = NULL;
-    build->after_instr = NULL;
- }
- static inline void
- nir_builder_insert_before_instr(nir_builder *build, nir_instr *before_instr)
+ nir_builder_instr_insert(nir_builder *build, nir_instr *instr)
  {
-    build->cf_node_list = NULL;
-    build->before_block = NULL;
-    build->after_block = NULL;
-    build->before_instr = before_instr;
-    build->after_instr = NULL;
- }
+    nir_instr_insert(build->cursor, instr);
  
- static inline void
- nir_builder_insert_after_instr(nir_builder *build, nir_instr *after_instr)
- {
-    build->cf_node_list = NULL;
-    build->before_block = NULL;
-    build->after_block = NULL;
-    build->before_instr = NULL;
-    build->after_instr = after_instr;
+    /* Move the cursor forward. */
+    if (build->cursor.option == nir_cursor_after_instr)
+       build->cursor.instr = instr;
  }
  
  static inline void
- nir_builder_instr_insert(nir_builder *build, nir_instr *instr)
+ nir_builder_cf_insert(nir_builder *build, nir_cf_node *cf)
  {
-    if (build->cf_node_list) {
-       nir_instr_insert_after_cf_list(build->cf_node_list, instr);
-    } else if (build->before_block) {
-       nir_instr_insert_before_block(build->before_block, instr);
-    } else if (build->after_block) {
-       nir_instr_insert_after_block(build->after_block, instr);
-    } else if (build->before_instr) {
-       nir_instr_insert_before(build->before_instr, instr);
-    } else {
-       assert(build->after_instr);
-       nir_instr_insert_after(build->after_instr, instr);
-       build->after_instr = instr;
-    }
+    nir_cf_node_insert(build->cursor, cf);
  }
  
  static inline nir_ssa_def *
@@@ -276,23 -217,6 +217,23 @@@ nir_swizzle(nir_builder *build, nir_ssa
                       nir_imov_alu(build, alu_src, num_components);
  }
  
 +/* Selects the right fdot given the number of components in each source. */
 +static inline nir_ssa_def *
 +nir_fdot(nir_builder *build, nir_ssa_def *src0, nir_ssa_def *src1)
 +{
 +   assert(src0->num_components == src1->num_components);
 +   switch (src0->num_components) {
 +   case 1: return nir_fmul(build, src0, src1);
 +   case 2: return nir_fdot2(build, src0, src1);
 +   case 3: return nir_fdot3(build, src0, src1);
 +   case 4: return nir_fdot4(build, src0, src1);
 +   default:
 +      unreachable("bad component size");
 +   }
 +
 +   return NULL;
 +}
 +
  /**
   * Turns a nir_src into a nir_ssa_def * so it can be passed to
   * nir_build_alu()-based builder calls.
index 612d2fff29311740c9ddc44aa0fc847f0864e450,0000000000000000000000000000000000000000..8fa80ba0f858ded7185fc8baea88f4b103506fcf
mode 100644,000000..100644
--- /dev/null
@@@ -1,2984 -1,0 +1,2975 @@@
-    nir_builder_insert_before_block(&b->nb, block);
 +/*
 + * Copyright Â© 2015 Intel Corporation
 + *
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice (including the next
 + * paragraph) shall be included in all copies or substantial portions of the
 + * Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 + * IN THE SOFTWARE.
 + *
 + * Authors:
 + *    Jason Ekstrand (jason@jlekstrand.net)
 + *
 + */
 +
 +#include "spirv_to_nir_private.h"
 +#include "nir_vla.h"
 +#include "nir_control_flow.h"
 +
 +static struct vtn_ssa_value *
 +vtn_const_ssa_value(struct vtn_builder *b, nir_constant *constant,
 +                    const struct glsl_type *type)
 +{
 +   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 < 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);
 +
 +            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->const_type);
 +
 +   case vtn_value_type_ssa:
 +      return val->ssa;
 +   default:
 +      unreachable("Invalid type for an SSA value");
 +   }
 +}
 +
 +static char *
 +vtn_string_literal(struct vtn_builder *b, const uint32_t *words,
 +                   unsigned word_count)
 +{
 +   return ralloc_strndup(b, (char *)words, word_count * sizeof(*words));
 +}
 +
 +static const uint32_t *
 +vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start,
 +                        const uint32_t *end, vtn_instruction_handler handler)
 +{
 +   const uint32_t *w = start;
 +   while (w < end) {
 +      SpvOp opcode = w[0] & SpvOpCodeMask;
 +      unsigned count = w[0] >> SpvWordCountShift;
 +      assert(count >= 1 && w + count <= end);
 +
 +      if (!handler(b, opcode, w, count))
 +         return w;
 +
 +      w += count;
 +   }
 +   assert(w == end);
 +   return w;
 +}
 +
 +static void
 +vtn_handle_extension(struct vtn_builder *b, SpvOp opcode,
 +                     const uint32_t *w, unsigned count)
 +{
 +   switch (opcode) {
 +   case SpvOpExtInstImport: {
 +      struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_extension);
 +      if (strcmp((const char *)&w[2], "GLSL.std.450") == 0) {
 +         val->ext_handler = vtn_handle_glsl450_instruction;
 +      } else {
 +         assert(!"Unsupported extension");
 +      }
 +      break;
 +   }
 +
 +   case SpvOpExtInst: {
 +      struct vtn_value *val = vtn_value(b, w[3], vtn_value_type_extension);
 +      bool handled = val->ext_handler(b, w[4], w, count);
 +      (void)handled;
 +      assert(handled);
 +      break;
 +   }
 +
 +   default:
 +      unreachable("Unhandled opcode");
 +   }
 +}
 +
 +static void
 +_foreach_decoration_helper(struct vtn_builder *b,
 +                           struct vtn_value *base_value,
 +                           int member,
 +                           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);
 +         new_member = dec->member;
 +      }
 +
 +      if (dec->group) {
 +         assert(dec->group->value_type == vtn_value_type_decoration_group);
 +         _foreach_decoration_helper(b, base_value, new_member, dec->group,
 +                                    cb, data);
 +      } else {
 +         cb(b, base_value, new_member, dec, data);
 +      }
 +   }
 +}
 +
 +/** Iterates (recursively if needed) over all of the decorations on a value
 + *
 + * This function iterates over all of the decorations applied to a given
 + * value.  If it encounters a decoration group, it recurses into the group
 + * and iterates over all of those decorations as well.
 + */
 +void
 +vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value,
 +                       vtn_decoration_foreach_cb cb, void *data)
 +{
 +   _foreach_decoration_helper(b, value, -1, value, cb, data);
 +}
 +
 +static void
 +vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
 +                      const uint32_t *w, unsigned count)
 +{
 +   const uint32_t *w_end = w + count;
 +   const uint32_t target = w[1];
 +   w += 2;
 +
 +   int member = -1;
 +   switch (opcode) {
 +   case SpvOpDecorationGroup:
 +      vtn_push_value(b, target, vtn_value_type_undef);
 +      break;
 +
 +   case SpvOpMemberDecorate:
 +      member = *(w++);
 +      /* fallthrough */
 +   case SpvOpDecorate: {
 +      struct vtn_value *val = &b->values[target];
 +
 +      struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
 +      dec->member = member;
 +      dec->decoration = *(w++);
 +      dec->literals = w;
 +
 +      /* Link into the list */
 +      dec->next = val->decoration;
 +      val->decoration = dec;
 +      break;
 +   }
 +
 +   case SpvOpGroupMemberDecorate:
 +      member = *(w++);
 +      /* fallthrough */
 +   case SpvOpGroupDecorate: {
 +      struct vtn_value *group = &b->values[target];
 +      assert(group->value_type == vtn_value_type_decoration_group);
 +
 +      for (; w < w_end; w++) {
 +         struct vtn_value *val = &b->values[*w];
 +         struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
 +         dec->member = member;
 +         dec->group = group;
 +
 +         /* Link into the list */
 +         dec->next = val->decoration;
 +         val->decoration = dec;
 +      }
 +      break;
 +   }
 +
 +   default:
 +      unreachable("Unhandled 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_ctx)
 +{
 +   struct member_decoration_ctx *ctx = void_ctx;
 +
 +   if (member < 0)
 +      return;
 +
 +   switch (dec->decoration) {
 +   case SpvDecorationRelaxedPrecision:
 +      break; /* FIXME: Do nothing with this for now. */
 +   case SpvDecorationSmooth:
 +      ctx->fields[member].interpolation = INTERP_QUALIFIER_SMOOTH;
 +      break;
 +   case SpvDecorationNoperspective:
 +      ctx->fields[member].interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
 +      break;
 +   case SpvDecorationFlat:
 +      ctx->fields[member].interpolation = INTERP_QUALIFIER_FLAT;
 +      break;
 +   case SpvDecorationCentroid:
 +      ctx->fields[member].centroid = true;
 +      break;
 +   case SpvDecorationSample:
 +      ctx->fields[member].sample = true;
 +      break;
 +   case SpvDecorationLocation:
 +      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];
 +      ctx->type->builtin_block = true;
 +      break;
 +   case SpvDecorationOffset:
 +      ctx->type->offsets[member] = dec->literals[0];
 +      break;
 +   default:
 +      unreachable("Unhandled member decoration");
 +   }
 +}
 +
 +static void
 +type_decoration_cb(struct vtn_builder *b,
 +                   struct vtn_value *val, int member,
 +                    const struct vtn_decoration *dec, void *ctx)
 +{
 +   struct vtn_type *type = val->type;
 +
 +   if (member != -1)
 +      return;
 +
 +   switch (dec->decoration) {
 +   case SpvDecorationArrayStride:
 +      type->stride = dec->literals[0];
 +      break;
 +   case SpvDecorationBlock:
 +      type->block = true;
 +      break;
 +   case SpvDecorationBufferBlock:
 +      type->buffer_block = true;
 +      break;
 +   case SpvDecorationGLSLShared:
 +   case SpvDecorationGLSLPacked:
 +      /* Ignore these, since we get explicit offsets anyways */
 +      break;
 +
 +   default:
 +      unreachable("Unhandled type decoration");
 +   }
 +}
 +
 +static void
 +vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
 +                const uint32_t *w, unsigned count)
 +{
 +   struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_type);
 +
 +   val->type = rzalloc(b, struct vtn_type);
 +   val->type->is_builtin = false;
 +
 +   switch (opcode) {
 +   case SpvOpTypeVoid:
 +      val->type->type = glsl_void_type();
 +      break;
 +   case SpvOpTypeBool:
 +      val->type->type = glsl_bool_type();
 +      break;
 +   case SpvOpTypeInt:
 +      val->type->type = glsl_int_type();
 +      break;
 +   case SpvOpTypeFloat:
 +      val->type->type = glsl_float_type();
 +      break;
 +
 +   case SpvOpTypeVector: {
 +      const struct glsl_type *base =
 +         vtn_value(b, w[2], vtn_value_type_type)->type->type;
 +      unsigned elems = w[3];
 +
 +      assert(glsl_type_is_scalar(base));
 +      val->type->type = glsl_vector_type(glsl_get_base_type(base), elems);
 +      break;
 +   }
 +
 +   case SpvOpTypeMatrix: {
 +      struct vtn_type *base =
 +         vtn_value(b, w[2], vtn_value_type_type)->type;
 +      unsigned columns = w[3];
 +
 +      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;
 +      break;
 +   }
 +
 +   case SpvOpTypeArray: {
 +      struct vtn_type *array_element =
 +         vtn_value(b, w[2], vtn_value_type_type)->type;
 +      val->type->type = glsl_array_type(array_element->type, w[3]);
 +      val->type->array_element = array_element;
 +      val->type->stride = 0;
 +      break;
 +   }
 +
 +   case SpvOpTypeStruct: {
 +      unsigned num_fields = count - 2;
 +      val->type->members = ralloc_array(b, struct vtn_type *, num_fields);
 +      val->type->offsets = ralloc_array(b, unsigned, num_fields);
 +
 +      NIR_VLA(struct glsl_struct_field, fields, count);
 +      for (unsigned i = 0; i < num_fields; i++) {
 +         /* TODO: Handle decorators */
 +         val->type->members[i] =
 +            vtn_value(b, w[i + 2], vtn_value_type_type)->type;
 +         fields[i].type = val->type->members[i]->type;
 +         fields[i].name = ralloc_asprintf(b, "field%d", i);
 +         fields[i].location = -1;
 +         fields[i].interpolation = 0;
 +         fields[i].centroid = 0;
 +         fields[i].sample = 0;
 +         fields[i].matrix_layout = 2;
 +         fields[i].stream = -1;
 +      }
 +
 +      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, num_fields, name);
 +      break;
 +   }
 +
 +   case SpvOpTypeFunction: {
 +      const struct glsl_type *return_type =
 +         vtn_value(b, w[2], vtn_value_type_type)->type->type;
 +      NIR_VLA(struct glsl_function_param, params, count - 3);
 +      for (unsigned i = 0; i < count - 3; i++) {
 +         params[i].type = vtn_value(b, w[i + 3], vtn_value_type_type)->type->type;
 +
 +         /* FIXME: */
 +         params[i].in = true;
 +         params[i].out = true;
 +      }
 +      val->type->type = glsl_function_type(return_type, params, count - 3);
 +      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;
 +      break;
 +
 +   case SpvOpTypeImage: {
 +      const struct glsl_type *sampled_type =
 +         vtn_value(b, w[2], vtn_value_type_type)->type->type;
 +
 +      assert(glsl_type_is_vector_or_scalar(sampled_type));
 +
 +      enum glsl_sampler_dim dim;
 +      switch ((SpvDim)w[3]) {
 +      case SpvDim1D:       dim = GLSL_SAMPLER_DIM_1D;    break;
 +      case SpvDim2D:       dim = GLSL_SAMPLER_DIM_2D;    break;
 +      case SpvDim3D:       dim = GLSL_SAMPLER_DIM_3D;    break;
 +      case SpvDimCube:     dim = GLSL_SAMPLER_DIM_CUBE;  break;
 +      case SpvDimRect:     dim = GLSL_SAMPLER_DIM_RECT;  break;
 +      case SpvDimBuffer:   dim = GLSL_SAMPLER_DIM_BUF;   break;
 +      default:
 +         unreachable("Invalid SPIR-V Sampler dimension");
 +      }
 +
 +      bool is_shadow = w[4];
 +      bool is_array = w[5];
 +
 +      assert(w[6] == 0 && "FIXME: Handl multi-sampled textures");
 +      assert(w[7] == 1 && "FIXME: Add support for non-sampled images");
 +
 +      val->type->type = glsl_sampler_type(dim, is_shadow, is_array,
 +                                          glsl_get_base_type(sampled_type));
 +      break;
 +   }
 +
 +   case SpvOpTypeSampledImage:
 +      val->type = vtn_value(b, w[2], vtn_value_type_type)->type;
 +      break;
 +
 +   case SpvOpTypeRuntimeArray:
 +   case SpvOpTypeOpaque:
 +   case SpvOpTypeEvent:
 +   case SpvOpTypeDeviceEvent:
 +   case SpvOpTypeReserveId:
 +   case SpvOpTypeQueue:
 +   case SpvOpTypePipe:
 +   default:
 +      unreachable("Unhandled opcode");
 +   }
 +   
 +   vtn_foreach_decoration(b, val, type_decoration_cb, NULL);
 +}
 +
 +static void
 +vtn_handle_constant(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_constant);
 +   val->const_type = vtn_value(b, w[1], vtn_value_type_type)->type->type;
 +   val->constant = ralloc(b, nir_constant);
 +   switch (opcode) {
 +   case SpvOpConstantTrue:
 +      assert(val->const_type == glsl_bool_type());
 +      val->constant->value.u[0] = NIR_TRUE;
 +      break;
 +   case SpvOpConstantFalse:
 +      assert(val->const_type == glsl_bool_type());
 +      val->constant->value.u[0] = NIR_FALSE;
 +      break;
 +   case SpvOpConstant:
 +      assert(glsl_type_is_scalar(val->const_type));
 +      val->constant->value.u[0] = w[3];
 +      break;
 +   case SpvOpConstantComposite: {
 +      unsigned elem_count = count - 3;
 +      nir_constant **elems = ralloc_array(b, nir_constant *, elem_count);
 +      for (unsigned i = 0; i < elem_count; i++)
 +         elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant;
 +
 +      switch (glsl_get_base_type(val->const_type)) {
 +      case GLSL_TYPE_UINT:
 +      case GLSL_TYPE_INT:
 +      case GLSL_TYPE_FLOAT:
 +      case GLSL_TYPE_BOOL:
 +         if (glsl_type_is_matrix(val->const_type)) {
 +            unsigned rows = glsl_get_vector_elements(val->const_type);
 +            assert(glsl_get_matrix_columns(val->const_type) == elem_count);
 +            for (unsigned i = 0; i < elem_count; i++)
 +               for (unsigned j = 0; j < rows; j++)
 +                  val->constant->value.u[rows * i + j] = elems[i]->value.u[j];
 +         } else {
 +            assert(glsl_type_is_vector(val->const_type));
 +            assert(glsl_get_vector_elements(val->const_type) == elem_count);
 +            for (unsigned i = 0; i < elem_count; i++)
 +               val->constant->value.u[i] = elems[i]->value.u[0];
 +         }
 +         ralloc_free(elems);
 +         break;
 +
 +      case GLSL_TYPE_STRUCT:
 +      case GLSL_TYPE_ARRAY:
 +         ralloc_steal(val->constant, elems);
 +         val->constant->elements = elems;
 +         break;
 +
 +      default:
 +         unreachable("Unsupported type for constants");
 +      }
 +      break;
 +   }
 +
 +   default:
 +      unreachable("Unhandled 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 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:
 +      /* Vulkan defines VertexID to be zero-based and reserves the new
 +       * builtin keyword VertexIndex to indicate the non-zero-based value.
 +       */
 +      *location = SYSTEM_VALUE_VERTEX_ID_ZERO_BASE;
 +      *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)
 +{
 +   assert(val->value_type == vtn_value_type_deref);
 +   assert(val->deref->deref.child == NULL);
 +   assert(val->deref->var == void_var);
 +
 +   nir_variable *var = void_var;
 +   switch (dec->decoration) {
 +   case SpvDecorationRelaxedPrecision:
 +      break; /* FIXME: Do nothing with this for now. */
 +   case SpvDecorationSmooth:
 +      var->data.interpolation = INTERP_QUALIFIER_SMOOTH;
 +      break;
 +   case SpvDecorationNoperspective:
 +      var->data.interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
 +      break;
 +   case SpvDecorationFlat:
 +      var->data.interpolation = INTERP_QUALIFIER_FLAT;
 +      break;
 +   case SpvDecorationCentroid:
 +      var->data.centroid = true;
 +      break;
 +   case SpvDecorationSample:
 +      var->data.sample = true;
 +      break;
 +   case SpvDecorationInvariant:
 +      var->data.invariant = true;
 +      break;
 +   case SpvDecorationConstant:
 +      assert(var->constant_initializer != NULL);
 +      var->data.read_only = true;
 +      break;
 +   case SpvDecorationNonwritable:
 +      var->data.read_only = true;
 +      break;
 +   case SpvDecorationLocation:
 +      var->data.explicit_location = true;
 +      var->data.location = dec->literals[0];
 +      break;
 +   case SpvDecorationComponent:
 +      var->data.location_frac = dec->literals[0];
 +      break;
 +   case SpvDecorationIndex:
 +      var->data.explicit_index = true;
 +      var->data.index = dec->literals[0];
 +      break;
 +   case SpvDecorationBinding:
 +      var->data.explicit_binding = true;
 +      var->data.binding = dec->literals[0];
 +      break;
 +   case SpvDecorationDescriptorSet:
 +      var->data.descriptor_set = dec->literals[0];
 +      break;
 +   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;
 +   case SpvDecorationRowMajor:
 +   case SpvDecorationColMajor:
 +   case SpvDecorationGLSLShared:
 +   case SpvDecorationPatch:
 +   case SpvDecorationRestrict:
 +   case SpvDecorationAliased:
 +   case SpvDecorationVolatile:
 +   case SpvDecorationCoherent:
 +   case SpvDecorationNonreadable:
 +   case SpvDecorationUniform:
 +      /* This is really nice but we have no use for it right now. */
 +   case SpvDecorationCPacked:
 +   case SpvDecorationSaturatedConversion:
 +   case SpvDecorationStream:
 +   case SpvDecorationOffset:
 +   case SpvDecorationXfbBuffer:
 +   case SpvDecorationFuncParamAttr:
 +   case SpvDecorationFPRoundingMode:
 +   case SpvDecorationFPFastMathMode:
 +   case SpvDecorationLinkageAttributes:
 +   case SpvDecorationSpecId:
 +      break;
 +   default:
 +      unreachable("Unhandled variable decoration");
 +   }
 +}
 +
 +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(var, "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, 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.
 +    */
 +   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,
 +                                            src_type->array_element,
 +                                            &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,
 +                                            src_type->members[i],
 +                                            &deref->deref);
 +      }
 +   }
 +
 +   src_deref_tail->child = old_child;
 +
 +   return val;
 +}
 +
 +static void
 +_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)) {
 +      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->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);
 +   } 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_type->array_element, 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_type->members[i], dest_deref,
 +                             &deref->deref, src->elems[i]);
 +      }
 +   }
 +
 +   dest_deref_tail->child = old_child;
 +}
 +
 +static struct vtn_ssa_value *
 +_vtn_block_load(struct vtn_builder *b, nir_intrinsic_op op,
 +                unsigned set, nir_ssa_def *binding,
 +                unsigned offset, nir_ssa_def *indirect,
 +                struct vtn_type *type)
 +{
 +   struct vtn_ssa_value *val = ralloc(b, struct vtn_ssa_value);
 +   val->type = type->type;
 +   val->transposed = NULL;
 +   if (glsl_type_is_vector_or_scalar(type->type)) {
 +      nir_intrinsic_instr *load = nir_intrinsic_instr_create(b->shader, op);
 +      load->num_components = glsl_get_vector_elements(type->type);
 +      load->const_index[0] = set;
 +      load->src[0] = nir_src_for_ssa(binding);
 +      load->const_index[1] = offset;
 +      if (indirect)
 +         load->src[1] = nir_src_for_ssa(indirect);
 +      nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, NULL);
 +      nir_builder_instr_insert(&b->nb, &load->instr);
 +      val->def = &load->dest.ssa;
 +   } else {
 +      unsigned elems = glsl_get_length(type->type);
 +      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
 +      if (glsl_type_is_struct(type->type)) {
 +         for (unsigned i = 0; i < elems; i++) {
 +            val->elems[i] = _vtn_block_load(b, op, set, binding,
 +                                            offset + type->offsets[i],
 +                                            indirect, type->members[i]);
 +         }
 +      } else {
 +         for (unsigned i = 0; i < elems; i++) {
 +            val->elems[i] = _vtn_block_load(b, op, set, binding,
 +                                            offset + i * type->stride,
 +                                            indirect, type->array_element);
 +         }
 +      }
 +   }
 +
 +   return val;
 +}
 +
 +static struct vtn_ssa_value *
 +vtn_block_load(struct vtn_builder *b, nir_deref_var *src,
 +               struct vtn_type *type, nir_deref *src_tail)
 +{
 +   unsigned set = src->var->data.descriptor_set;
 +   
 +   nir_ssa_def *binding = nir_imm_int(&b->nb, src->var->data.binding);
 +   nir_deref *deref = &src->deref;
 +   
 +   /* The block variable may be an array, in which case the array index adds
 +    * an offset to the binding. Figure out that index now.
 +    */
 +
 +   if (deref->child->deref_type == nir_deref_type_array) {
 +      deref = deref->child;
 +      type = type->array_element;
 +      nir_deref_array *deref_array = nir_deref_as_array(deref);
 +      if (deref_array->deref_array_type == nir_deref_array_type_direct) {
 +         binding = nir_imm_int(&b->nb, src->var->data.binding +
 +                                       deref_array->base_offset);
 +      } else {
 +         binding = nir_iadd(&b->nb, binding, deref_array->indirect.ssa);
 +      }
 +   }
 +
 +   unsigned offset = 0;
 +   nir_ssa_def *indirect = NULL;
 +   while (deref != src_tail) {
 +      deref = deref->child;
 +      switch (deref->deref_type) {
 +      case nir_deref_type_array: {
 +         nir_deref_array *deref_array = nir_deref_as_array(deref);
 +         if (deref_array->deref_array_type == nir_deref_array_type_direct) {
 +            offset += type->stride * deref_array->base_offset;
 +         } else {
 +            nir_ssa_def *offset = nir_imul(&b->nb, deref_array->indirect.ssa,
 +                                           nir_imm_int(&b->nb, type->stride));
 +            indirect = indirect ? nir_iadd(&b->nb, indirect, offset) : offset;
 +         }
 +         type = type->array_element;
 +         break;
 +      }
 +      
 +      case nir_deref_type_struct: {
 +         nir_deref_struct *deref_struct = nir_deref_as_struct(deref);
 +         offset += type->offsets[deref_struct->index];
 +         type = type->members[deref_struct->index];
 +         break;
 +      }
 +
 +      default:
 +         unreachable("unknown deref type");
 +      }
 +   }
 +
 +   /* TODO SSBO's */
 +   nir_intrinsic_op op = indirect ? nir_intrinsic_load_ubo_indirect
 +                                  : nir_intrinsic_load_ubo;
 +
 +   return _vtn_block_load(b, op, set, binding, offset, indirect, type);
 +}
 +
 +/*
 + * 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,
 +                  struct vtn_type *src_type)
 +{
 +   nir_deref *src_tail = get_deref_tail(src);
 +
 +   struct vtn_ssa_value *val;
 +   if (src->var->interface_type && src->var->data.mode == nir_var_uniform)
 +      val = vtn_block_load(b, src, src_type, src_tail);
 +   else
 +      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);
 +      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, 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_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)
 +         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_type, dest, dest_tail, val);
 +   } else {
 +      _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, struct vtn_type *type)
 +{
 +   nir_deref *src_tail = get_deref_tail(src);
 +
 +   if (src_tail->child || src->var->interface_type) {
 +      assert(get_deref_tail(dest)->child);
 +      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);
 +      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)
 +{
 +   switch (opcode) {
 +   case SpvOpVariable: {
 +      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->type;
 +      var->name = ralloc_strdup(var, val->name);
 +
 +      bool builtin_block = false;
 +      if (type->block) {
 +         var->interface_type = type->type;
 +         builtin_block = type->builtin_block;
 +      } else if (glsl_type_is_array(type->type) &&
 +                 (type->array_element->block ||
 +                  type->array_element->buffer_block)) {
 +         var->interface_type = type->array_element->type;
 +         builtin_block = type->array_element->builtin_block;
 +      } else {
 +         var->interface_type = NULL;
 +      }
 +
 +      switch ((SpvStorageClass)w[3]) {
 +      case SpvStorageClassUniform:
 +      case SpvStorageClassUniformConstant:
 +         var->data.mode = nir_var_uniform;
 +         var->data.read_only = true;
 +         break;
 +      case SpvStorageClassInput:
 +         var->data.mode = nir_var_shader_in;
 +         var->data.read_only = true;
 +         break;
 +      case SpvStorageClassOutput:
 +         var->data.mode = nir_var_shader_out;
 +         break;
 +      case SpvStorageClassPrivateGlobal:
 +         var->data.mode = nir_var_global;
 +         break;
 +      case SpvStorageClassFunction:
 +         var->data.mode = nir_var_local;
 +         break;
 +      case SpvStorageClassWorkgroupLocal:
 +      case SpvStorageClassWorkgroupGlobal:
 +      case SpvStorageClassGeneric:
 +      case SpvStorageClassAtomicCounter:
 +      default:
 +         unreachable("Unhandled variable storage class");
 +      }
 +
 +      if (count > 4) {
 +         assert(count == 5);
 +         var->constant_initializer =
 +            vtn_value(b, w[4], vtn_value_type_constant)->constant;
 +      }
 +
 +      val->deref = nir_deref_var_create(b, var);
 +      val->deref_type = type;
 +
 +      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;
 +      }
 +
 +      /* If this was a uniform block, then we're not going to actually use the
 +       * variable (we're only going to use it to compute offsets), so don't
 +       * declare it in the shader.
 +       */
 +      if (var->data.mode == nir_var_uniform && var->interface_type)
 +         break;
 +
 +      /* Builtin blocks are lowered to individual variables during SPIR-V ->
 +       * NIR, so don't declare them either.
 +       */
 +      if (builtin_block)
 +         break;
 +
 +      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;
 +   }
 +
 +   case SpvOpAccessChain:
 +   case SpvOpInBoundsAccessChain: {
 +      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));
 +      struct vtn_type *deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 +
 +      nir_deref *tail = &val->deref->deref;
 +      while (tail->child)
 +         tail = tail->child;
 +
 +      for (unsigned i = 0; i < count - 4; i++) {
 +         assert(w[i + 4] < b->value_id_bound);
 +         struct vtn_value *idx_val = &b->values[w[i + 4]];
 +
 +         enum glsl_base_type base_type = glsl_get_base_type(tail->type);
 +         switch (base_type) {
 +         case GLSL_TYPE_UINT:
 +         case GLSL_TYPE_INT:
 +         case GLSL_TYPE_FLOAT:
 +         case GLSL_TYPE_DOUBLE:
 +         case GLSL_TYPE_BOOL:
 +         case GLSL_TYPE_ARRAY: {
 +            nir_deref_array *deref_arr = nir_deref_array_create(b);
 +            if (base_type == GLSL_TYPE_ARRAY ||
 +                glsl_type_is_matrix(tail->type)) {
 +               deref_type = deref_type->array_element;
 +            } else {
 +               assert(glsl_type_is_vector(tail->type));
 +               deref_type = ralloc(b, struct vtn_type);
 +               deref_type->type = glsl_scalar_type(base_type);
 +            }
 +
 +            deref_arr->deref.type = 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;
 +               deref_arr->base_offset = idx;
 +            } else {
 +               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])->def);
 +            }
 +            tail->child = &deref_arr->deref;
 +            break;
 +         }
 +
 +         case GLSL_TYPE_STRUCT: {
 +            assert(idx_val->value_type == vtn_value_type_constant);
 +            unsigned idx = idx_val->constant->value.u[0];
 +            deref_type = deref_type->members[idx];
 +            nir_deref_struct *deref_struct = nir_deref_struct_create(b, idx);
 +            deref_struct->deref.type = deref_type->type;
 +            tail->child = &deref_struct->deref;
 +            break;
 +         }
 +         default:
 +            unreachable("Invalid type for deref");
 +         }
 +         tail = tail->child;
 +      }
 +
 +      /* For uniform blocks, we don't resolve the access chain until we
 +       * actually access the variable, so we need to keep around the original
 +       * type of the variable.
 +       */
 +      if (base->var->interface_type && base->var->data.mode == nir_var_uniform)
 +         val->deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 +      else
 +         val->deref_type = deref_type;
 +
 +
 +      break;
 +   }
 +
 +   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, type);
 +      break;
 +   }
 +
 +   case SpvOpLoad: {
 +      nir_deref_var *src = vtn_value(b, w[3], vtn_value_type_deref)->deref;
 +      struct vtn_type *src_type =
 +         vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 +
 +      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, 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, dest_type);
 +      break;
 +   }
 +
 +   case SpvOpCopyMemorySized:
 +   case SpvOpArrayLength:
 +   case SpvOpImageTexelPointer:
 +   default:
 +      unreachable("Unhandled opcode");
 +   }
 +}
 +
 +static void
 +vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
 +                         const uint32_t *w, unsigned count)
 +{
 +   unreachable("Unhandled opcode");
 +}
 +
 +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_tex_src
 +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->def);
 +   src.src_type = type;
 +   return src;
 +}
 +
 +static void
 +vtn_handle_texture(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);
 +   nir_deref_var *sampler = vtn_value(b, w[3], vtn_value_type_deref)->deref;
 +
 +   nir_tex_src srcs[8]; /* 8 should be enough */
 +   nir_tex_src *p = srcs;
 +
 +   unsigned idx = 4;
 +
 +   unsigned coord_components = 0;
 +   switch (opcode) {
 +   case SpvOpImageSampleImplicitLod:
 +   case SpvOpImageSampleExplicitLod: 
 +   case SpvOpImageSampleDrefImplicitLod: 
 +   case SpvOpImageSampleDrefExplicitLod: 
 +   case SpvOpImageSampleProjImplicitLod:
 +   case SpvOpImageSampleProjExplicitLod: 
 +   case SpvOpImageSampleProjDrefImplicitLod: 
 +   case SpvOpImageSampleProjDrefExplicitLod: 
 +   case SpvOpImageFetch:
 +   case SpvOpImageGather:
 +   case SpvOpImageDrefGather: 
 +   case SpvOpImageQueryLod: {
 +      /* All these types have the coordinate as their first real argument */
 +      struct vtn_ssa_value *coord = vtn_ssa_value(b, w[idx++]);
 +      coord_components = glsl_get_vector_elements(coord->type);
 +      p->src = nir_src_for_ssa(coord->def);
 +      p->src_type = nir_tex_src_coord;
 +      p++;
 +      break;
 +   }
 +
 +   default:
 +      break;
 +   }
 +
 +   nir_texop texop;
 +   switch (opcode) {
 +   case SpvOpImageSampleImplicitLod:
 +      texop = nir_texop_tex;
 +      break;
 +
 +   case SpvOpImageSampleExplicitLod: 
 +   case SpvOpImageSampleDrefImplicitLod: 
 +   case SpvOpImageSampleDrefExplicitLod: 
 +   case SpvOpImageSampleProjImplicitLod:
 +   case SpvOpImageSampleProjExplicitLod: 
 +   case SpvOpImageSampleProjDrefImplicitLod: 
 +   case SpvOpImageSampleProjDrefExplicitLod: 
 +   case SpvOpImageFetch:
 +   case SpvOpImageGather:
 +   case SpvOpImageDrefGather: 
 +   case SpvOpImageQuerySizeLod:
 +   case SpvOpImageQuerySize:
 +   case SpvOpImageQueryLod:
 +   case SpvOpImageQueryLevels:
 +   case SpvOpImageQuerySamples:
 +   default:
 +      unreachable("Unhandled opcode");
 +   }
 +
 +   /* From now on, the remaining sources are "Optional Image Operands." */
 +   if (idx < count) {
 +      /* XXX handle these (bias, lod, etc.) */
 +      assert(0);
 +   }
 +
 +
 +   nir_tex_instr *instr = nir_tex_instr_create(b->shader, p - srcs);
 +
 +   const struct glsl_type *sampler_type = nir_deref_tail(&sampler->deref)->type;
 +   instr->sampler_dim = glsl_get_sampler_dim(sampler_type);
 +
 +   switch (glsl_get_sampler_result_type(sampler_type)) {
 +   case GLSL_TYPE_FLOAT:   instr->dest_type = nir_type_float;     break;
 +   case GLSL_TYPE_INT:     instr->dest_type = nir_type_int;       break;
 +   case GLSL_TYPE_UINT:    instr->dest_type = nir_type_unsigned;  break;
 +   case GLSL_TYPE_BOOL:    instr->dest_type = nir_type_bool;      break;
 +   default:
 +      unreachable("Invalid base type for sampler result");
 +   }
 +
 +   instr->op = texop;
 +   memcpy(instr->src, srcs, instr->num_srcs * sizeof(*instr->src));
 +   instr->coord_components = coord_components;
 +   instr->is_array = glsl_sampler_type_is_array(sampler_type);
 +   instr->is_shadow = glsl_sampler_type_is_shadow(sampler_type);
 +
 +   instr->sampler = nir_deref_as_var(nir_copy_deref(instr, &sampler->deref));
 +
 +   nir_ssa_dest_init(&instr->instr, &instr->dest, 4, NULL);
 +   val->ssa = vtn_create_ssa_value(b, glsl_vector_type(GLSL_TYPE_FLOAT, 4));
 +   val->ssa->def = &instr->dest.ssa;
 +
 +   nir_builder_instr_insert(&b->nb, &instr->instr);
 +}
 +
 +
 +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);
 +   vec->dest.write_mask = (1 << num_components) - 1;
 +
 +   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)
 +{
 +   struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
 +
 +   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
 +vtn_handle_alu(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);
 +   const struct glsl_type *type =
 +      vtn_value(b, w[1], vtn_value_type_type)->type->type;
 +   val->ssa = vtn_create_ssa_value(b, 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])->def;
 +
 +   /* Indicates that the first two arguments should be swapped.  This is
 +    * used for implementing greater-than and less-than-or-equal.
 +    */
 +   bool swap = false;
 +
 +   nir_op op;
 +   switch (opcode) {
 +   /* Basic ALU operations */
 +   case SpvOpSNegate:               op = nir_op_ineg;    break;
 +   case SpvOpFNegate:               op = nir_op_fneg;    break;
 +   case SpvOpNot:                   op = nir_op_inot;    break;
 +
 +   case SpvOpAny:
 +      switch (src[0]->num_components) {
 +      case 1:  op = nir_op_imov;    break;
 +      case 2:  op = nir_op_bany2;   break;
 +      case 3:  op = nir_op_bany3;   break;
 +      case 4:  op = nir_op_bany4;   break;
 +      }
 +      break;
 +
 +   case SpvOpAll:
 +      switch (src[0]->num_components) {
 +      case 1:  op = nir_op_imov;    break;
 +      case 2:  op = nir_op_ball2;   break;
 +      case 3:  op = nir_op_ball3;   break;
 +      case 4:  op = nir_op_ball4;   break;
 +      }
 +      break;
 +
 +   case SpvOpIAdd:                  op = nir_op_iadd;    break;
 +   case SpvOpFAdd:                  op = nir_op_fadd;    break;
 +   case SpvOpISub:                  op = nir_op_isub;    break;
 +   case SpvOpFSub:                  op = nir_op_fsub;    break;
 +   case SpvOpIMul:                  op = nir_op_imul;    break;
 +   case SpvOpFMul:                  op = nir_op_fmul;    break;
 +   case SpvOpUDiv:                  op = nir_op_udiv;    break;
 +   case SpvOpSDiv:                  op = nir_op_idiv;    break;
 +   case SpvOpFDiv:                  op = nir_op_fdiv;    break;
 +   case SpvOpUMod:                  op = nir_op_umod;    break;
 +   case SpvOpSMod:                  op = nir_op_umod;    break; /* FIXME? */
 +   case SpvOpFMod:                  op = nir_op_fmod;    break;
 +
 +   case SpvOpDot:
 +      assert(src[0]->num_components == src[1]->num_components);
 +      switch (src[0]->num_components) {
 +      case 1:  op = nir_op_fmul;    break;
 +      case 2:  op = nir_op_fdot2;   break;
 +      case 3:  op = nir_op_fdot3;   break;
 +      case 4:  op = nir_op_fdot4;   break;
 +      }
 +      break;
 +
 +   case SpvOpShiftRightLogical:     op = nir_op_ushr;    break;
 +   case SpvOpShiftRightArithmetic:  op = nir_op_ishr;    break;
 +   case SpvOpShiftLeftLogical:      op = nir_op_ishl;    break;
 +   case SpvOpLogicalOr:             op = nir_op_ior;     break;
 +   case SpvOpLogicalEqual:          op = nir_op_ieq;     break;
 +   case SpvOpLogicalNotEqual:       op = nir_op_ine;     break;
 +   case SpvOpLogicalAnd:            op = nir_op_iand;    break;
 +   case SpvOpBitwiseOr:             op = nir_op_ior;     break;
 +   case SpvOpBitwiseXor:            op = nir_op_ixor;    break;
 +   case SpvOpBitwiseAnd:            op = nir_op_iand;    break;
 +   case SpvOpSelect:                op = nir_op_bcsel;   break;
 +   case SpvOpIEqual:                op = nir_op_ieq;     break;
 +
 +   /* Comparisons: (TODO: How do we want to handled ordered/unordered?) */
 +   case SpvOpFOrdEqual:             op = nir_op_feq;     break;
 +   case SpvOpFUnordEqual:           op = nir_op_feq;     break;
 +   case SpvOpINotEqual:             op = nir_op_ine;     break;
 +   case SpvOpFOrdNotEqual:          op = nir_op_fne;     break;
 +   case SpvOpFUnordNotEqual:        op = nir_op_fne;     break;
 +   case SpvOpULessThan:             op = nir_op_ult;     break;
 +   case SpvOpSLessThan:             op = nir_op_ilt;     break;
 +   case SpvOpFOrdLessThan:          op = nir_op_flt;     break;
 +   case SpvOpFUnordLessThan:        op = nir_op_flt;     break;
 +   case SpvOpUGreaterThan:          op = nir_op_ult;  swap = true;   break;
 +   case SpvOpSGreaterThan:          op = nir_op_ilt;  swap = true;   break;
 +   case SpvOpFOrdGreaterThan:       op = nir_op_flt;  swap = true;   break;
 +   case SpvOpFUnordGreaterThan:     op = nir_op_flt;  swap = true;   break;
 +   case SpvOpULessThanEqual:        op = nir_op_uge;  swap = true;   break;
 +   case SpvOpSLessThanEqual:        op = nir_op_ige;  swap = true;   break;
 +   case SpvOpFOrdLessThanEqual:     op = nir_op_fge;  swap = true;   break;
 +   case SpvOpFUnordLessThanEqual:   op = nir_op_fge;  swap = true;   break;
 +   case SpvOpUGreaterThanEqual:     op = nir_op_uge;     break;
 +   case SpvOpSGreaterThanEqual:     op = nir_op_ige;     break;
 +   case SpvOpFOrdGreaterThanEqual:  op = nir_op_fge;     break;
 +   case SpvOpFUnordGreaterThanEqual:op = nir_op_fge;     break;
 +
 +   /* Conversions: */
 +   case SpvOpConvertFToU:           op = nir_op_f2u;     break;
 +   case SpvOpConvertFToS:           op = nir_op_f2i;     break;
 +   case SpvOpConvertSToF:           op = nir_op_i2f;     break;
 +   case SpvOpConvertUToF:           op = nir_op_u2f;     break;
 +   case SpvOpBitcast:               op = nir_op_imov;    break;
 +   case SpvOpUConvert:
 +   case SpvOpSConvert:
 +      op = nir_op_imov; /* TODO: NIR is 32-bit only; these are no-ops. */
 +      break;
 +   case SpvOpFConvert:
 +      op = nir_op_fmov;
 +      break;
 +
 +   /* Derivatives: */
 +   case SpvOpDPdx:         op = nir_op_fddx;          break;
 +   case SpvOpDPdy:         op = nir_op_fddy;          break;
 +   case SpvOpDPdxFine:     op = nir_op_fddx_fine;     break;
 +   case SpvOpDPdyFine:     op = nir_op_fddy_fine;     break;
 +   case SpvOpDPdxCoarse:   op = nir_op_fddx_coarse;   break;
 +   case SpvOpDPdyCoarse:   op = nir_op_fddy_coarse;   break;
 +   case SpvOpFwidth:
 +      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->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->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->def = nir_fmul(&b->nb, src[0], src[1]);
 +      return;
 +
 +   case SpvOpSRem:
 +   case SpvOpFRem:
 +      unreachable("No NIR equivalent");
 +
 +   case SpvOpIsNan:
 +   case SpvOpIsInf:
 +   case SpvOpIsFinite:
 +   case SpvOpIsNormal:
 +   case SpvOpSignBitSet:
 +   case SpvOpLessOrGreater:
 +   case SpvOpOrdered:
 +   case SpvOpUnordered:
 +   default:
 +      unreachable("Unhandled opcode");
 +   }
 +
 +   if (swap) {
 +      nir_ssa_def *tmp = src[0];
 +      src[0] = src[1];
 +      src[1] = tmp;
 +   }
 +
 +   nir_alu_instr *instr = nir_alu_instr_create(b->shader, op);
 +   nir_ssa_dest_init(&instr->instr, &instr->dest.dest,
 +                     glsl_get_vector_elements(type), val->name);
 +   instr->dest.write_mask = (1 << glsl_get_vector_elements(type)) - 1;
 +   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);
 +   const struct glsl_type *type =
 +      vtn_value(b, w[1], vtn_value_type_type)->type->type;
 +   val->ssa = vtn_create_ssa_value(b, 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(type),
 +                                         vtn_ssa_value(b, w[3])->def,
 +                                         vtn_ssa_value(b, w[4])->def,
 +                                         w + 5);
 +      break;
 +
 +   case SpvOpCompositeConstruct: {
 +      unsigned elems = count - 3;
 +      if (glsl_type_is_vector_or_scalar(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(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");
 +   }
 +}
 +
 +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);
 +   const struct glsl_type *type =
 +      vtn_value(b, w[1], vtn_value_type_type)->type->type;
 +   val->ssa = vtn_phi_node_create(b, 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]);
 +         }
 +      }
 +   }
 +
-       struct exec_node *list_tail = exec_list_get_tail(b->nb.cf_node_list);
-       nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node);
-       assert(tail_node->type == nir_cf_node_block);
-       block->block = nir_cf_node_as_block(tail_node);
++   b->nb.cursor = nir_before_block(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)
 +{
 +   switch (opcode) {
 +   case SpvOpSource:
 +   case SpvOpSourceExtension:
 +   case SpvOpExtension:
 +      /* Unhandled, but these are for debug so that's ok. */
 +      break;
 +
 +   case SpvOpCapability:
 +      /*
 +       * TODO properly handle these and give a real error if asking for too
 +       * much.
 +       */
 +      assert(w[1] == SpvCapabilityMatrix ||
 +             w[1] == SpvCapabilityShader);
 +      break;
 +
 +   case SpvOpExtInstImport:
 +      vtn_handle_extension(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpMemoryModel:
 +      assert(w[1] == SpvAddressingModelLogical);
 +      assert(w[2] == SpvMemoryModelGLSL450);
 +      break;
 +
 +   case SpvOpEntryPoint:
 +      assert(b->entry_point == NULL);
 +      b->entry_point = &b->values[w[2]];
 +      b->execution_model = w[1];
 +      break;
 +
 +   case SpvOpExecutionMode:
 +      /*
 +       * TODO handle these - for Vulkan OriginUpperLeft is always set for
 +       * fragment shaders, so we can ignore this for now
 +       */
 +      break;
 +
 +   case SpvOpString:
 +      vtn_push_value(b, w[1], vtn_value_type_string)->str =
 +         vtn_string_literal(b, &w[2], count - 2);
 +      break;
 +
 +   case SpvOpName:
 +      b->values[w[1]].name = vtn_string_literal(b, &w[2], count - 2);
 +      break;
 +
 +   case SpvOpMemberName:
 +      /* TODO */
 +      break;
 +
 +   case SpvOpLine:
 +      break; /* Ignored for now */
 +
 +   case SpvOpDecorationGroup:
 +   case SpvOpDecorate:
 +   case SpvOpMemberDecorate:
 +   case SpvOpGroupDecorate:
 +   case SpvOpGroupMemberDecorate:
 +      vtn_handle_decoration(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpTypeVoid:
 +   case SpvOpTypeBool:
 +   case SpvOpTypeInt:
 +   case SpvOpTypeFloat:
 +   case SpvOpTypeVector:
 +   case SpvOpTypeMatrix:
 +   case SpvOpTypeImage:
 +   case SpvOpTypeSampler:
 +   case SpvOpTypeSampledImage:
 +   case SpvOpTypeArray:
 +   case SpvOpTypeRuntimeArray:
 +   case SpvOpTypeStruct:
 +   case SpvOpTypeOpaque:
 +   case SpvOpTypePointer:
 +   case SpvOpTypeFunction:
 +   case SpvOpTypeEvent:
 +   case SpvOpTypeDeviceEvent:
 +   case SpvOpTypeReserveId:
 +   case SpvOpTypeQueue:
 +   case SpvOpTypePipe:
 +      vtn_handle_type(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpConstantTrue:
 +   case SpvOpConstantFalse:
 +   case SpvOpConstant:
 +   case SpvOpConstantComposite:
 +   case SpvOpConstantSampler:
 +   case SpvOpSpecConstantTrue:
 +   case SpvOpSpecConstantFalse:
 +   case SpvOpSpecConstant:
 +   case SpvOpSpecConstantComposite:
 +      vtn_handle_constant(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpVariable:
 +      vtn_handle_variables(b, opcode, w, count);
 +      break;
 +
 +   default:
 +      return false; /* End of preamble */
 +   }
 +
 +   return true;
 +}
 +
 +static bool
 +vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode,
 +                                      const uint32_t *w, unsigned count)
 +{
 +   switch (opcode) {
 +   case SpvOpFunction: {
 +      assert(b->func == NULL);
 +      b->func = rzalloc(b, struct vtn_function);
 +
 +      const struct glsl_type *result_type =
 +         vtn_value(b, w[1], vtn_value_type_type)->type->type;
 +      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function);
 +      const struct glsl_type *func_type =
 +         vtn_value(b, w[4], vtn_value_type_type)->type->type;
 +
 +      assert(glsl_get_function_return_type(func_type) == result_type);
 +
 +      nir_function *func =
 +         nir_function_create(b->shader, ralloc_strdup(b->shader, val->name));
 +
 +      nir_function_overload *overload = nir_function_overload_create(func);
 +      overload->num_params = glsl_get_length(func_type);
 +      overload->params = ralloc_array(overload, nir_parameter,
 +                                      overload->num_params);
 +      for (unsigned i = 0; i < overload->num_params; i++) {
 +         const struct glsl_function_param *param =
 +            glsl_get_function_param(func_type, i);
 +         overload->params[i].type = param->type;
 +         if (param->in) {
 +            if (param->out) {
 +               overload->params[i].param_type = nir_parameter_inout;
 +            } else {
 +               overload->params[i].param_type = nir_parameter_in;
 +            }
 +         } else {
 +            if (param->out) {
 +               overload->params[i].param_type = nir_parameter_out;
 +            } else {
 +               assert(!"Parameter is neither in nor out");
 +            }
 +         }
 +      }
 +      b->func->overload = overload;
 +      break;
 +   }
 +
 +   case SpvOpFunctionEnd:
 +      b->func->end = w;
 +      b->func = NULL;
 +      break;
 +
 +   case SpvOpFunctionParameter:
 +      break; /* Does nothing */
 +
 +   case SpvOpLabel: {
 +      assert(b->block == NULL);
 +      b->block = rzalloc(b, struct vtn_block);
 +      b->block->label = w;
 +      vtn_push_value(b, w[1], vtn_value_type_block)->block = b->block;
 +
 +      if (b->func->start_block == NULL) {
 +         /* This is the first block encountered for this function.  In this
 +          * case, we set the start block and add it to the list of
 +          * implemented functions that we'll walk later.
 +          */
 +         b->func->start_block = b->block;
 +         exec_list_push_tail(&b->functions, &b->func->node);
 +      }
 +      break;
 +   }
 +
 +   case SpvOpBranch:
 +   case SpvOpBranchConditional:
 +   case SpvOpSwitch:
 +   case SpvOpKill:
 +   case SpvOpReturn:
 +   case SpvOpReturnValue:
 +   case SpvOpUnreachable:
 +      assert(b->block);
 +      b->block->branch = w;
 +      b->block = NULL;
 +      break;
 +
 +   case SpvOpSelectionMerge:
 +   case SpvOpLoopMerge:
 +      assert(b->block && b->block->merge_op == SpvOpNop);
 +      b->block->merge_op = opcode;
 +      b->block->merge_block_id = w[1];
 +      break;
 +
 +   default:
 +      /* Continue on as per normal */
 +      return true;
 +   }
 +
 +   return true;
 +}
 +
 +static bool
 +vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
 +                            const uint32_t *w, unsigned count)
 +{
 +   switch (opcode) {
 +   case SpvOpLabel: {
 +      struct vtn_block *block = vtn_value(b, w[1], vtn_value_type_block)->block;
 +      assert(block->block == NULL);
 +
-          nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node);
-          struct exec_list *old_list = b->nb.cf_node_list;
++      block->block = nir_cursor_current_block(b->nb.cursor);
 +      break;
 +   }
 +
 +   case SpvOpLoopMerge:
 +   case SpvOpSelectionMerge:
 +      /* This is handled by cfg pre-pass and walk_blocks */
 +      break;
 +
 +   case SpvOpUndef:
 +      vtn_push_value(b, w[2], vtn_value_type_undef);
 +      break;
 +
 +   case SpvOpExtInst:
 +      vtn_handle_extension(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpVariable:
 +   case SpvOpLoad:
 +   case SpvOpStore:
 +   case SpvOpCopyMemory:
 +   case SpvOpCopyMemorySized:
 +   case SpvOpAccessChain:
 +   case SpvOpInBoundsAccessChain:
 +   case SpvOpArrayLength:
 +   case SpvOpImageTexelPointer:
 +      vtn_handle_variables(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpFunctionCall:
 +      vtn_handle_function_call(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpImageSampleImplicitLod:
 +   case SpvOpImageSampleExplicitLod: 
 +   case SpvOpImageSampleDrefImplicitLod: 
 +   case SpvOpImageSampleDrefExplicitLod: 
 +   case SpvOpImageSampleProjImplicitLod:
 +   case SpvOpImageSampleProjExplicitLod: 
 +   case SpvOpImageSampleProjDrefImplicitLod: 
 +   case SpvOpImageSampleProjDrefExplicitLod: 
 +   case SpvOpImageFetch:
 +   case SpvOpImageGather:
 +   case SpvOpImageDrefGather: 
 +   case SpvOpImageQuerySizeLod:
 +   case SpvOpImageQuerySize:
 +   case SpvOpImageQueryLod:
 +   case SpvOpImageQueryLevels:
 +   case SpvOpImageQuerySamples:
 +      vtn_handle_texture(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpSNegate:
 +   case SpvOpFNegate:
 +   case SpvOpNot:
 +   case SpvOpAny:
 +   case SpvOpAll:
 +   case SpvOpConvertFToU:
 +   case SpvOpConvertFToS:
 +   case SpvOpConvertSToF:
 +   case SpvOpConvertUToF:
 +   case SpvOpUConvert:
 +   case SpvOpSConvert:
 +   case SpvOpFConvert:
 +   case SpvOpConvertPtrToU:
 +   case SpvOpConvertUToPtr:
 +   case SpvOpPtrCastToGeneric:
 +   case SpvOpGenericCastToPtr:
 +   case SpvOpBitcast:
 +   case SpvOpIsNan:
 +   case SpvOpIsInf:
 +   case SpvOpIsFinite:
 +   case SpvOpIsNormal:
 +   case SpvOpSignBitSet:
 +   case SpvOpLessOrGreater:
 +   case SpvOpOrdered:
 +   case SpvOpUnordered:
 +   case SpvOpIAdd:
 +   case SpvOpFAdd:
 +   case SpvOpISub:
 +   case SpvOpFSub:
 +   case SpvOpIMul:
 +   case SpvOpFMul:
 +   case SpvOpUDiv:
 +   case SpvOpSDiv:
 +   case SpvOpFDiv:
 +   case SpvOpUMod:
 +   case SpvOpSRem:
 +   case SpvOpSMod:
 +   case SpvOpFRem:
 +   case SpvOpFMod:
 +   case SpvOpVectorTimesScalar:
 +   case SpvOpDot:
 +   case SpvOpShiftRightLogical:
 +   case SpvOpShiftRightArithmetic:
 +   case SpvOpShiftLeftLogical:
 +   case SpvOpLogicalOr:
 +   case SpvOpLogicalEqual:
 +   case SpvOpLogicalNotEqual:
 +   case SpvOpLogicalAnd:
 +   case SpvOpBitwiseOr:
 +   case SpvOpBitwiseXor:
 +   case SpvOpBitwiseAnd:
 +   case SpvOpSelect:
 +   case SpvOpIEqual:
 +   case SpvOpFOrdEqual:
 +   case SpvOpFUnordEqual:
 +   case SpvOpINotEqual:
 +   case SpvOpFOrdNotEqual:
 +   case SpvOpFUnordNotEqual:
 +   case SpvOpULessThan:
 +   case SpvOpSLessThan:
 +   case SpvOpFOrdLessThan:
 +   case SpvOpFUnordLessThan:
 +   case SpvOpUGreaterThan:
 +   case SpvOpSGreaterThan:
 +   case SpvOpFOrdGreaterThan:
 +   case SpvOpFUnordGreaterThan:
 +   case SpvOpULessThanEqual:
 +   case SpvOpSLessThanEqual:
 +   case SpvOpFOrdLessThanEqual:
 +   case SpvOpFUnordLessThanEqual:
 +   case SpvOpUGreaterThanEqual:
 +   case SpvOpSGreaterThanEqual:
 +   case SpvOpFOrdGreaterThanEqual:
 +   case SpvOpFUnordGreaterThanEqual:
 +   case SpvOpDPdx:
 +   case SpvOpDPdy:
 +   case SpvOpFwidth:
 +   case SpvOpDPdxFine:
 +   case SpvOpDPdyFine:
 +   case SpvOpFwidthFine:
 +   case SpvOpDPdxCoarse:
 +   case SpvOpDPdyCoarse:
 +   case SpvOpFwidthCoarse:
 +      vtn_handle_alu(b, opcode, w, count);
 +      break;
 +
 +   case SpvOpTranspose:
 +   case SpvOpOuterProduct:
 +   case SpvOpMatrixTimesScalar:
 +   case SpvOpVectorTimesMatrix:
 +   case SpvOpMatrixTimesVector:
 +   case SpvOpMatrixTimesMatrix:
 +      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");
 +   }
 +
 +   return true;
 +}
 +
 +static void
 +vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start,
 +                struct vtn_block *break_block, struct vtn_block *cont_block,
 +                struct vtn_block *end_block)
 +{
 +   struct vtn_block *block = start;
 +   while (block != end_block) {
 +      if (block->merge_op == SpvOpLoopMerge) {
 +         /* This is the jump into a loop. */
 +         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_builder_insert_after_cf_list(&b->nb, &loop->body);
++         nir_cf_node_insert(b->nb.cursor, &loop->cf_node);
 +
 +         /* Reset the merge_op to prerevent infinite recursion */
 +         block->merge_op = SpvOpNop;
 +
-          nir_builder_insert_after_cf_list(&b->nb, old_list);
++         b->nb.cursor = nir_after_cf_list(&loop->body);
 +         vtn_walk_blocks(b, block, new_break_block, new_cont_block, NULL);
 +
-       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);
++         b->nb.cursor = nir_after_cf_node(&loop->cf_node);
 +         block = new_break_block;
 +         continue;
 +      }
 +
 +      const uint32_t *w = block->branch;
 +      SpvOp branch_op = w[0] & SpvOpCodeMask;
 +
 +      b->block = block;
 +      vtn_foreach_instruction(b, block->label, block->branch,
 +                              vtn_handle_body_instruction);
 +
-          nir_cf_node_insert_end(b->nb.cf_node_list, &if_stmt->cf_node);
++      nir_block *cur_block = nir_cursor_current_block(b->nb.cursor);
++      assert(cur_block == block->block);
 +      _mesa_hash_table_insert(b->block_table, cur_block, block);
 +
 +      switch (branch_op) {
 +      case SpvOpBranch: {
 +         struct vtn_block *branch_block =
 +            vtn_value(b, w[1], vtn_value_type_block)->block;
 +
 +         if (branch_block == break_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_break);
 +            nir_builder_instr_insert(&b->nb, &jump->instr);
 +
 +            return;
 +         } else if (branch_block == cont_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_continue);
 +            nir_builder_instr_insert(&b->nb, &jump->instr);
 +
 +            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;
 +         }
 +      }
 +
 +      case SpvOpBranchConditional: {
 +         /* Gather up the branch blocks */
 +         struct vtn_block *then_block =
 +            vtn_value(b, w[2], vtn_value_type_block)->block;
 +         struct vtn_block *else_block =
 +            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])->def);
-             struct exec_list *old_list = b->nb.cf_node_list;
-             nir_builder_insert_after_cf_list(&b->nb, &if_stmt->then_list);
++         nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node);
 +
 +         if (then_block == break_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_break);
 +            nir_instr_insert_after_cf_list(&if_stmt->then_list,
 +                                           &jump->instr);
 +            block = else_block;
 +         } else if (else_block == break_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_break);
 +            nir_instr_insert_after_cf_list(&if_stmt->else_list,
 +                                           &jump->instr);
 +            block = then_block;
 +         } else if (then_block == cont_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_continue);
 +            nir_instr_insert_after_cf_list(&if_stmt->then_list,
 +                                           &jump->instr);
 +            block = else_block;
 +         } else if (else_block == cont_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_continue);
 +            nir_instr_insert_after_cf_list(&if_stmt->else_list,
 +                                           &jump->instr);
 +            block = then_block;
 +         } else {
 +            /* 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;
 +
-             nir_builder_insert_after_cf_list(&b->nb, &if_stmt->else_list);
++            b->nb.cursor = nir_after_cf_list(&if_stmt->then_list);
 +            vtn_walk_blocks(b, then_block, break_block, cont_block, merge_block);
 +
-             nir_builder_insert_after_cf_list(&b->nb, old_list);
++            b->nb.cursor = nir_after_cf_list(&if_stmt->else_list);
 +            vtn_walk_blocks(b, else_block, break_block, cont_block, merge_block);
 +
-       nir_builder_insert_after_cf_list(&b->nb, &b->impl->body);
++            b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node);
 +            block = merge_block;
 +            continue;
 +         }
 +
 +         /* If we got here then we inserted a predicated break or continue
 +          * above and we need to handle the other case.  We already set
 +          * `block` above to indicate what block to visit after the
 +          * predicated break.
 +          */
 +
 +         /* It's possible that the other branch is also a break/continue.
 +          * If it is, we handle that here.
 +          */
 +         if (block == break_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_break);
 +            nir_builder_instr_insert(&b->nb, &jump->instr);
 +
 +            return;
 +         } else if (block == cont_block) {
 +            nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                         nir_jump_continue);
 +            nir_builder_instr_insert(&b->nb, &jump->instr);
 +
 +            return;
 +         }
 +
 +         /* If we got here then there was a predicated break/continue but
 +          * the other half of the if has stuff in it.  `block` was already
 +          * set above so there is nothing left for us to do.
 +          */
 +         continue;
 +      }
 +
 +      case SpvOpReturn: {
 +         nir_jump_instr *jump = nir_jump_instr_create(b->shader,
 +                                                      nir_jump_return);
 +         nir_builder_instr_insert(&b->nb, &jump->instr);
 +         return;
 +      }
 +
 +      case SpvOpKill: {
 +         nir_intrinsic_instr *discard =
 +            nir_intrinsic_instr_create(b->shader, nir_intrinsic_discard);
 +         nir_builder_instr_insert(&b->nb, &discard->instr);
 +         return;
 +      }
 +
 +      case SpvOpSwitch:
 +      case SpvOpReturnValue:
 +      case SpvOpUnreachable:
 +      default:
 +         unreachable("Unhandled opcode");
 +      }
 +   }
 +}
 +
 +nir_shader *
 +spirv_to_nir(const uint32_t *words, size_t word_count,
 +             gl_shader_stage stage,
 +             const nir_shader_compiler_options *options)
 +{
 +   const uint32_t *word_end = words + word_count;
 +
 +   /* Handle the SPIR-V header (first 4 dwords)  */
 +   assert(word_count > 5);
 +
 +   assert(words[0] == SpvMagicNumber);
 +   assert(words[1] == 99);
 +   /* words[2] == generator magic */
 +   unsigned value_id_bound = words[3];
 +   assert(words[4] == 0);
 +
 +   words+= 5;
 +
 +   nir_shader *shader = nir_shader_create(NULL, stage, options);
 +
 +   /* Initialize the stn_builder object */
 +   struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);
 +   b->shader = shader;
 +   b->value_id_bound = value_id_bound;
 +   b->values = rzalloc_array(b, struct vtn_value, value_id_bound);
 +   exec_list_make_empty(&b->functions);
 +
 +   /* Handle all the preamble instructions */
 +   words = vtn_foreach_instruction(b, words, word_end,
 +                                   vtn_handle_preamble_instruction);
 +
 +   /* Do a very quick CFG analysis pass */
 +   vtn_foreach_instruction(b, words, word_end,
 +                           vtn_handle_first_cfg_pass_instruction);
 +
 +   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);
++      b->nb.cursor = nir_after_cf_list(&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);
 +   }
 +
 +   /* Because we can still have output reads in NIR, we need to lower
 +    * outputs to temporaries before we are truely finished.
 +    */
 +   nir_lower_outputs_to_temporaries(shader);
 +
 +   ralloc_free(b);
 +
 +   return shader;
 +}
index 3bbaf977bc5e978a15e55bc37bab1ec175a9e557,07fe1983ef28469e6aa1723f66583aaa65860865..f9dcdc735b338c991e0f094e570c4c83037455b5
@@@ -57,7 -57,6 +57,7 @@@
  # define GEN7_3DPRIM_VERTEXBUFFER_ACCESS_SEQUENTIAL (0 << 8)
  # define GEN7_3DPRIM_VERTEXBUFFER_ACCESS_RANDOM     (1 << 8)
  
 +#ifndef _3DPRIM_POINTLIST /* FIXME: Avoid clashing with defines from bdw_pack.h */
  #define _3DPRIM_POINTLIST         0x01
  #define _3DPRIM_LINELIST          0x02
  #define _3DPRIM_LINESTRIP         0x03
@@@ -79,7 -78,6 +79,7 @@@
  #define _3DPRIM_LINESTRIP_BF      0x13
  #define _3DPRIM_LINESTRIP_CONT_BF 0x14
  #define _3DPRIM_TRIFAN_NOSTIPPLE  0x15
 +#endif
  
  /* We use this offset to be able to pass native primitive types in struct
   * _mesa_prim::mode.  Native primitive types are BRW_PRIM_OFFSET +
  #define GEN8_SURFACE_TILING_W                       (1 << 12)
  #define GEN8_SURFACE_TILING_X                       (2 << 12)
  #define GEN8_SURFACE_TILING_Y                       (3 << 12)
+ #define GEN8_SURFACE_SAMPLER_L2_BYPASS_DISABLE      (1 << 9)
  #define BRW_SURFACE_RC_READ_WRITE     (1 << 8)
  #define BRW_SURFACE_MIPLAYOUT_SHIFT   10
  #define BRW_SURFACE_MIPMAPLAYOUT_BELOW   0
  #define BRW_SURFACEFORMAT_R8G8B8_UINT                    0x1C8
  #define BRW_SURFACEFORMAT_R8G8B8_SINT                    0x1C9
  #define BRW_SURFACEFORMAT_RAW                            0x1FF
+ #define GEN9_SURFACE_ASTC_HDR_FORMAT_BIT                 0x100
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_4x4_U8sRGB         0x200
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_5x4_U8sRGB         0x208
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_5x5_U8sRGB         0x209
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_6x5_U8sRGB         0x211
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_6x6_U8sRGB         0x212
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_8x5_U8sRGB         0x221
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_8x6_U8sRGB         0x222
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_8x8_U8sRGB         0x224
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x5_U8sRGB        0x231
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x6_U8sRGB        0x232
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x8_U8sRGB        0x234
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x10_U8sRGB       0x236
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_12x10_U8sRGB       0x23E
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_12x12_U8sRGB       0x23F
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_4x4_FLT16          0x240
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_5x4_FLT16          0x248
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_5x5_FLT16          0x249
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_6x5_FLT16          0x251
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_6x6_FLT16          0x252
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_8x5_FLT16          0x261
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_8x6_FLT16          0x262
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_8x8_FLT16          0x264
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x5_FLT16         0x271
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x6_FLT16         0x272
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x8_FLT16         0x274
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_10x10_FLT16        0x276
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_12x10_FLT16        0x27E
+ #define BRW_SURFACEFORMAT_ASTC_LDR_2D_12x12_FLT16        0x27F
  #define BRW_SURFACE_FORMAT_SHIFT      18
  #define BRW_SURFACE_FORMAT_MASK               INTEL_MASK(26, 18)
  
index 159f7161e1140c49e01e09f74b4bc77a96f9e4bb,269914d64a887e346f0d680e869c7e99033960d7..76530a476d6be39a35c562f088c774dfacb592ba
@@@ -427,7 -427,9 +427,9 @@@ fs_reg::equals(const fs_reg &r) cons
             negate == r.negate &&
             abs == r.abs &&
             !reladdr && !r.reladdr &&
-            memcmp(&fixed_hw_reg, &r.fixed_hw_reg, sizeof(fixed_hw_reg)) == 0 &&
+            ((file != HW_REG && file != IMM) ||
+             memcmp(&fixed_hw_reg, &r.fixed_hw_reg,
+                    sizeof(fixed_hw_reg)) == 0) &&
             stride == r.stride);
  }
  
@@@ -489,7 -491,6 +491,7 @@@ type_size_scalar(const struct glsl_typ
     case GLSL_TYPE_ERROR:
     case GLSL_TYPE_INTERFACE:
     case GLSL_TYPE_DOUBLE:
 +   case GLSL_TYPE_FUNCTION:
        unreachable("not reached");
     }
  
@@@ -1528,10 -1529,6 +1530,10 @@@ fs_visitor::assign_vs_urb_setup(
     unsigned vue_entries =
        MAX2(count, vs_prog_data->base.vue_map.num_slots);
  
 +   /* URB entry size is counted in units of 64 bytes (for the 3DSTATE_URB_VS
 +    * command).  Each attribute is 16 bytes (4 floats/dwords), so each unit
 +    * fits four attributes.
 +    */
     vs_prog_data->base.urb_entry_size = ALIGN(vue_entries, 4) / 4;
     vs_prog_data->base.urb_read_length = (count + 1) / 2;
  
@@@ -1789,57 -1786,49 +1791,49 @@@ fs_visitor::assign_constant_locations(
     if (dispatch_width != 8)
        return;
  
+    unsigned int num_pull_constants = 0;
     pull_constant_loc = ralloc_array(mem_ctx, int, uniforms);
     memset(pull_constant_loc, -1, sizeof(pull_constant_loc[0]) * uniforms);
  
-    /* Walk through and find array access of uniforms.  Put a copy of that
-     * uniform in the pull constant buffer.
+    bool is_live[uniforms];
+    memset(is_live, 0, sizeof(is_live));
+    /* First, we walk through the instructions and do two things:
+     *
+     *  1) Figure out which uniforms are live.
+     *
+     *  2) Find all indirect access of uniform arrays and flag them as needing
+     *     to go into the pull constant buffer.
      *
      * Note that we don't move constant-indexed accesses to arrays.  No
      * testing has been done of the performance impact of this choice.
      */
     foreach_block_and_inst_safe(block, fs_inst, inst, cfg) {
        for (int i = 0 ; i < inst->sources; i++) {
-          if (inst->src[i].file != UNIFORM || !inst->src[i].reladdr)
+          if (inst->src[i].file != UNIFORM)
              continue;
  
-          int uniform = inst->src[i].reg;
-          /* If this array isn't already present in the pull constant buffer,
-           * add it.
-           */
-          if (pull_constant_loc[uniform] == -1) {
-             const gl_constant_value **values = &stage_prog_data->param[uniform];
-             assert(param_size[uniform]);
-             for (int j = 0; j < param_size[uniform]; j++) {
-                pull_constant_loc[uniform + j] = stage_prog_data->nr_pull_params;
+          if (inst->src[i].reladdr) {
+             int uniform = inst->src[i].reg;
  
-                stage_prog_data->pull_param[stage_prog_data->nr_pull_params++] =
-                   values[j];
+             /* If this array isn't already present in the pull constant buffer,
+              * add it.
+              */
+             if (pull_constant_loc[uniform] == -1) {
+                assert(param_size[uniform]);
+                for (int j = 0; j < param_size[uniform]; j++)
+                   pull_constant_loc[uniform + j] = num_pull_constants++;
              }
+          } else {
+             /* Mark the the one accessed uniform as live */
+             int constant_nr = inst->src[i].reg + inst->src[i].reg_offset;
+             if (constant_nr >= 0 && constant_nr < (int) uniforms)
+                is_live[constant_nr] = true;
           }
        }
     }
  
-    /* Find which UNIFORM registers are still in use. */
-    bool is_live[uniforms];
-    for (unsigned int i = 0; i < uniforms; i++) {
-       is_live[i] = false;
-    }
-    foreach_block_and_inst(block, fs_inst, inst, cfg) {
-       for (int i = 0; i < inst->sources; i++) {
-          if (inst->src[i].file != UNIFORM)
-             continue;
-          int constant_nr = inst->src[i].reg + inst->src[i].reg_offset;
-          if (constant_nr >= 0 && constant_nr < (int) uniforms)
-             is_live[constant_nr] = true;
-       }
-    }
     /* Only allow 16 registers (128 uniform components) as push constants.
      *
      * Just demote the end of the list.  We could probably do better
        } else {
           /* Demote to a pull constant. */
           push_constant_loc[i] = -1;
-          int pull_index = stage_prog_data->nr_pull_params++;
-          stage_prog_data->pull_param[pull_index] = stage_prog_data->param[i];
-          pull_constant_loc[i] = pull_index;
+          pull_constant_loc[i] = num_pull_constants++;
        }
     }
  
     stage_prog_data->nr_params = num_push_constants;
+    stage_prog_data->nr_pull_params = num_pull_constants;
  
     /* Up until now, the param[] array has been indexed by reg + reg_offset
-     * of UNIFORM registers.  Condense it to only contain the uniforms we
-     * chose to upload as push constants.
+     * of UNIFORM registers.  Move pull constants into pull_param[] and
+     * condense param[] to only contain the uniforms we chose to push.
+     *
+     * NOTE: Because we are condensing the params[] array, we know that
+     * push_constant_loc[i] <= i and we can do it in one smooth loop without
+     * having to make a copy.
      */
     for (unsigned int i = 0; i < uniforms; i++) {
-       int remapped = push_constant_loc[i];
-       if (remapped == -1)
-          continue;
+       const gl_constant_value *value = stage_prog_data->param[i];
  
-       assert(remapped <= (int)i);
-       stage_prog_data->param[remapped] = stage_prog_data->param[i];
+       if (pull_constant_loc[i] != -1) {
+          stage_prog_data->pull_param[pull_constant_loc[i]] = value;
+       } else if (push_constant_loc[i] != -1) {
+          stage_prog_data->param[push_constant_loc[i]] = value;
+       }
     }
  }
  
@@@ -2650,22 -2641,9 +2646,22 @@@ fs_visitor::emit_repclear_shader(
     brw_wm_prog_key *key = (brw_wm_prog_key*) this->key;
     int base_mrf = 1;
     int color_mrf = base_mrf + 2;
 +   fs_inst *mov;
  
 -   fs_inst *mov = bld.exec_all().MOV(vec4(brw_message_reg(color_mrf)),
 -                                     fs_reg(UNIFORM, 0, BRW_REGISTER_TYPE_F));
 +   if (uniforms == 1) {
 +      mov = bld.exec_all().MOV(vec4(brw_message_reg(color_mrf)),
 +                               fs_reg(UNIFORM, 0, BRW_REGISTER_TYPE_F));
 +   } else {
 +      struct brw_reg reg =
 +         brw_reg(BRW_GENERAL_REGISTER_FILE,
 +                 2, 3, 0, 0, BRW_REGISTER_TYPE_F,
 +                 BRW_VERTICAL_STRIDE_8,
 +                 BRW_WIDTH_2,
 +                 BRW_HORIZONTAL_STRIDE_4, BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
 +
 +      mov = bld.exec_all().MOV(vec4(brw_message_reg(color_mrf)),
 +                               fs_reg(reg));
 +   }
  
     fs_inst *write;
     if (key->nr_color_regions == 1) {
     assign_curb_setup();
  
     /* Now that we have the uniform assigned, go ahead and force it to a vec4. */
 -   assert(mov->src[0].file == HW_REG);
 -   mov->src[0] = brw_vec4_grf(mov->src[0].fixed_hw_reg.nr, 0);
 +   if (uniforms == 1) {
 +      assert(mov->src[0].file == HW_REG);
 +      mov->src[0] = brw_vec4_grf(mov->src[0].fixed_hw_reg.nr, 0);
 +   }
  }
  
  /**
@@@ -4806,11 -4782,11 +4802,11 @@@ fs_visitor::optimize(
      */
     bld = fs_builder(this, 64);
  
-    split_virtual_grfs();
     assign_constant_locations();
     demote_pull_constants();
  
+    split_virtual_grfs();
  #define OPT(pass, args...) ({                                           \
        pass_num++;                                                       \
        bool this_progress = pass(args);                                  \
@@@ -4975,8 -4951,7 +4971,8 @@@ fs_visitor::run_vs(gl_clip_plane *clip_
  {
     assert(stage == MESA_SHADER_VERTEX);
  
 -   assign_common_binding_table_offsets(0);
 +   if (prog_data->map_entries == NULL)
 +      assign_common_binding_table_offsets(0);
     setup_vs_payload();
  
     if (shader_time_index >= 0)
@@@ -5015,8 -4990,9 +5011,8 @@@ fs_visitor::run_fs(bool do_rep_send
  
     assert(stage == MESA_SHADER_FRAGMENT);
  
 -   sanity_param_count = prog->Parameters->NumParameters;
 -
 -   assign_binding_table_offsets();
 +   if (prog_data->map_entries == NULL)
 +      assign_binding_table_offsets();
  
     if (devinfo->gen >= 6)
        setup_payload_gen6();
     else
        wm_prog_data->reg_blocks_16 = brw_register_blocks(grf_used);
  
 -   /* If any state parameters were appended, then ParameterValues could have
 -    * been realloced, in which case the driver uniform storage set up by
 -    * _mesa_associate_uniform_storage() would point to freed memory.  Make
 -    * sure that didn't happen.
 -    */
 -   assert(sanity_param_count == prog->Parameters->NumParameters);
 -
     return !failed;
  }
  
@@@ -5158,7 -5141,7 +5154,7 @@@ brw_wm_fs_emit(struct brw_context *brw
     if (prog)
        shader = (brw_shader *) prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
  
 -   if (unlikely(INTEL_DEBUG & DEBUG_WM))
 +   if (unlikely(INTEL_DEBUG & DEBUG_WM) && shader->base.ir)
        brw_dump_ir("fragment", prog, &shader->base, &fp->Base);
  
     int st_index8 = -1, st_index16 = -1;
index cd2b850581e52ab109ce2cc9d4ff0c9b7bd5ceba,9929dd6a42f4428fb6bb2eb7e5b6f5187ca1bac8..da8d47f1c5ec7d5599ddc8898bc5d2770c650b5d
@@@ -42,8 -42,7 +42,8 @@@ fs_visitor::emit_nir_code(
      */
     nir_setup_inputs(nir);
     nir_setup_outputs(nir);
 -   nir_setup_uniforms(nir);
 +   uniforms = nir->num_uniforms;
 +   //nir_setup_uniforms(nir);
     nir_emit_system_values(nir);
  
     /* get the main function and emit it */
@@@ -132,7 -131,7 +132,7 @@@ fs_visitor::nir_setup_outputs(nir_shade
  
        switch (stage) {
        case MESA_SHADER_VERTEX:
-          for (int i = 0; i < ALIGN(type_size_scalar(var->type), 4) / 4; i++) {
+          for (unsigned int i = 0; i < ALIGN(type_size_scalar(var->type), 4) / 4; i++) {
              int output = var->data.location + i;
              this->outputs[output] = offset(reg, bld, 4 * i);
              this->output_components[output] = vector_elements;
@@@ -191,8 -190,8 +191,8 @@@ fs_visitor::nir_setup_uniforms(nir_shad
              nir_setup_builtin_uniform(var);
           else
              nir_setup_uniform(var);
-          param_size[var->data.driver_location] = type_size_scalar(var->type);
+          if(type_size_scalar(var->type) > 0)
+             param_size[var->data.driver_location] = type_size_scalar(var->type);
        }
     } else {
        /* prog_to_nir only creates a single giant uniform variable so we can
                 &prog->Parameters->ParameterValues[p][i];
           }
        }
-       param_size[0] = prog->Parameters->NumParameters * 4;
+       if(prog->Parameters->NumParameters > 0)
+          param_size[0] = prog->Parameters->NumParameters * 4;
     }
  }
  
@@@ -416,8 -416,6 +417,6 @@@ fs_visitor::nir_emit_if(nir_if *if_stmt
     nir_emit_cf_list(&if_stmt->else_list);
  
     bld.emit(BRW_OPCODE_ENDIF);
-    try_replace_with_sel();
  }
  
  void
@@@ -1517,22 -1515,13 +1516,22 @@@ fs_visitor::nir_emit_intrinsic(const fs
        has_indirect = true;
        /* fallthrough */
     case nir_intrinsic_load_ubo: {
 +      uint32_t set = instr->const_index[0];
        nir_const_value *const_index = nir_src_as_const_value(instr->src[0]);
        fs_reg surf_index;
  
        if (const_index) {
 -         surf_index = fs_reg(stage_prog_data->binding_table.ubo_start +
 -                             const_index->u[0]);
 +         uint32_t binding = const_index->u[0];
 +
 +         /* FIXME: We should probably assert here, but dota2 seems to hit
 +          * it and we'd like to keep going.
 +          */
 +         if (binding >= stage_prog_data->bind_map[set].index_count)
 +            binding = 0;
 +
 +         surf_index = fs_reg(stage_prog_data->bind_map[set].index[binding]);
        } else {
 +         assert(0 && "need more info from the ir for this.");
           /* The block index is not a constant. Evaluate the index expression
            * per-channel and add the base UBO index; we have to select a value
            * from any live channel.
                                       BRW_REGISTER_TYPE_D),
                   fs_reg(2));
  
 -         unsigned vec4_offset = instr->const_index[0] / 4;
 +         unsigned vec4_offset = instr->const_index[1] / 4;
           for (int i = 0; i < instr->num_components; i++)
              VARYING_PULL_CONSTANT_LOAD(bld, offset(dest, bld, i), surf_index,
                                         base_offset, vec4_offset + i);
           fs_reg packed_consts = vgrf(glsl_type::float_type);
           packed_consts.type = dest.type;
  
 -         fs_reg const_offset_reg((unsigned) instr->const_index[0] & ~15);
 +         fs_reg const_offset_reg((unsigned) instr->const_index[1] & ~15);
           bld.emit(FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD, packed_consts,
                    surf_index, const_offset_reg);
  
  void
  fs_visitor::nir_emit_texture(const fs_builder &bld, nir_tex_instr *instr)
  {
 -   unsigned sampler = instr->sampler_index;
 +   uint32_t set = instr->sampler_set;
 +   uint32_t binding = instr->sampler_index;
 +
 +   assert(binding < stage_prog_data->bind_map[set].index_count);
 +   assert(stage_prog_data->bind_map[set].index[binding] < 1000);
 +
 +   unsigned sampler = stage_prog_data->bind_map[set].index[binding];
     fs_reg sampler_reg(sampler);
  
     /* FINISHME: We're failing to recompile our programs when the sampler is
@@@ -1914,12 -1897,6 +1913,12 @@@ fs_visitor::nir_emit_jump(const fs_buil
        bld.emit(BRW_OPCODE_CONTINUE);
        break;
     case nir_jump_return:
 +      /* This has to be the last block in the shader.  We don't handle
 +       * early returns.
 +       */
 +      assert(nir_cf_node_next(&instr->instr.block->cf_node) == NULL &&
 +             instr->instr.block->cf_node.parent->type == nir_cf_node_function);
 +      break;
     default:
        unreachable("unknown jump");
     }
index 0276d47c4d401136f6ec639a1c622cc1b78a990a,247b223f2e2cb42adcd078f3eca176b071753808..4c8602a108572265cb1eacedd247599ecaa2b0f8
@@@ -63,6 -63,8 +63,8 @@@ nir_optimize(nir_shader *nir, bool is_s
        nir_validate_shader(nir);
        progress |= nir_opt_remove_phis(nir);
        nir_validate_shader(nir);
+       progress |= nir_opt_undef(nir);
+       nir_validate_shader(nir);
     } while (progress);
  }
  
@@@ -77,6 -79,7 +79,6 @@@ brw_create_nir(struct brw_context *brw
     const nir_shader_compiler_options *options =
        ctx->Const.ShaderCompilerOptions[stage].NirOptions;
     struct gl_shader *shader = shader_prog ? shader_prog->_LinkedShaders[stage] : NULL;
 -   bool debug_enabled = INTEL_DEBUG & intel_debug_flag_for_shader_stage(stage);
     nir_shader *nir;
  
     /* First, lower the GLSL IR or Mesa IR to NIR */
     }
     nir_validate_shader(nir);
  
 +   brw_process_nir(nir, brw->intelScreen->devinfo, shader_prog, stage, is_scalar);
 +
 +   static GLuint msg_id = 0;
 +   _mesa_gl_debug(&brw->ctx, &msg_id,
 +                  MESA_DEBUG_SOURCE_SHADER_COMPILER,
 +                  MESA_DEBUG_TYPE_OTHER,
 +                  MESA_DEBUG_SEVERITY_NOTIFICATION,
 +                  "%s NIR shader:\n",
 +                  _mesa_shader_stage_to_abbrev(stage));
 +
 +   return nir;
 +}
 +
 +void
 +brw_process_nir(nir_shader *nir,
 +                const struct brw_device_info *devinfo,
 +                const struct gl_shader_program *shader_prog,
 +                gl_shader_stage stage, bool is_scalar)
 +{
 +   bool debug_enabled = INTEL_DEBUG & intel_debug_flag_for_shader_stage(stage);
 +
     nir_lower_global_vars_to_local(nir);
     nir_validate_shader(nir);
  
  
     if (shader_prog) {
        nir_lower_samplers(nir, shader_prog);
 -      nir_validate_shader(nir);
 +   } else {
 +      nir_lower_samplers_for_vk(nir);
     }
 +   nir_validate_shader(nir);
  
     nir_lower_system_values(nir);
     nir_validate_shader(nir);
  
     nir_optimize(nir, is_scalar);
  
 -   if (brw->gen >= 6) {
 +   if (devinfo->gen >= 6) {
        /* Try and fuse multiply-adds */
        nir_opt_peephole_ffma(nir);
        nir_validate_shader(nir);
      * run it last because it stashes data in instr->pass_flags and we don't
      * want that to be squashed by other NIR passes.
      */
 -   if (brw->gen <= 5)
 +   if (devinfo->gen <= 5)
        brw_nir_analyze_boolean_resolves(nir);
  
     nir_sweep(nir);
                _mesa_shader_stage_to_string(stage));
        nir_print_shader(nir, stderr);
     }
 -
 -   return nir;
  }
  
  enum brw_reg_type
index 63f75da7e99f7437b498d91d5f4592fcfb010f34,b97b6c13a13d3646504a37cd0cd231ce63086964..5e528b5c5a19c5d3cc3dd5b1ee6e2f7fdb27f7b5
@@@ -216,8 -216,9 +216,9 @@@ dst_reg::equals(const dst_reg &r) cons
             writemask == r.writemask &&
             (reladdr == r.reladdr ||
              (reladdr && r.reladdr && reladdr->equals(*r.reladdr))) &&
-            memcmp(&fixed_hw_reg, &r.fixed_hw_reg,
-                   sizeof(fixed_hw_reg)) == 0);
+            ((file != HW_REG && file != IMM) ||
+             memcmp(&fixed_hw_reg, &r.fixed_hw_reg,
+                    sizeof(fixed_hw_reg)) == 0));
  }
  
  bool
@@@ -1916,7 -1917,7 +1917,7 @@@ brw_vs_emit(struct brw_context *brw
     if (INTEL_DEBUG & DEBUG_SHADER_TIME)
        st_index = brw_get_shader_time_index(brw, prog, &vp->Base, ST_VS);
  
 -   if (unlikely(INTEL_DEBUG & DEBUG_VS))
 +   if (unlikely(INTEL_DEBUG & DEBUG_VS) && shader->base.ir)
        brw_dump_ir("vertex", prog, &shader->base, &vp->Base);
  
     if (!vp->Base.nir &&
index 58f41bfd55dd842f231e489a77abbf4e454ffb9f,b3b3c21f491df8379bf0b36dc1d0b99b85cc8cf5..6bd55d395b2272cb2e2d4f769c4c9417b27fbbcd
@@@ -60,7 -60,7 +60,7 @@@ static const struct dri_debug_control d
     { "urb",         DEBUG_URB },
     { "vs",          DEBUG_VS },
     { "clip",        DEBUG_CLIP },
 -   { "aub",         DEBUG_AUB },
 +   { "foob",        DEBUG_AUB }, /* disable aub dumbing in the dri driver */
     { "shader_time", DEBUG_SHADER_TIME },
     { "no16",        DEBUG_NO16 },
     { "blorp",       DEBUG_BLORP },
@@@ -68,7 -68,7 +68,7 @@@
     { "optimizer",   DEBUG_OPTIMIZER },
     { "ann",         DEBUG_ANNOTATION },
     { "no8",         DEBUG_NO8 },
-    { "vec4vs",      DEBUG_VEC4VS },
+    { "vec4",        DEBUG_VEC4VS },
     { "spill",       DEBUG_SPILL },
     { "cs",          DEBUG_CS },
     { NULL,    0 }
diff --combined src/mesa/main/mtypes.h
index 4883cbc93d5aba4e857e9dfe1f29b37b7de9c699,a172952c1fbfb01fe1f0cc72fe7e86b8a1d2aa66..4e88494c387ab7bac542571dc7f7611717aa96fa
@@@ -94,6 -94,113 +94,6 @@@ struct vbo_context
  #define PRIM_OUTSIDE_BEGIN_END   (PRIM_MAX + 1)
  #define PRIM_UNKNOWN             (PRIM_MAX + 2)
  
 -/**
 - * Indexes for vertex program attributes.
 - * GL_NV_vertex_program aliases generic attributes over the conventional
 - * attributes.  In GL_ARB_vertex_program shader the aliasing is optional.
 - * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the
 - * generic attributes are distinct/separate).
 - */
 -typedef enum
 -{
 -   VERT_ATTRIB_POS = 0,
 -   VERT_ATTRIB_WEIGHT = 1,
 -   VERT_ATTRIB_NORMAL = 2,
 -   VERT_ATTRIB_COLOR0 = 3,
 -   VERT_ATTRIB_COLOR1 = 4,
 -   VERT_ATTRIB_FOG = 5,
 -   VERT_ATTRIB_COLOR_INDEX = 6,
 -   VERT_ATTRIB_EDGEFLAG = 7,
 -   VERT_ATTRIB_TEX0 = 8,
 -   VERT_ATTRIB_TEX1 = 9,
 -   VERT_ATTRIB_TEX2 = 10,
 -   VERT_ATTRIB_TEX3 = 11,
 -   VERT_ATTRIB_TEX4 = 12,
 -   VERT_ATTRIB_TEX5 = 13,
 -   VERT_ATTRIB_TEX6 = 14,
 -   VERT_ATTRIB_TEX7 = 15,
 -   VERT_ATTRIB_POINT_SIZE = 16,
 -   VERT_ATTRIB_GENERIC0 = 17,
 -   VERT_ATTRIB_GENERIC1 = 18,
 -   VERT_ATTRIB_GENERIC2 = 19,
 -   VERT_ATTRIB_GENERIC3 = 20,
 -   VERT_ATTRIB_GENERIC4 = 21,
 -   VERT_ATTRIB_GENERIC5 = 22,
 -   VERT_ATTRIB_GENERIC6 = 23,
 -   VERT_ATTRIB_GENERIC7 = 24,
 -   VERT_ATTRIB_GENERIC8 = 25,
 -   VERT_ATTRIB_GENERIC9 = 26,
 -   VERT_ATTRIB_GENERIC10 = 27,
 -   VERT_ATTRIB_GENERIC11 = 28,
 -   VERT_ATTRIB_GENERIC12 = 29,
 -   VERT_ATTRIB_GENERIC13 = 30,
 -   VERT_ATTRIB_GENERIC14 = 31,
 -   VERT_ATTRIB_GENERIC15 = 32,
 -   VERT_ATTRIB_MAX = 33
 -} gl_vert_attrib;
 -
 -/**
 - * Symbolic constats to help iterating over
 - * specific blocks of vertex attributes.
 - *
 - * VERT_ATTRIB_FF
 - *   includes all fixed function attributes as well as
 - *   the aliased GL_NV_vertex_program shader attributes.
 - * VERT_ATTRIB_TEX
 - *   include the classic texture coordinate attributes.
 - *   Is a subset of VERT_ATTRIB_FF.
 - * VERT_ATTRIB_GENERIC
 - *   include the OpenGL 2.0+ GLSL generic shader attributes.
 - *   These alias the generic GL_ARB_vertex_shader attributes.
 - */
 -#define VERT_ATTRIB_FF(i)           (VERT_ATTRIB_POS + (i))
 -#define VERT_ATTRIB_FF_MAX          VERT_ATTRIB_GENERIC0
 -
 -#define VERT_ATTRIB_TEX(i)          (VERT_ATTRIB_TEX0 + (i))
 -#define VERT_ATTRIB_TEX_MAX         MAX_TEXTURE_COORD_UNITS
 -
 -#define VERT_ATTRIB_GENERIC(i)      (VERT_ATTRIB_GENERIC0 + (i))
 -#define VERT_ATTRIB_GENERIC_MAX     MAX_VERTEX_GENERIC_ATTRIBS
 -
 -/**
 - * Bitflags for vertex attributes.
 - * These are used in bitfields in many places.
 - */
 -/*@{*/
 -#define VERT_BIT_POS             BITFIELD64_BIT(VERT_ATTRIB_POS)
 -#define VERT_BIT_WEIGHT          BITFIELD64_BIT(VERT_ATTRIB_WEIGHT)
 -#define VERT_BIT_NORMAL          BITFIELD64_BIT(VERT_ATTRIB_NORMAL)
 -#define VERT_BIT_COLOR0          BITFIELD64_BIT(VERT_ATTRIB_COLOR0)
 -#define VERT_BIT_COLOR1          BITFIELD64_BIT(VERT_ATTRIB_COLOR1)
 -#define VERT_BIT_FOG             BITFIELD64_BIT(VERT_ATTRIB_FOG)
 -#define VERT_BIT_COLOR_INDEX     BITFIELD64_BIT(VERT_ATTRIB_COLOR_INDEX)
 -#define VERT_BIT_EDGEFLAG        BITFIELD64_BIT(VERT_ATTRIB_EDGEFLAG)
 -#define VERT_BIT_TEX0            BITFIELD64_BIT(VERT_ATTRIB_TEX0)
 -#define VERT_BIT_TEX1            BITFIELD64_BIT(VERT_ATTRIB_TEX1)
 -#define VERT_BIT_TEX2            BITFIELD64_BIT(VERT_ATTRIB_TEX2)
 -#define VERT_BIT_TEX3            BITFIELD64_BIT(VERT_ATTRIB_TEX3)
 -#define VERT_BIT_TEX4            BITFIELD64_BIT(VERT_ATTRIB_TEX4)
 -#define VERT_BIT_TEX5            BITFIELD64_BIT(VERT_ATTRIB_TEX5)
 -#define VERT_BIT_TEX6            BITFIELD64_BIT(VERT_ATTRIB_TEX6)
 -#define VERT_BIT_TEX7            BITFIELD64_BIT(VERT_ATTRIB_TEX7)
 -#define VERT_BIT_POINT_SIZE      BITFIELD64_BIT(VERT_ATTRIB_POINT_SIZE)
 -#define VERT_BIT_GENERIC0        BITFIELD64_BIT(VERT_ATTRIB_GENERIC0)
 -
 -#define VERT_BIT(i)              BITFIELD64_BIT(i)
 -#define VERT_BIT_ALL             BITFIELD64_RANGE(0, VERT_ATTRIB_MAX)
 -
 -#define VERT_BIT_FF(i)           VERT_BIT(i)
 -#define VERT_BIT_FF_ALL          BITFIELD64_RANGE(0, VERT_ATTRIB_FF_MAX)
 -#define VERT_BIT_TEX(i)          VERT_BIT(VERT_ATTRIB_TEX(i))
 -#define VERT_BIT_TEX_ALL         \
 -   BITFIELD64_RANGE(VERT_ATTRIB_TEX(0), VERT_ATTRIB_TEX_MAX)
 -
 -#define VERT_BIT_GENERIC(i)      VERT_BIT(VERT_ATTRIB_GENERIC(i))
 -#define VERT_BIT_GENERIC_ALL     \
 -   BITFIELD64_RANGE(VERT_ATTRIB_GENERIC(0), VERT_ATTRIB_GENERIC_MAX)
 -/*@}*/
 -
 -
  #define VARYING_SLOT_MAX      (VARYING_SLOT_VAR0 + MAX_VARYING)
  #define VARYING_SLOT_PATCH0   (VARYING_SLOT_MAX)
  #define VARYING_SLOT_TESS_MAX (VARYING_SLOT_PATCH0 + MAX_VARYING)
@@@ -2473,11 -2580,6 +2473,11 @@@ struct gl_uniform_bloc
      */
     GLuint Binding;
  
 +   /**
 +    * Vulkan descriptor set qualifier for this block.
 +    */
 +   GLuint Set;
 +
     /**
      * Minimum size (in bytes) of a buffer object to back this uniform buffer
      * (GL_UNIFORM_BLOCK_DATA_SIZE).
@@@ -3751,6 -3853,8 +3751,8 @@@ struct gl_extension
     GLboolean ATI_fragment_shader;
     GLboolean ATI_separate_stencil;
     GLboolean INTEL_performance_query;
+    GLboolean KHR_texture_compression_astc_hdr;
+    GLboolean KHR_texture_compression_astc_ldr;
     GLboolean MESA_pack_invert;
     GLboolean MESA_ycbcr_texture;
     GLboolean NV_conditional_render;