shader: implement RDNA2 frexp exponent

This commit is contained in:
nmzik
2026-08-17 07:47:28 +02:00
parent 8ce06ccdf6
commit 1be9568a02
7 changed files with 63 additions and 0 deletions
@@ -566,6 +566,7 @@ std::string OpcodeToString(Opcode opcode) {
case Opcode::VCvtI16F16: return "v_cvt_i16_f16";
case Opcode::VCvtRpiI32F32: return "v_cvt_rpi_i32_f32";
case Opcode::VCvtFlrI32F32: return "v_cvt_flr_i32_f32";
case Opcode::VFrexpExpI32F32: return "v_frexp_exp_i32_f32";
case Opcode::VCvtOffF32I4: return "v_cvt_off_f32_i4";
case Opcode::VCvtF32Ubyte0: return "v_cvt_f32_ubyte0";
case Opcode::VCvtF32Ubyte1: return "v_cvt_f32_ubyte1";
@@ -151,6 +151,7 @@ enum class Opcode {
VCvtI16F16,
VCvtRpiI32F32,
VCvtFlrI32F32,
VFrexpExpI32F32,
VCvtOffF32I4,
VCvtF32Ubyte0,
VCvtF32Ubyte1,
@@ -120,6 +120,7 @@ constexpr OpcodeMap VOP1_OPCODE_LIST[] = {
{0x38u, Opcode::VBfrevB32},
{0x39u, Opcode::VFfbhU32},
{0x3au, Opcode::VFfblB32},
{0x3fu, Opcode::VFrexpExpI32F32},
{0x42u, Opcode::VMovreldB32},
{0x43u, Opcode::VMovrelsB32},
{0x50u, Opcode::VCvtF16U16},
@@ -168,6 +169,7 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = {
{0x38u, Opcode::VBfrevB32},
{0x39u, Opcode::VFfbhU32},
{0x3au, Opcode::VFfblB32},
{0x3fu, Opcode::VFrexpExpI32F32},
{0x42u, Opcode::VMovreldB32},
{0x43u, Opcode::VMovrelsB32},
{0x50u, Opcode::VCvtF16U16},
@@ -410,6 +412,7 @@ bool IsVop1FloatSourceOpcode(Opcode opcode) {
case Opcode::VCvtI32F32:
case Opcode::VCvtRpiI32F32:
case Opcode::VCvtFlrI32F32:
case Opcode::VFrexpExpI32F32:
case Opcode::VCvtF16F32:
case Opcode::VRcpF32:
case Opcode::VRcpIflagF32:
@@ -109,6 +109,23 @@ bool Translator::TranslateConversion(const IR::Instruction& inst) {
WriteOperand(inst.dst, convert_i32(rounded));
return true;
}
case IR::Opcode::FrexpExpI32F32: {
const auto bits = ir.BitCastU32(f32(0));
const auto exponent = IR::U32(
ir.Emit(IR::ValueOpcode::BitFieldUExtract, {bits, IR::Value(23u), IR::Value(8u)}));
const auto mantissa = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x007fffffu)));
const auto normal = ir.ISub(exponent, IR::U32(IR::Value(126u)));
const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {mantissa}));
const auto subnormal = ir.ISub(msb, IR::U32(IR::Value(148u)));
const auto denormal = ir.Select(ir.INotEqual(mantissa, IR::U32(IR::Value(0u))),
subnormal, IR::U32(IR::Value(0u)));
const auto finite = ir.Select(
ir.INotEqual(exponent, IR::U32(IR::Value(0xffu))),
ir.Select(ir.INotEqual(exponent, IR::U32(IR::Value(0u))), normal, denormal),
IR::U32(IR::Value(0u)));
WriteOperand(inst.dst, finite);
return true;
}
case IR::Opcode::ConvertI4ToOffsetF32: {
const auto nibble = IR::U32(
ir.Emit(IR::ValueOpcode::BitFieldSExtract, {u32(0), IR::Value(0u), IR::Value(4u)}));
@@ -103,6 +103,7 @@ constexpr LowerMap LOWER_OPS[] = {
{Decoder::Opcode::VCvtI16F16, Opcode::ConvertF16ToI16},
{Decoder::Opcode::VCvtRpiI32F32, Opcode::ConvertRoundPlusInfF32ToI32},
{Decoder::Opcode::VCvtFlrI32F32, Opcode::ConvertFloorF32ToI32},
{Decoder::Opcode::VFrexpExpI32F32, Opcode::FrexpExpI32F32},
{Decoder::Opcode::VCvtOffF32I4, Opcode::ConvertI4ToOffsetF32},
{Decoder::Opcode::VRcpF32, Opcode::RcpF32},
{Decoder::Opcode::VRcpIflagF32, Opcode::RcpIflagF32},
@@ -213,6 +213,7 @@ IR_OPCODE(ConvertI16ToF16, General, Conversion)
IR_OPCODE(ConvertF16ToI16, General, Conversion)
IR_OPCODE(ConvertRoundPlusInfF32ToI32, General, Conversion)
IR_OPCODE(ConvertFloorF32ToI32, General, Conversion)
IR_OPCODE(FrexpExpI32F32, General, Conversion)
IR_OPCODE(ConvertI4ToOffsetF32, General, Conversion)
IR_OPCODE(LdexpF32, General, Float)
IR_OPCODE(PackF32ToF16Rtz, General, Conversion)