+static struct vtn_ssa_value *
+vtn_nir_select(struct vtn_builder *b, struct vtn_ssa_value *src0,
+ struct vtn_ssa_value *src1, struct vtn_ssa_value *src2)
+{
+ struct vtn_ssa_value *dest = rzalloc(b, struct vtn_ssa_value);
+ dest->type = src1->type;
+
+ if (glsl_type_is_vector_or_scalar(src1->type)) {
+ dest->def = nir_bcsel(&b->nb, src0->def, src1->def, src2->def);
+ } else {
+ unsigned elems = glsl_get_length(src1->type);
+
+ dest->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+ for (unsigned i = 0; i < elems; i++) {
+ dest->elems[i] = vtn_nir_select(b, src0,
+ src1->elems[i], src2->elems[i]);
+ }
+ }
+
+ return dest;
+}
+
+static void
+vtn_handle_select(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count)
+{
+ /* Handle OpSelect up-front here because it needs to be able to handle
+ * pointers and not just regular vectors and scalars.
+ */
+ struct vtn_value *res_val = vtn_untyped_value(b, w[2]);
+ struct vtn_value *cond_val = vtn_untyped_value(b, w[3]);
+ struct vtn_value *obj1_val = vtn_untyped_value(b, w[4]);
+ struct vtn_value *obj2_val = vtn_untyped_value(b, w[5]);
+
+ vtn_fail_if(obj1_val->type != res_val->type ||
+ obj2_val->type != res_val->type,
+ "Object types must match the result type in OpSelect");
+
+ vtn_fail_if((cond_val->type->base_type != vtn_base_type_scalar &&
+ cond_val->type->base_type != vtn_base_type_vector) ||
+ !glsl_type_is_boolean(cond_val->type->type),
+ "OpSelect must have either a vector of booleans or "
+ "a boolean as Condition type");
+
+ vtn_fail_if(cond_val->type->base_type == vtn_base_type_vector &&
+ (res_val->type->base_type != vtn_base_type_vector ||
+ res_val->type->length != cond_val->type->length),
+ "When Condition type in OpSelect is a vector, the Result "
+ "type must be a vector of the same length");
+
+ switch (res_val->type->base_type) {
+ case vtn_base_type_scalar:
+ case vtn_base_type_vector:
+ case vtn_base_type_matrix:
+ case vtn_base_type_array:
+ case vtn_base_type_struct:
+ /* OK. */
+ break;
+ case vtn_base_type_pointer:
+ /* We need to have actual storage for pointer types. */
+ vtn_fail_if(res_val->type->type == NULL,
+ "Invalid pointer result type for OpSelect");
+ break;
+ default:
+ vtn_fail("Result type of OpSelect must be a scalar, composite, or pointer");
+ }
+
+ struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
+ struct vtn_ssa_value *ssa = vtn_nir_select(b,
+ vtn_ssa_value(b, w[3]), vtn_ssa_value(b, w[4]), vtn_ssa_value(b, w[5]));
+
+ vtn_push_ssa(b, w[2], res_type, ssa);
+}
+
+static void
+vtn_handle_ptr(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count)
+{
+ struct vtn_type *type1 = vtn_untyped_value(b, w[3])->type;
+ struct vtn_type *type2 = vtn_untyped_value(b, w[4])->type;
+ vtn_fail_if(type1->base_type != vtn_base_type_pointer ||
+ type2->base_type != vtn_base_type_pointer,
+ "%s operands must have pointer types",
+ spirv_op_to_string(opcode));
+ vtn_fail_if(type1->storage_class != type2->storage_class,
+ "%s operands must have the same storage class",
+ spirv_op_to_string(opcode));
+
+ struct vtn_type *vtn_type =
+ vtn_value(b, w[1], vtn_value_type_type)->type;
+ const struct glsl_type *type = vtn_type->type;
+
+ nir_address_format addr_format = vtn_mode_to_address_format(
+ b, vtn_storage_class_to_mode(b, type1->storage_class, NULL, NULL));
+
+ nir_ssa_def *def;
+
+ switch (opcode) {
+ case SpvOpPtrDiff: {
+ /* OpPtrDiff returns the difference in number of elements (not byte offset). */
+ unsigned elem_size, elem_align;
+ glsl_get_natural_size_align_bytes(type1->deref->type,
+ &elem_size, &elem_align);
+
+ def = nir_build_addr_isub(&b->nb,
+ vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ addr_format);
+ def = nir_idiv(&b->nb, def, nir_imm_intN_t(&b->nb, elem_size, def->bit_size));
+ def = nir_i2i(&b->nb, def, glsl_get_bit_size(type));
+ break;
+ }
+
+ case SpvOpPtrEqual:
+ case SpvOpPtrNotEqual: {
+ def = nir_build_addr_ieq(&b->nb,
+ vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ addr_format);
+ if (opcode == SpvOpPtrNotEqual)
+ def = nir_inot(&b->nb, def);
+ break;
+ }
+
+ default:
+ unreachable("Invalid ptr operation");
+ }
+
+ struct vtn_ssa_value *ssa_value = vtn_create_ssa_value(b, type);
+ ssa_value->def = def;
+ vtn_push_ssa(b, w[2], vtn_type, ssa_value);
+}
+