spirv: Handle all OpenCL conversion ops with full rounding

This is done for kernels via the new convert_alu_types intrinsic.  For
Vulkan and OpenGL, we maintain the old path so that drivers don't have
to add that lowering pass.

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6945>
This commit is contained in:
Jason Ekstrand
2020-09-30 16:43:31 -05:00
committed by Marge Bot
parent 8e8458218c
commit 8610af12b6
2 changed files with 77 additions and 14 deletions
+2
View File
@@ -5135,6 +5135,8 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
case SpvOpSConvert:
case SpvOpFConvert:
case SpvOpQuantizeToF16:
case SpvOpSatConvertSToU:
case SpvOpSatConvertUToS:
case SpvOpPtrCastToGeneric:
case SpvOpGenericCastToPtr:
case SpvOpIsNan:
+75 -14
View File
@@ -220,9 +220,11 @@ convert_op_src_type(SpvOp opcode)
return nir_type_float;
case SpvOpSConvert:
case SpvOpConvertSToF:
case SpvOpSatConvertSToU:
return nir_type_int;
case SpvOpUConvert:
case SpvOpConvertUToF:
case SpvOpSatConvertUToS:
return nir_type_uint;
default:
unreachable("Unhandled conversion op");
@@ -239,9 +241,11 @@ convert_op_dst_type(SpvOp opcode)
return nir_type_float;
case SpvOpSConvert:
case SpvOpConvertFToS:
case SpvOpSatConvertUToS:
return nir_type_int;
case SpvOpUConvert:
case SpvOpConvertFToU:
case SpvOpSatConvertSToU:
return nir_type_uint;
default:
unreachable("Unhandled conversion op");
@@ -386,6 +390,14 @@ vtn_rounding_mode_to_nir(struct vtn_builder *b, SpvFPRoundingMode mode)
return nir_rounding_mode_rtne;
case SpvFPRoundingModeRTZ:
return nir_rounding_mode_rtz;
case SpvFPRoundingModeRTP:
vtn_fail_if(b->shader->info.stage != MESA_SHADER_KERNEL,
"FPRoundingModeRTP is only supported in kernels");
return nir_rounding_mode_ru;
case SpvFPRoundingModeRTN:
vtn_fail_if(b->shader->info.stage != MESA_SHADER_KERNEL,
"FPRoundingModeRTN is only supported in kernels");
return nir_rounding_mode_rd;
default:
vtn_fail("Unsupported rounding mode: %s",
spirv_fproundingmode_to_string(mode));
@@ -393,15 +405,31 @@ vtn_rounding_mode_to_nir(struct vtn_builder *b, SpvFPRoundingMode mode)
}
}
struct conversion_opts {
nir_rounding_mode rounding_mode;
bool saturate;
};
static void
handle_rounding_mode(struct vtn_builder *b, struct vtn_value *val, int member,
const struct vtn_decoration *dec, void *_out_rounding_mode)
handle_conversion_opts(struct vtn_builder *b, struct vtn_value *val, int member,
const struct vtn_decoration *dec, void *_opts)
{
nir_rounding_mode *out_rounding_mode = _out_rounding_mode;
assert(dec->scope == VTN_DEC_DECORATION);
if (dec->decoration != SpvDecorationFPRoundingMode)
return;
*out_rounding_mode = vtn_rounding_mode_to_nir(b, dec->operands[0]);
struct conversion_opts *opts = _opts;
switch (dec->decoration) {
case SpvDecorationFPRoundingMode:
opts->rounding_mode = vtn_rounding_mode_to_nir(b, dec->operands[0]);
break;
case SpvDecorationSaturatedConversion:
vtn_fail_if(b->shader->info.stage != MESA_SHADER_KERNEL,
"Saturated conversions are only allowed in kernels");
opts->saturate = true;
break;
default:
break;
}
}
static void
@@ -592,15 +620,48 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
break;
}
case SpvOpFConvert: {
nir_alu_type src_alu_type = nir_get_nir_type_for_glsl_type(vtn_src[0]->type);
nir_alu_type dst_alu_type = nir_get_nir_type_for_glsl_type(dest_type);
nir_rounding_mode rounding_mode = nir_rounding_mode_undef;
case SpvOpUConvert:
case SpvOpConvertFToU:
case SpvOpConvertFToS:
case SpvOpConvertSToF:
case SpvOpConvertUToF:
case SpvOpSConvert:
case SpvOpFConvert:
case SpvOpSatConvertSToU:
case SpvOpSatConvertUToS: {
unsigned src_bit_size = glsl_get_bit_size(vtn_src[0]->type);
unsigned dst_bit_size = glsl_get_bit_size(dest_type);
nir_alu_type src_type = convert_op_src_type(opcode) | src_bit_size;
nir_alu_type dst_type = convert_op_dst_type(opcode) | dst_bit_size;
vtn_foreach_decoration(b, dest_val, handle_rounding_mode, &rounding_mode);
nir_op op = nir_type_conversion_op(src_alu_type, dst_alu_type, rounding_mode);
struct conversion_opts opts = {
.rounding_mode = nir_rounding_mode_undef,
.saturate = false,
};
vtn_foreach_decoration(b, dest_val, handle_conversion_opts, &opts);
dest->def = nir_build_alu(&b->nb, op, src[0], src[1], NULL, NULL);
if (opcode == SpvOpSatConvertSToU || opcode == SpvOpSatConvertUToS)
opts.saturate = true;
if (b->shader->info.stage == MESA_SHADER_KERNEL) {
if (opts.rounding_mode == nir_rounding_mode_undef && !opts.saturate) {
nir_op op = nir_type_conversion_op(src_type, dst_type,
nir_rounding_mode_undef);
dest->def = nir_build_alu(&b->nb, op, src[0], NULL, NULL, NULL);
} else {
dest->def = nir_convert_alu_types(&b->nb, src[0], src_type,
dst_type, opts.rounding_mode,
opts.saturate);
}
} else {
vtn_fail_if(opts.rounding_mode != nir_rounding_mode_undef &&
dst_type != nir_type_float16,
"Rounding modes are only allowed on conversions to "
"16-bit float types");
nir_op op = nir_type_conversion_op(src_type, dst_type,
opts.rounding_mode);
dest->def = nir_build_alu(&b->nb, op, src[0], NULL, NULL, NULL);
}
break;
}