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:
committed by
Marge Bot
parent
8e8458218c
commit
8610af12b6
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user