zink: implement some more trivial opcodes
[mesa.git] / src / gallium / drivers / zink / nir_to_spirv / nir_to_spirv.c
index d2001eb7de28aa0f003b390e0f316a2fcb4377f5..09312dae406c2eb67a4135d91c7d737929713b20 100644 (file)
@@ -35,7 +35,6 @@ struct ntv_context {
    SpvId GLSL_std_450;
 
    gl_shader_stage stage;
-   int var_location;
 
    SpvId ubos[128];
    size_t num_ubos;
@@ -56,15 +55,21 @@ struct ntv_context {
    size_t num_blocks;
    bool block_started;
    SpvId loop_break, loop_cont;
+
+   SpvId front_face_var;
 };
 
 static SpvId
-get_fvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
-                  const float values[]);
+get_fvec_constant(struct ntv_context *ctx, unsigned bit_size,
+                  unsigned num_components, float value);
+
+static SpvId
+get_uvec_constant(struct ntv_context *ctx, unsigned bit_size,
+                  unsigned num_components, uint32_t value);
 
 static SpvId
-get_uvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
-                  const uint32_t values[]);
+get_ivec_constant(struct ntv_context *ctx, unsigned bit_size,
+                  unsigned num_components, int32_t value);
 
 static SpvId
 emit_unop(struct ntv_context *ctx, SpvOp op, SpvId type, SpvId src);
@@ -96,6 +101,27 @@ block_label(struct ntv_context *ctx, nir_block *block)
    return ctx->block_ids[block->index];
 }
 
+static SpvId
+emit_float_const(struct ntv_context *ctx, int bit_size, float value)
+{
+   assert(bit_size == 32);
+   return spirv_builder_const_float(&ctx->builder, bit_size, value);
+}
+
+static SpvId
+emit_uint_const(struct ntv_context *ctx, int bit_size, uint32_t value)
+{
+   assert(bit_size == 32);
+   return spirv_builder_const_uint(&ctx->builder, bit_size, value);
+}
+
+static SpvId
+emit_int_const(struct ntv_context *ctx, int bit_size, int32_t value)
+{
+   assert(bit_size == 32);
+   return spirv_builder_const_int(&ctx->builder, bit_size, value);
+}
+
 static SpvId
 get_fvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
 {
@@ -113,9 +139,9 @@ get_fvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_component
 static SpvId
 get_ivec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
 {
-   assert(bit_size == 32); // only 32-bit ints supported so far
+   assert(bit_size == 1 || bit_size == 32); // only 32-bit ints supported so far
 
-   SpvId int_type = spirv_builder_type_int(&ctx->builder, bit_size);
+   SpvId int_type = spirv_builder_type_int(&ctx->builder, MAX2(bit_size, 32));
    if (num_components > 1)
       return spirv_builder_type_vector(&ctx->builder, int_type,
                                        num_components);
@@ -127,9 +153,9 @@ get_ivec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_component
 static SpvId
 get_uvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
 {
-   assert(bit_size == 32); // only 32-bit uints supported so far
+   assert(bit_size == 1 || bit_size == 32); // only 32-bit uints supported so far
 
-   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
+   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, MAX2(bit_size, 32));
    if (num_components > 1)
       return spirv_builder_type_vector(&ctx->builder, uint_type,
                                        num_components);
@@ -149,6 +175,9 @@ static SpvId
 get_glsl_basetype(struct ntv_context *ctx, enum glsl_base_type type)
 {
    switch (type) {
+   case GLSL_TYPE_BOOL:
+      return spirv_builder_type_bool(&ctx->builder);
+
    case GLSL_TYPE_FLOAT:
       return spirv_builder_type_float(&ctx->builder, 32);
 
@@ -179,7 +208,7 @@ get_glsl_type(struct ntv_context *ctx, const struct glsl_type *type)
    if (glsl_type_is_array(type)) {
       SpvId ret = spirv_builder_type_array(&ctx->builder,
          get_glsl_type(ctx, glsl_get_array_element(type)),
-         spirv_builder_const_uint(&ctx->builder, 32, glsl_get_length(type)));
+         emit_uint_const(ctx, 32, glsl_get_length(type)));
       uint32_t stride = glsl_get_explicit_stride(type);
       if (stride)
          spirv_builder_emit_array_stride(&ctx->builder, ret, stride);
@@ -204,11 +233,17 @@ emit_input(struct ntv_context *ctx, struct nir_variable *var)
       spirv_builder_emit_name(&ctx->builder, var_id, var->name);
 
    if (ctx->stage == MESA_SHADER_FRAGMENT) {
-      if (var->data.location >= VARYING_SLOT_VAR0 ||
-          (var->data.location >= VARYING_SLOT_COL0 &&
-           var->data.location <= VARYING_SLOT_TEX7)) {
+      if (var->data.location >= VARYING_SLOT_VAR0)
+         spirv_builder_emit_location(&ctx->builder, var_id,
+                                     var->data.location -
+                                     VARYING_SLOT_VAR0 +
+                                     VARYING_SLOT_TEX0);
+      else if ((var->data.location >= VARYING_SLOT_COL0 &&
+                var->data.location <= VARYING_SLOT_TEX7) ||
+               var->data.location == VARYING_SLOT_BFC0 ||
+               var->data.location == VARYING_SLOT_BFC1) {
          spirv_builder_emit_location(&ctx->builder, var_id,
-                                     ctx->var_location++);
+                                     var->data.location);
       } else {
          switch (var->data.location) {
          case VARYING_SLOT_POS:
@@ -256,11 +291,17 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
 
 
    if (ctx->stage == MESA_SHADER_VERTEX) {
-      if (var->data.location >= VARYING_SLOT_VAR0 ||
-          (var->data.location >= VARYING_SLOT_COL0 &&
-           var->data.location <= VARYING_SLOT_TEX7)) {
+      if (var->data.location >= VARYING_SLOT_VAR0)
          spirv_builder_emit_location(&ctx->builder, var_id,
-                                     ctx->var_location++);
+                                     var->data.location -
+                                     VARYING_SLOT_VAR0 +
+                                     VARYING_SLOT_TEX0);
+      else if ((var->data.location >= VARYING_SLOT_COL0 &&
+                var->data.location <= VARYING_SLOT_TEX7) ||
+               var->data.location == VARYING_SLOT_BFC0 ||
+               var->data.location == VARYING_SLOT_BFC1) {
+         spirv_builder_emit_location(&ctx->builder, var_id,
+                                     var->data.location);
       } else {
          switch (var->data.location) {
          case VARYING_SLOT_POS:
@@ -321,12 +362,16 @@ type_to_dim(enum glsl_sampler_dim gdim, bool *is_ms)
       return SpvDim1D;
    case GLSL_SAMPLER_DIM_2D:
       return SpvDim2D;
-   case GLSL_SAMPLER_DIM_RECT:
-      return SpvDimRect;
-   case GLSL_SAMPLER_DIM_CUBE:
-      return SpvDimCube;
    case GLSL_SAMPLER_DIM_3D:
       return SpvDim3D;
+   case GLSL_SAMPLER_DIM_CUBE:
+      return SpvDimCube;
+   case GLSL_SAMPLER_DIM_RECT:
+      return SpvDimRect;
+   case GLSL_SAMPLER_DIM_BUF:
+      return SpvDimBuffer;
+   case GLSL_SAMPLER_DIM_EXTERNAL:
+      return SpvDim2D; /* seems dodgy... */
    case GLSL_SAMPLER_DIM_MS:
       *is_ms = true;
       return SpvDim2D;
@@ -371,7 +416,7 @@ emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
 {
    uint32_t size = glsl_count_attribute_slots(var->type, false);
    SpvId vec4_type = get_uvec_type(ctx, 32, 4);
-   SpvId array_length = spirv_builder_const_uint(&ctx->builder, 32, size);
+   SpvId array_length = emit_uint_const(ctx, 32, size);
    SpvId array_type = spirv_builder_type_array(&ctx->builder, vec4_type,
                                                array_length);
    spirv_builder_emit_array_stride(&ctx->builder, array_type, 16);
@@ -484,9 +529,9 @@ get_alu_src_uint(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
       return def;
 
    int bit_size = nir_src_bit_size(alu->src[src].src);
-   assert(bit_size == 32);
+   assert(bit_size == 1 || bit_size == 32);
 
-   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
+   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, MAX2(bit_size, 32));
    if (used_channels == 1) {
       uint32_t indices[] =  { alu->src[src].swizzle[0] };
       return spirv_builder_emit_composite_extract(&ctx->builder, uint_type,
@@ -529,34 +574,42 @@ store_ssa_def_uint(struct ntv_context *ctx, nir_ssa_def *ssa, SpvId result)
    ctx->defs[ssa->index] = result;
 }
 
+static SpvId
+emit_select(struct ntv_context *ctx, SpvId type, SpvId cond,
+            SpvId if_true, SpvId if_false)
+{
+   return emit_triop(ctx, SpvOpSelect, type, cond, if_true, if_false);
+}
+
 static SpvId
 bvec_to_uvec(struct ntv_context *ctx, SpvId value, unsigned num_components)
 {
    SpvId otype = get_uvec_type(ctx, 32, num_components);
-   uint32_t zeros[4] = { 0, 0, 0, 0 };
-   uint32_t ones[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
-   SpvId zero = get_uvec_constant(ctx, 32, num_components, zeros);
-   SpvId one = get_uvec_constant(ctx, 32, num_components, ones);
-   return emit_triop(ctx, SpvOpSelect, otype, value, one, zero);
+   SpvId zero = get_uvec_constant(ctx, 32, num_components, 0);
+   SpvId one = get_uvec_constant(ctx, 32, num_components, UINT32_MAX);
+   return emit_select(ctx, otype, value, one, zero);
 }
 
 static SpvId
 uvec_to_bvec(struct ntv_context *ctx, SpvId value, unsigned num_components)
 {
    SpvId type = get_bvec_type(ctx, num_components);
-
-   uint32_t zeros[NIR_MAX_VEC_COMPONENTS] = { 0 };
-   SpvId zero = get_uvec_constant(ctx, 32, num_components, zeros);
-
+   SpvId zero = get_uvec_constant(ctx, 32, num_components, 0);
    return emit_binop(ctx, SpvOpINotEqual, type, value, zero);
 }
 
+static SpvId
+emit_bitcast(struct ntv_context *ctx, SpvId type, SpvId value)
+{
+   return emit_unop(ctx, SpvOpBitcast, type, value);
+}
+
 static SpvId
 bitcast_to_uvec(struct ntv_context *ctx, SpvId value, unsigned bit_size,
                 unsigned num_components)
 {
    SpvId type = get_uvec_type(ctx, bit_size, num_components);
-   return emit_unop(ctx, SpvOpBitcast, type, value);
+   return emit_bitcast(ctx, type, value);
 }
 
 static SpvId
@@ -564,7 +617,7 @@ bitcast_to_ivec(struct ntv_context *ctx, SpvId value, unsigned bit_size,
                 unsigned num_components)
 {
    SpvId type = get_ivec_type(ctx, bit_size, num_components);
-   return emit_unop(ctx, SpvOpBitcast, type, value);
+   return emit_bitcast(ctx, type, value);
 }
 
 static SpvId
@@ -572,7 +625,7 @@ bitcast_to_fvec(struct ntv_context *ctx, SpvId value, unsigned bit_size,
                unsigned num_components)
 {
    SpvId type = get_fvec_type(ctx, bit_size, num_components);
-   return emit_unop(ctx, SpvOpBitcast, type, value);
+   return emit_bitcast(ctx, type, value);
 }
 
 static void
@@ -658,45 +711,72 @@ emit_builtin_binop(struct ntv_context *ctx, enum GLSLstd450 op, SpvId type,
 }
 
 static SpvId
-get_fvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
-                  const float values[])
+emit_builtin_triop(struct ntv_context *ctx, enum GLSLstd450 op, SpvId type,
+                   SpvId src0, SpvId src1, SpvId src2)
+{
+   SpvId args[] = { src0, src1, src2 };
+   return spirv_builder_emit_ext_inst(&ctx->builder, type, ctx->GLSL_std_450,
+                                      op, args, ARRAY_SIZE(args));
+}
+
+static SpvId
+get_fvec_constant(struct ntv_context *ctx, unsigned bit_size,
+                  unsigned num_components, float value)
 {
    assert(bit_size == 32);
 
-   if (num_components > 1) {
-      SpvId components[num_components];
-      for (int i = 0; i < num_components; i++)
-         components[i] = spirv_builder_const_float(&ctx->builder, bit_size,
-                                                   values[i]);
+   SpvId result = emit_float_const(ctx, bit_size, value);
+   if (num_components == 1)
+      return result;
 
-      SpvId type = get_fvec_type(ctx, bit_size, num_components);
-      return spirv_builder_const_composite(&ctx->builder, type, components,
-                                           num_components);
-   }
+   assert(num_components > 1);
+   SpvId components[num_components];
+   for (int i = 0; i < num_components; i++)
+      components[i] = result;
 
-   assert(num_components == 1);
-   return spirv_builder_const_float(&ctx->builder, bit_size, values[0]);
+   SpvId type = get_fvec_type(ctx, bit_size, num_components);
+   return spirv_builder_const_composite(&ctx->builder, type, components,
+                                        num_components);
 }
 
 static SpvId
-get_uvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
-                  const uint32_t values[])
+get_uvec_constant(struct ntv_context *ctx, unsigned bit_size,
+                  unsigned num_components, uint32_t value)
 {
    assert(bit_size == 32);
 
-   if (num_components > 1) {
-      SpvId components[num_components];
-      for (int i = 0; i < num_components; i++)
-         components[i] = spirv_builder_const_uint(&ctx->builder, bit_size,
-                                                  values[i]);
+   SpvId result = emit_uint_const(ctx, bit_size, value);
+   if (num_components == 1)
+      return result;
 
-      SpvId type = get_uvec_type(ctx, bit_size, num_components);
-      return spirv_builder_const_composite(&ctx->builder, type, components,
-                                           num_components);
-   }
+   assert(num_components > 1);
+   SpvId components[num_components];
+   for (int i = 0; i < num_components; i++)
+      components[i] = result;
 
-   assert(num_components == 1);
-   return spirv_builder_const_uint(&ctx->builder, bit_size, values[0]);
+   SpvId type = get_uvec_type(ctx, bit_size, num_components);
+   return spirv_builder_const_composite(&ctx->builder, type, components,
+                                        num_components);
+}
+
+static SpvId
+get_ivec_constant(struct ntv_context *ctx, unsigned bit_size,
+                  unsigned num_components, int32_t value)
+{
+   assert(bit_size == 32);
+
+   SpvId result = emit_int_const(ctx, bit_size, value);
+   if (num_components == 1)
+      return result;
+
+   assert(num_components > 1);
+   SpvId components[num_components];
+   for (int i = 0; i < num_components; i++)
+      components[i] = result;
+
+   SpvId type = get_ivec_type(ctx, bit_size, num_components);
+   return spirv_builder_const_composite(&ctx->builder, type, components,
+                                        num_components);
 }
 
 static inline unsigned
@@ -803,14 +883,30 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    UNOP(nir_op_f2u32, SpvOpConvertFToU)
    UNOP(nir_op_i2f32, SpvOpConvertSToF)
    UNOP(nir_op_u2f32, SpvOpConvertUToF)
+   UNOP(nir_op_inot, SpvOpNot)
 #undef UNOP
 
+   case nir_op_b2i32:
+      assert(nir_op_infos[alu->op].num_inputs == 1);
+      result = emit_select(ctx, dest_type, src[0],
+                           get_ivec_constant(ctx, 32, num_components, 1),
+                           get_ivec_constant(ctx, 32, num_components, 0));
+      break;
+
+   case nir_op_b2f32:
+      assert(nir_op_infos[alu->op].num_inputs == 1);
+      result = emit_select(ctx, dest_type, src[0],
+                           get_fvec_constant(ctx, 32, num_components, 1),
+                           get_fvec_constant(ctx, 32, num_components, 0));
+      break;
+
 #define BUILTIN_UNOP(nir_op, spirv_op) \
    case nir_op: \
       assert(nir_op_infos[alu->op].num_inputs == 1); \
       result = emit_builtin_unop(ctx, spirv_op, dest_type, src[0]); \
       break;
 
+   BUILTIN_UNOP(nir_op_iabs, GLSLstd450SAbs)
    BUILTIN_UNOP(nir_op_fabs, GLSLstd450FAbs)
    BUILTIN_UNOP(nir_op_fsqrt, GLSLstd450Sqrt)
    BUILTIN_UNOP(nir_op_frsq, GLSLstd450InverseSqrt)
@@ -826,22 +922,20 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BUILTIN_UNOP(nir_op_fcos, GLSLstd450Cos)
 #undef BUILTIN_UNOP
 
-   case nir_op_frcp: {
+   case nir_op_frcp:
       assert(nir_op_infos[alu->op].num_inputs == 1);
-      float one[4] = { 1, 1, 1, 1 };
-      src[1] = src[0];
-      src[0] = get_fvec_constant(ctx, bit_size, num_components, one);
-      result = emit_binop(ctx, SpvOpFDiv, dest_type, src[0], src[1]);
-      }
+      result = emit_binop(ctx, SpvOpFDiv, dest_type,
+                          get_fvec_constant(ctx, bit_size, num_components, 1),
+                          src[0]);
       break;
 
-   case nir_op_f2b1: {
+   case nir_op_f2b1:
       assert(nir_op_infos[alu->op].num_inputs == 1);
-      float values[NIR_MAX_VEC_COMPONENTS] = { 0 };
-      SpvId zero = get_fvec_constant(ctx, nir_src_bit_size(alu->src[0].src),
-                                     num_components, values);
-      result = emit_binop(ctx, SpvOpFOrdNotEqual, dest_type, src[0], zero);
-      break;
+      result = emit_binop(ctx, SpvOpFOrdNotEqual, dest_type, src[0],
+                          get_fvec_constant(ctx,
+                                            nir_src_bit_size(alu->src[0].src),
+                                            num_components, 0));
+      break;
 
 
 #define BINOP(nir_op, spirv_op) \
@@ -855,6 +949,7 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BINOP(nir_op_imul, SpvOpIMul)
    BINOP(nir_op_idiv, SpvOpSDiv)
    BINOP(nir_op_udiv, SpvOpUDiv)
+   BINOP(nir_op_umod, SpvOpUMod)
    BINOP(nir_op_fadd, SpvOpFAdd)
    BINOP(nir_op_fsub, SpvOpFSub)
    BINOP(nir_op_fmul, SpvOpFMul)
@@ -864,6 +959,7 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BINOP(nir_op_ige, SpvOpSGreaterThanEqual)
    BINOP(nir_op_ieq, SpvOpIEqual)
    BINOP(nir_op_ine, SpvOpINotEqual)
+   BINOP(nir_op_uge, SpvOpUGreaterThanEqual)
    BINOP(nir_op_flt, SpvOpFOrdLessThan)
    BINOP(nir_op_fge, SpvOpFOrdGreaterThanEqual)
    BINOP(nir_op_feq, SpvOpFOrdEqual)
@@ -871,6 +967,8 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BINOP(nir_op_ishl, SpvOpShiftLeftLogical)
    BINOP(nir_op_ishr, SpvOpShiftRightArithmetic)
    BINOP(nir_op_ushr, SpvOpShiftRightLogical)
+   BINOP(nir_op_iand, SpvOpBitwiseAnd)
+   BINOP(nir_op_ior, SpvOpBitwiseOr)
 #undef BINOP
 
 #define BUILTIN_BINOP(nir_op, spirv_op) \
@@ -898,8 +996,8 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
       int num_components = nir_dest_num_components(alu->dest.dest);
       SpvId bool_type = get_bvec_type(ctx, num_components);
 
-      SpvId zero = spirv_builder_const_float(&ctx->builder, 32, 0.0f);
-      SpvId one = spirv_builder_const_float(&ctx->builder, 32, 1.0f);
+      SpvId zero = emit_float_const(ctx, bit_size, 0.0f);
+      SpvId one = emit_float_const(ctx, bit_size, 1.0f);
       if (num_components > 1) {
          SpvId zero_comps[num_components], one_comps[num_components];
          for (int i = 0; i < num_components; i++) {
@@ -923,22 +1021,77 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
       }
 
       result = emit_binop(ctx, op, bool_type, src[0], src[1]);
-      result = emit_triop(ctx, SpvOpSelect, dest_type, result, one, zero);
+      result = emit_select(ctx, dest_type, result, one, zero);
       }
       break;
 
-   case nir_op_fcsel: {
+   case nir_op_flrp:
       assert(nir_op_infos[alu->op].num_inputs == 3);
-      int num_components = nir_dest_num_components(alu->dest.dest);
-      SpvId bool_type = get_bvec_type(ctx, num_components);
+      result = emit_builtin_triop(ctx, GLSLstd450FMix, dest_type,
+                                  src[0], src[1], src[2]);
+      break;
+
+   case nir_op_fcsel:
+      result = emit_binop(ctx, SpvOpFOrdGreaterThan,
+                          get_bvec_type(ctx, num_components),
+                          src[0],
+                          get_fvec_constant(ctx,
+                                            nir_src_bit_size(alu->src[0].src),
+                                            num_components, 0));
+      result = emit_select(ctx, dest_type, result, src[1], src[2]);
+      break;
 
-      float zero[4] = { 0, 0, 0, 0 };
-      SpvId cmp = get_fvec_constant(ctx, nir_src_bit_size(alu->src[0].src),
-                                         num_components, zero);
+   case nir_op_bcsel:
+      assert(nir_op_infos[alu->op].num_inputs == 3);
+      result = emit_select(ctx, dest_type, src[0], src[1], src[2]);
+      break;
 
-      result = emit_binop(ctx, SpvOpFOrdGreaterThan, bool_type, src[0], cmp);
-      result = emit_triop(ctx, SpvOpSelect, dest_type, result, src[1], src[2]);
-      }
+   case nir_op_bany_fnequal2:
+   case nir_op_bany_fnequal3:
+   case nir_op_bany_fnequal4:
+      assert(nir_op_infos[alu->op].num_inputs == 2);
+      assert(alu_instr_src_components(alu, 0) ==
+             alu_instr_src_components(alu, 1));
+      result = emit_binop(ctx, SpvOpFOrdNotEqual,
+                          get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+                          src[0], src[1]);
+      result = emit_unop(ctx, SpvOpAny, dest_type, result);
+      break;
+
+   case nir_op_ball_fequal2:
+   case nir_op_ball_fequal3:
+   case nir_op_ball_fequal4:
+      assert(nir_op_infos[alu->op].num_inputs == 2);
+      assert(alu_instr_src_components(alu, 0) ==
+             alu_instr_src_components(alu, 1));
+      result = emit_binop(ctx, SpvOpFOrdEqual,
+                          get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+                          src[0], src[1]);
+      result = emit_unop(ctx, SpvOpAll, dest_type, result);
+      break;
+
+   case nir_op_bany_inequal2:
+   case nir_op_bany_inequal3:
+   case nir_op_bany_inequal4:
+      assert(nir_op_infos[alu->op].num_inputs == 2);
+      assert(alu_instr_src_components(alu, 0) ==
+             alu_instr_src_components(alu, 1));
+      result = emit_binop(ctx, SpvOpINotEqual,
+                          get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+                          src[0], src[1]);
+      result = emit_unop(ctx, SpvOpAny, dest_type, result);
+      break;
+
+   case nir_op_ball_iequal2:
+   case nir_op_ball_iequal3:
+   case nir_op_ball_iequal4:
+      assert(nir_op_infos[alu->op].num_inputs == 2);
+      assert(alu_instr_src_components(alu, 0) ==
+             alu_instr_src_components(alu, 1));
+      result = emit_binop(ctx, SpvOpIEqual,
+                          get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+                          src[0], src[1]);
+      result = emit_unop(ctx, SpvOpAll, dest_type, result);
       break;
 
    case nir_op_vec2:
@@ -965,13 +1118,40 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
 static void
 emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
 {
-   uint32_t values[NIR_MAX_VEC_COMPONENTS];
-   for (int i = 0; i < load_const->def.num_components; ++i)
-      values[i] = load_const->value[i].u32;
+   unsigned bit_size = load_const->def.bit_size;
+   unsigned num_components = load_const->def.num_components;
+
+   SpvId constant;
+   if (num_components > 1) {
+      SpvId components[num_components];
+      SpvId type;
+      if (bit_size == 1) {
+         for (int i = 0; i < num_components; i++)
+            components[i] = spirv_builder_const_bool(&ctx->builder,
+                                                     load_const->value[i].b);
+
+         type = get_bvec_type(ctx, num_components);
+      } else {
+         for (int i = 0; i < num_components; i++)
+            components[i] = emit_uint_const(ctx, bit_size,
+                                            load_const->value[i].u32);
+
+         type = get_uvec_type(ctx, bit_size, num_components);
+      }
+      constant = spirv_builder_const_composite(&ctx->builder, type,
+                                               components, num_components);
+   } else {
+      assert(num_components == 1);
+      if (bit_size == 1)
+         constant = spirv_builder_const_bool(&ctx->builder,
+                                             load_const->value[0].b);
+      else
+         constant = emit_uint_const(ctx, bit_size, load_const->value[0].u32);
+   }
+
+   if (bit_size == 1)
+      constant = bvec_to_uvec(ctx, constant, num_components);
 
-   SpvId constant = get_uvec_constant(ctx, load_const->def.bit_size,
-                                           load_const->def.num_components,
-                                           values);
    store_ssa_def_uint(ctx, &load_const->def, constant);
 }
 
@@ -990,8 +1170,8 @@ emit_load_ubo(struct ntv_context *ctx, nir_intrinsic_instr *intr)
                                                       uvec4_type);
 
       unsigned idx = const_offset->u32;
-      SpvId member = spirv_builder_const_uint(&ctx->builder, 32, 0);
-      SpvId offset = spirv_builder_const_uint(&ctx->builder, 32, idx);
+      SpvId member = emit_uint_const(ctx, 32, 0);
+      SpvId offset = emit_uint_const(ctx, 32, idx);
       SpvId offsets[] = { member, offset };
       SpvId ptr = spirv_builder_emit_access_chain(&ctx->builder, pointer_type,
                                                   ctx->ubos[0], offsets,
@@ -1060,12 +1240,38 @@ emit_store_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
    SpvId src = get_src_uint(ctx, &intr->src[1]);
 
    nir_variable *var = nir_intrinsic_get_var(intr, 0);
-   SpvId result = emit_unop(ctx, SpvOpBitcast,
-                            get_glsl_type(ctx, glsl_without_array(var->type)),
-                            src);
+   SpvId type = get_glsl_type(ctx, glsl_without_array(var->type));
+   SpvId result = emit_bitcast(ctx, type, src);
    spirv_builder_emit_store(&ctx->builder, ptr, result);
 }
 
+static void
+emit_load_front_face(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+   SpvId var_type = get_glsl_type(ctx, glsl_bool_type());
+   if (!ctx->front_face_var) {
+      SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
+                                                      SpvStorageClassInput,
+                                                      var_type);
+      ctx->front_face_var = spirv_builder_emit_var(&ctx->builder,
+                                                   pointer_type,
+                                                   SpvStorageClassInput);
+      spirv_builder_emit_name(&ctx->builder, ctx->front_face_var,
+                              "gl_FrontFacing");
+      spirv_builder_emit_builtin(&ctx->builder, ctx->front_face_var,
+                                 SpvBuiltInFrontFacing);
+
+      assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
+      ctx->entry_ifaces[ctx->num_entry_ifaces++] = ctx->front_face_var;
+   }
+
+   SpvId result = spirv_builder_emit_load(&ctx->builder, var_type,
+                                          ctx->front_face_var);
+   assert(1 == nir_dest_num_components(intr->dest));
+   result = bvec_to_uvec(ctx, result, 1);
+   store_dest_uint(ctx, &intr->dest, result);
+}
+
 static void
 emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
@@ -1086,6 +1292,10 @@ emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
       emit_store_deref(ctx, intr);
       break;
 
+   case nir_intrinsic_load_front_face:
+      emit_load_front_face(ctx, intr);
+      break;
+
    default:
       fprintf(stderr, "emit_intrinsic: not implemented (%s)\n",
               nir_intrinsic_infos[intr->intrinsic].name);
@@ -1112,21 +1322,35 @@ get_src_float(struct ntv_context *ctx, nir_src *src)
    return bitcast_to_fvec(ctx, def, bit_size, num_components);
 }
 
+static SpvId
+get_src_int(struct ntv_context *ctx, nir_src *src)
+{
+   SpvId def = get_src_uint(ctx, src);
+   unsigned num_components = nir_src_num_components(*src);
+   unsigned bit_size = nir_src_bit_size(*src);
+   return bitcast_to_ivec(ctx, def, bit_size, num_components);
+}
+
 static void
 emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 {
    assert(tex->op == nir_texop_tex ||
           tex->op == nir_texop_txb ||
-          tex->op == nir_texop_txl);
+          tex->op == nir_texop_txl ||
+          tex->op == nir_texop_txd ||
+          tex->op == nir_texop_txf);
    assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
    assert(tex->texture_index == tex->sampler_index);
 
-   SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0;
-   unsigned coord_components;
+   SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0, dx = 0, dy = 0;
+   unsigned coord_components = 0;
    for (unsigned i = 0; i < tex->num_srcs; i++) {
       switch (tex->src[i].src_type) {
       case nir_tex_src_coord:
-         coord = get_src_float(ctx, &tex->src[i].src);
+         if (tex->op == nir_texop_txf)
+            coord = get_src_int(ctx, &tex->src[i].src);
+         else
+            coord = get_src_float(ctx, &tex->src[i].src);
          coord_components = nir_src_num_components(tex->src[i].src);
          break;
 
@@ -1144,7 +1368,10 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 
       case nir_tex_src_lod:
          assert(nir_src_num_components(tex->src[i].src) == 1);
-         lod = get_src_float(ctx, &tex->src[i].src);
+         if (tex->op == nir_texop_txf)
+            lod = get_src_int(ctx, &tex->src[i].src);
+         else
+            lod = get_src_float(ctx, &tex->src[i].src);
          assert(lod != 0);
          break;
 
@@ -1154,6 +1381,16 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
          assert(dref != 0);
          break;
 
+      case nir_tex_src_ddx:
+         dx = get_src_float(ctx, &tex->src[i].src);
+         assert(dx != 0);
+         break;
+
+      case nir_tex_src_ddy:
+         dy = get_src_float(ctx, &tex->src[i].src);
+         assert(dy != 0);
+         break;
+
       default:
          fprintf(stderr, "texture source: %d\n", tex->src[i].src_type);
          unreachable("unknown texture source");
@@ -1161,7 +1398,7 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
    }
 
    if (lod == 0 && ctx->stage != MESA_SHADER_FRAGMENT) {
-      lod = spirv_builder_const_float(&ctx->builder, 32, 0);
+      lod = emit_float_const(ctx, 32, 0.0f);
       assert(lod != 0);
    }
 
@@ -1207,11 +1444,19 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
    if (dref)
       actual_dest_type = float_type;
 
-   SpvId result = spirv_builder_emit_image_sample(&ctx->builder,
-                                                  actual_dest_type, load,
-                                                  coord,
-                                                  proj != 0,
-                                                  lod, bias, dref);
+   SpvId result;
+   if (tex->op == nir_texop_txf) {
+      SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load);
+      result = spirv_builder_emit_image_fetch(&ctx->builder, dest_type,
+                                              image, coord, lod);
+   } else {
+      result = spirv_builder_emit_image_sample(&ctx->builder,
+                                               actual_dest_type, load,
+                                               coord,
+                                               proj != 0,
+                                               lod, bias, dref, dx, dy);
+   }
+
    spirv_builder_emit_decoration(&ctx->builder, result,
                                  SpvDecorationRelaxedPrecision);
 
@@ -1385,7 +1630,7 @@ static SpvId
 get_src_bool(struct ntv_context *ctx, nir_src *src)
 {
    SpvId def = get_src_uint(ctx, src);
-   assert(nir_src_bit_size(*src) == 32);
+   assert(nir_src_bit_size(*src) == 1);
    unsigned num_components = nir_src_num_components(*src);
    return uvec_to_bvec(ctx, def, num_components);
 }
@@ -1558,9 +1803,6 @@ nir_to_spirv(struct nir_shader *s)
    nir_foreach_variable(var, &s->uniforms)
       emit_uniform(&ctx, var);
 
-   spirv_builder_emit_entry_point(&ctx.builder, exec_model, entry_point,
-                                  "main", ctx.entry_ifaces,
-                                  ctx.num_entry_ifaces);
    if (s->info.stage == MESA_SHADER_FRAGMENT) {
       spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
                                    SpvExecutionModeOriginUpperLeft);
@@ -1618,6 +1860,10 @@ nir_to_spirv(struct nir_shader *s)
    spirv_builder_return(&ctx.builder); // doesn't belong here, but whatevz
    spirv_builder_function_end(&ctx.builder);
 
+   spirv_builder_emit_entry_point(&ctx.builder, exec_model, entry_point,
+                                  "main", ctx.entry_ifaces,
+                                  ctx.num_entry_ifaces);
+
    size_t num_words = spirv_builder_get_num_words(&ctx.builder);
 
    ret = CALLOC_STRUCT(spirv_shader);