mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
shader: implement RDNA2 frexp exponent
This commit is contained in:
@@ -566,6 +566,7 @@ std::string OpcodeToString(Opcode opcode) {
|
|||||||
case Opcode::VCvtI16F16: return "v_cvt_i16_f16";
|
case Opcode::VCvtI16F16: return "v_cvt_i16_f16";
|
||||||
case Opcode::VCvtRpiI32F32: return "v_cvt_rpi_i32_f32";
|
case Opcode::VCvtRpiI32F32: return "v_cvt_rpi_i32_f32";
|
||||||
case Opcode::VCvtFlrI32F32: return "v_cvt_flr_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::VCvtOffF32I4: return "v_cvt_off_f32_i4";
|
||||||
case Opcode::VCvtF32Ubyte0: return "v_cvt_f32_ubyte0";
|
case Opcode::VCvtF32Ubyte0: return "v_cvt_f32_ubyte0";
|
||||||
case Opcode::VCvtF32Ubyte1: return "v_cvt_f32_ubyte1";
|
case Opcode::VCvtF32Ubyte1: return "v_cvt_f32_ubyte1";
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ enum class Opcode {
|
|||||||
VCvtI16F16,
|
VCvtI16F16,
|
||||||
VCvtRpiI32F32,
|
VCvtRpiI32F32,
|
||||||
VCvtFlrI32F32,
|
VCvtFlrI32F32,
|
||||||
|
VFrexpExpI32F32,
|
||||||
VCvtOffF32I4,
|
VCvtOffF32I4,
|
||||||
VCvtF32Ubyte0,
|
VCvtF32Ubyte0,
|
||||||
VCvtF32Ubyte1,
|
VCvtF32Ubyte1,
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ constexpr OpcodeMap VOP1_OPCODE_LIST[] = {
|
|||||||
{0x38u, Opcode::VBfrevB32},
|
{0x38u, Opcode::VBfrevB32},
|
||||||
{0x39u, Opcode::VFfbhU32},
|
{0x39u, Opcode::VFfbhU32},
|
||||||
{0x3au, Opcode::VFfblB32},
|
{0x3au, Opcode::VFfblB32},
|
||||||
|
{0x3fu, Opcode::VFrexpExpI32F32},
|
||||||
{0x42u, Opcode::VMovreldB32},
|
{0x42u, Opcode::VMovreldB32},
|
||||||
{0x43u, Opcode::VMovrelsB32},
|
{0x43u, Opcode::VMovrelsB32},
|
||||||
{0x50u, Opcode::VCvtF16U16},
|
{0x50u, Opcode::VCvtF16U16},
|
||||||
@@ -168,6 +169,7 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = {
|
|||||||
{0x38u, Opcode::VBfrevB32},
|
{0x38u, Opcode::VBfrevB32},
|
||||||
{0x39u, Opcode::VFfbhU32},
|
{0x39u, Opcode::VFfbhU32},
|
||||||
{0x3au, Opcode::VFfblB32},
|
{0x3au, Opcode::VFfblB32},
|
||||||
|
{0x3fu, Opcode::VFrexpExpI32F32},
|
||||||
{0x42u, Opcode::VMovreldB32},
|
{0x42u, Opcode::VMovreldB32},
|
||||||
{0x43u, Opcode::VMovrelsB32},
|
{0x43u, Opcode::VMovrelsB32},
|
||||||
{0x50u, Opcode::VCvtF16U16},
|
{0x50u, Opcode::VCvtF16U16},
|
||||||
@@ -410,6 +412,7 @@ bool IsVop1FloatSourceOpcode(Opcode opcode) {
|
|||||||
case Opcode::VCvtI32F32:
|
case Opcode::VCvtI32F32:
|
||||||
case Opcode::VCvtRpiI32F32:
|
case Opcode::VCvtRpiI32F32:
|
||||||
case Opcode::VCvtFlrI32F32:
|
case Opcode::VCvtFlrI32F32:
|
||||||
|
case Opcode::VFrexpExpI32F32:
|
||||||
case Opcode::VCvtF16F32:
|
case Opcode::VCvtF16F32:
|
||||||
case Opcode::VRcpF32:
|
case Opcode::VRcpF32:
|
||||||
case Opcode::VRcpIflagF32:
|
case Opcode::VRcpIflagF32:
|
||||||
|
|||||||
@@ -109,6 +109,23 @@ bool Translator::TranslateConversion(const IR::Instruction& inst) {
|
|||||||
WriteOperand(inst.dst, convert_i32(rounded));
|
WriteOperand(inst.dst, convert_i32(rounded));
|
||||||
return true;
|
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: {
|
case IR::Opcode::ConvertI4ToOffsetF32: {
|
||||||
const auto nibble = IR::U32(
|
const auto nibble = IR::U32(
|
||||||
ir.Emit(IR::ValueOpcode::BitFieldSExtract, {u32(0), IR::Value(0u), IR::Value(4u)}));
|
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::VCvtI16F16, Opcode::ConvertF16ToI16},
|
||||||
{Decoder::Opcode::VCvtRpiI32F32, Opcode::ConvertRoundPlusInfF32ToI32},
|
{Decoder::Opcode::VCvtRpiI32F32, Opcode::ConvertRoundPlusInfF32ToI32},
|
||||||
{Decoder::Opcode::VCvtFlrI32F32, Opcode::ConvertFloorF32ToI32},
|
{Decoder::Opcode::VCvtFlrI32F32, Opcode::ConvertFloorF32ToI32},
|
||||||
|
{Decoder::Opcode::VFrexpExpI32F32, Opcode::FrexpExpI32F32},
|
||||||
{Decoder::Opcode::VCvtOffF32I4, Opcode::ConvertI4ToOffsetF32},
|
{Decoder::Opcode::VCvtOffF32I4, Opcode::ConvertI4ToOffsetF32},
|
||||||
{Decoder::Opcode::VRcpF32, Opcode::RcpF32},
|
{Decoder::Opcode::VRcpF32, Opcode::RcpF32},
|
||||||
{Decoder::Opcode::VRcpIflagF32, Opcode::RcpIflagF32},
|
{Decoder::Opcode::VRcpIflagF32, Opcode::RcpIflagF32},
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ IR_OPCODE(ConvertI16ToF16, General, Conversion)
|
|||||||
IR_OPCODE(ConvertF16ToI16, General, Conversion)
|
IR_OPCODE(ConvertF16ToI16, General, Conversion)
|
||||||
IR_OPCODE(ConvertRoundPlusInfF32ToI32, General, Conversion)
|
IR_OPCODE(ConvertRoundPlusInfF32ToI32, General, Conversion)
|
||||||
IR_OPCODE(ConvertFloorF32ToI32, General, Conversion)
|
IR_OPCODE(ConvertFloorF32ToI32, General, Conversion)
|
||||||
|
IR_OPCODE(FrexpExpI32F32, General, Conversion)
|
||||||
IR_OPCODE(ConvertI4ToOffsetF32, General, Conversion)
|
IR_OPCODE(ConvertI4ToOffsetF32, General, Conversion)
|
||||||
IR_OPCODE(LdexpF32, General, Float)
|
IR_OPCODE(LdexpF32, General, Float)
|
||||||
IR_OPCODE(PackF32ToF16Rtz, General, Conversion)
|
IR_OPCODE(PackF32ToF16Rtz, General, Conversion)
|
||||||
|
|||||||
@@ -13527,6 +13527,44 @@ TestCase VectorFloatConversionOps() {
|
|||||||
O::SEndpgm}};
|
O::SEndpgm}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase VectorFrexpExpI32F32Edges() {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
|
const std::vector<u32> inputs = {
|
||||||
|
0x00000000u, 0x80000000u, 0x3f000000u, 0xbf800000u,
|
||||||
|
0x40800000u, 0xc1000000u, 0x00800000u, 0x007fffffu,
|
||||||
|
0x00000001u, 0x7f800000u, 0x7fc00000u,
|
||||||
|
};
|
||||||
|
std::vector<u32> code;
|
||||||
|
for (u32 i = 0; i < static_cast<u32>(inputs.size()); i++) {
|
||||||
|
AppendVMovU32(&code, 31, i * sizeof(u32));
|
||||||
|
AppendBufferLoadDword(&code, i == 3u ? 23u : i, 31);
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < static_cast<u32>(inputs.size()); i++) {
|
||||||
|
const auto dst = 16u + i;
|
||||||
|
if (dst == 19u) {
|
||||||
|
code.push_back(0x7e267ef9u); // captured v_frexp_exp_i32_f32 v19, abs(v23)
|
||||||
|
code.push_back(0x00260617u);
|
||||||
|
} else {
|
||||||
|
code.push_back(EncodeVop1(0x3f, dst, Vgpr(i)));
|
||||||
|
}
|
||||||
|
AppendStoreVgpr(&code, dst, i);
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
|
||||||
|
TestCase test;
|
||||||
|
test.name = "VectorFrexpExpI32F32Edges";
|
||||||
|
test.code = std::move(code);
|
||||||
|
test.initial = inputs;
|
||||||
|
test.expected = {0u, 0u, 0u, 1u, 3u, 4u,
|
||||||
|
0xffffff83u, 0xffffff82u, 0xffffff6cu, 0u, 0u};
|
||||||
|
test.opcodes = {O::VMovB32, O::BufferLoadDword, O::VFrexpExpI32F32,
|
||||||
|
O::BufferStoreDword, O::SEndpgm};
|
||||||
|
test.decoded_counts = {{"v_frexp_exp_i32_f32", inputs.size()}};
|
||||||
|
test.required_spirv = {"FindUMsb", "OpBitFieldUExtract"};
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase CvtF32ToIntSaturatesNaNAndOutOfRange() {
|
TestCase CvtF32ToIntSaturatesNaNAndOutOfRange() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -17842,6 +17880,7 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(VectorMinMaxF32NanAndSignedZeroEdges);
|
AddCase(VectorMinMaxF32NanAndSignedZeroEdges);
|
||||||
AddCase(VectorMed3F32NanUsesMin3Path);
|
AddCase(VectorMed3F32NanUsesMin3Path);
|
||||||
AddCase(VectorFloatConversionOps);
|
AddCase(VectorFloatConversionOps);
|
||||||
|
AddCase(VectorFrexpExpI32F32Edges);
|
||||||
AddCase(CvtF32ToIntSaturatesNaNAndOutOfRange);
|
AddCase(CvtF32ToIntSaturatesNaNAndOutOfRange);
|
||||||
AddCase(VectorSpecialF32FlushesDenormalInputs);
|
AddCase(VectorSpecialF32FlushesDenormalInputs);
|
||||||
AddCase(VectorRcpIflagF32IntegerReciprocal);
|
AddCase(VectorRcpIflagF32IntegerReciprocal);
|
||||||
|
|||||||
Reference in New Issue
Block a user