spirv: Move OpSelect handling to a function

This will make a later change easier to review.

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
This commit is contained in:
Caio Marcelo de Oliveira Filho 2019-06-03 15:30:33 -07:00
parent ea0e89859c
commit 17630291e5

View file

@ -4084,6 +4084,70 @@ vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode,
return true;
}
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 *sel_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]);
const struct glsl_type *sel_type;
switch (res_val->type->base_type) {
case vtn_base_type_scalar:
sel_type = glsl_bool_type();
break;
case vtn_base_type_vector:
sel_type = glsl_vector_type(GLSL_TYPE_BOOL, res_val->type->length);
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");
sel_type = glsl_bool_type();
break;
default:
vtn_fail("Result type of OpSelect must be a scalar, vector, or pointer");
}
if (unlikely(sel_val->type->type != sel_type)) {
if (sel_val->type->type == glsl_bool_type()) {
/* This case is illegal but some older versions of GLSLang produce
* it. The GLSLang issue was fixed on March 30, 2017:
*
* https://github.com/KhronosGroup/glslang/issues/809
*
* Unfortunately, there are applications in the wild which are
* shipping with this bug so it isn't nice to fail on them so we
* throw a warning instead. It's not actually a problem for us as
* nir_builder will just splat the condition out which is most
* likely what the client wanted anyway.
*/
vtn_warn("Condition type of OpSelect must have the same number "
"of components as Result Type");
} else {
vtn_fail("Condition type of OpSelect must be a scalar or vector "
"of Boolean type. It must have the same number of "
"components as Result Type");
}
}
vtn_fail_if(obj1_val->type != res_val->type ||
obj2_val->type != res_val->type,
"Object types must match the result type in OpSelect");
struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, res_type->type);
ssa->def = nir_bcsel(&b->nb, vtn_ssa_value(b, w[3])->def,
vtn_ssa_value(b, w[4])->def,
vtn_ssa_value(b, w[5])->def);
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)
@ -4258,67 +4322,9 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
break;
}
case SpvOpSelect: {
/* 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 *sel_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]);
const struct glsl_type *sel_type;
switch (res_val->type->base_type) {
case vtn_base_type_scalar:
sel_type = glsl_bool_type();
break;
case vtn_base_type_vector:
sel_type = glsl_vector_type(GLSL_TYPE_BOOL, res_val->type->length);
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");
sel_type = glsl_bool_type();
break;
default:
vtn_fail("Result type of OpSelect must be a scalar, vector, or pointer");
}
if (unlikely(sel_val->type->type != sel_type)) {
if (sel_val->type->type == glsl_bool_type()) {
/* This case is illegal but some older versions of GLSLang produce
* it. The GLSLang issue was fixed on March 30, 2017:
*
* https://github.com/KhronosGroup/glslang/issues/809
*
* Unfortunately, there are applications in the wild which are
* shipping with this bug so it isn't nice to fail on them so we
* throw a warning instead. It's not actually a problem for us as
* nir_builder will just splat the condition out which is most
* likely what the client wanted anyway.
*/
vtn_warn("Condition type of OpSelect must have the same number "
"of components as Result Type");
} else {
vtn_fail("Condition type of OpSelect must be a scalar or vector "
"of Boolean type. It must have the same number of "
"components as Result Type");
}
}
vtn_fail_if(obj1_val->type != res_val->type ||
obj2_val->type != res_val->type,
"Object types must match the result type in OpSelect");
struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, res_type->type);
ssa->def = nir_bcsel(&b->nb, vtn_ssa_value(b, w[3])->def,
vtn_ssa_value(b, w[4])->def,
vtn_ssa_value(b, w[5])->def);
vtn_push_ssa(b, w[2], res_type, ssa);
case SpvOpSelect:
vtn_handle_select(b, opcode, w, count);
break;
}
case SpvOpSNegate:
case SpvOpFNegate: