mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
shader: V_MAD_I16
This commit is contained in:
@@ -228,6 +228,7 @@ enum class Opcode {
|
|||||||
V_CVT_PKRTZ_F16_F32,
|
V_CVT_PKRTZ_F16_F32,
|
||||||
V_CVT_PK_U8_F32,
|
V_CVT_PK_U8_F32,
|
||||||
V_MAD_F32,
|
V_MAD_F32,
|
||||||
|
V_MAD_I16,
|
||||||
V_MAD_I32_I24,
|
V_MAD_I32_I24,
|
||||||
V_MAD_U32_U24,
|
V_MAD_U32_U24,
|
||||||
V_MAD_U64_U32,
|
V_MAD_U64_U32,
|
||||||
|
|||||||
@@ -312,6 +312,7 @@ constexpr OpcodeMap VOP3_OPCODE_LIST[] = {
|
|||||||
{0x345u, Opcode::V_XAD_U32},
|
{0x345u, Opcode::V_XAD_U32},
|
||||||
{0x346u, Opcode::V_LSHL_ADD_U32},
|
{0x346u, Opcode::V_LSHL_ADD_U32},
|
||||||
{0x347u, Opcode::V_ADD_LSHL_U32},
|
{0x347u, Opcode::V_ADD_LSHL_U32},
|
||||||
|
{0x35eu, Opcode::V_MAD_I16},
|
||||||
{0x360u, Opcode::V_READLANE_B32},
|
{0x360u, Opcode::V_READLANE_B32},
|
||||||
{0x361u, Opcode::V_WRITELANE_B32},
|
{0x361u, Opcode::V_WRITELANE_B32},
|
||||||
{0x362u, Opcode::V_LDEXP_F32},
|
{0x362u, Opcode::V_LDEXP_F32},
|
||||||
@@ -424,7 +425,7 @@ bool IsNativeVop3F16TernaryOpcode(Opcode opcode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsNativeVop3I16TernaryOpcode(Opcode opcode) {
|
bool IsNativeVop3I16TernaryOpcode(Opcode opcode) {
|
||||||
return opcode == Opcode::V_MED3_I16;
|
return opcode == Opcode::V_MED3_I16 || opcode == Opcode::V_MAD_I16;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsNativeVop3B16BinaryOpcode(Opcode opcode) {
|
bool IsNativeVop3B16BinaryOpcode(Opcode opcode) {
|
||||||
@@ -1362,7 +1363,8 @@ bool SupportsNativeVop3ResultModifiers(Opcode opcode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SupportsNativeVop3Clamp(Opcode opcode) {
|
bool SupportsNativeVop3Clamp(Opcode opcode) {
|
||||||
return SupportsNativeVop3ResultModifiers(opcode) || UsesInexactClampControl(opcode);
|
return SupportsNativeVop3ResultModifiers(opcode) || UsesInexactClampControl(opcode) ||
|
||||||
|
opcode == Opcode::V_MAD_I16;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mix,
|
bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mix,
|
||||||
@@ -1383,7 +1385,7 @@ bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mi
|
|||||||
return opcode != Opcode::V_FMA_F16 && (clamp != 0u || omod != 0u);
|
return opcode != Opcode::V_FMA_F16 && (clamp != 0u || omod != 0u);
|
||||||
}
|
}
|
||||||
if (IsNativeVop3I16TernaryOpcode(opcode)) {
|
if (IsNativeVop3I16TernaryOpcode(opcode)) {
|
||||||
return abs != 0u || clamp != 0u || omod != 0u || neg != 0u;
|
return abs != 0u || (clamp != 0u && !clamp_modifier) || omod != 0u || neg != 0u;
|
||||||
}
|
}
|
||||||
if (IsNativeVop3B16BinaryOpcode(opcode)) {
|
if (IsNativeVop3B16BinaryOpcode(opcode)) {
|
||||||
return abs != 0u || clamp != 0u || omod != 0u || neg != 0u;
|
return abs != 0u || clamp != 0u || omod != 0u || neg != 0u;
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ bool Translator::Integer16Binary(const Decoder::Instruction& inst, IR::ValueOpco
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Translator::V_MAD_I16(const Decoder::Instruction& inst) {
|
||||||
|
const auto lhs = ReadU16AsU32(inst.src0, true);
|
||||||
|
const auto rhs = ReadU16AsU32(inst.src1, true);
|
||||||
|
auto result = ir.IAdd(ir.IMul(lhs, rhs), ReadU16AsU32(inst.src2, true));
|
||||||
|
if (inst.dst.clamp) {
|
||||||
|
result = IR::U32(ir.Emit(IR::ValueOpcode::SMax32, {result, IR::Value(0xffff8000u)}));
|
||||||
|
result = IR::U32(ir.Emit(IR::ValueOpcode::SMin32, {result, IR::Value(0x7fffu)}));
|
||||||
|
}
|
||||||
|
Write16Bits(DestinationOperand(inst), ir.BitwiseAnd(result, IR::U32(IR::Value(0xffffu))));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Translator::V_MED3_I16(const Decoder::Instruction& inst) {
|
bool Translator::V_MED3_I16(const Decoder::Instruction& inst) {
|
||||||
const auto result = IR::U32(ir.Emit(
|
const auto result = IR::U32(ir.Emit(
|
||||||
IR::ValueOpcode::SMedTri32, {ReadU16AsU32(inst.src0, true), ReadU16AsU32(inst.src1, true),
|
IR::ValueOpcode::SMedTri32, {ReadU16AsU32(inst.src0, true), ReadU16AsU32(inst.src1, true),
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ private:
|
|||||||
bool FloatCube(const Decoder::Instruction& inst, uint32_t result_kind);
|
bool FloatCube(const Decoder::Instruction& inst, uint32_t result_kind);
|
||||||
bool Integer16Shift(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool arithmetic);
|
bool Integer16Shift(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool arithmetic);
|
||||||
bool Integer16Binary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool sign);
|
bool Integer16Binary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool sign);
|
||||||
|
bool V_MAD_I16(const Decoder::Instruction& inst);
|
||||||
bool V_MED3_I16(const Decoder::Instruction& inst);
|
bool V_MED3_I16(const Decoder::Instruction& inst);
|
||||||
bool PackedInteger16Shift(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
bool PackedInteger16Shift(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
|
||||||
bool arithmetic);
|
bool arithmetic);
|
||||||
|
|||||||
@@ -328,6 +328,7 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
|
|||||||
case O::V_SUB_NC_U16:
|
case O::V_SUB_NC_U16:
|
||||||
case O::V_SUB_NC_I16: return Integer16Binary(inst, IR::ValueOpcode::ISub32, false);
|
case O::V_SUB_NC_I16: return Integer16Binary(inst, IR::ValueOpcode::ISub32, false);
|
||||||
case O::V_MUL_LO_U16: return Integer16Binary(inst, IR::ValueOpcode::IMul32, false);
|
case O::V_MUL_LO_U16: return Integer16Binary(inst, IR::ValueOpcode::IMul32, false);
|
||||||
|
case O::V_MAD_I16: return V_MAD_I16(inst);
|
||||||
case O::V_MED3_I16: return V_MED3_I16(inst);
|
case O::V_MED3_I16: return V_MED3_I16(inst);
|
||||||
case O::V_MIN_I16: return Integer16Binary(inst, IR::ValueOpcode::SMin32, true);
|
case O::V_MIN_I16: return Integer16Binary(inst, IR::ValueOpcode::SMin32, true);
|
||||||
case O::V_MAX_I16: return Integer16Binary(inst, IR::ValueOpcode::SMax32, true);
|
case O::V_MAX_I16: return Integer16Binary(inst, IR::ValueOpcode::SMax32, true);
|
||||||
|
|||||||
@@ -18205,6 +18205,64 @@ TestCase Vop3MulLoU16CapturedAndSelectors() {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase Vop3MadI16CapturedSelectorsAndSaturation() {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
struct MadCase {
|
||||||
|
u32 lhs, rhs, addend, expected;
|
||||||
|
u32 selectors = 0;
|
||||||
|
bool clamp = false;
|
||||||
|
u32 dst = 1;
|
||||||
|
};
|
||||||
|
constexpr u32 a = 0x8000fffdu, b = 0xfffe0005u, c = 0xfff90007u;
|
||||||
|
const std::array<MadCase, 14> cases{{
|
||||||
|
{a, b, c, 0xa5a5fff8u}, // Captured: -3 * 5 + 7 = -8.
|
||||||
|
{a, b, c, 0x8007beefu, 9}, // Source 0 high; destination high.
|
||||||
|
{a, b, c, 0xa5a5000du, 2}, // Source 1 high: -3 * -2 + 7.
|
||||||
|
{a, b, c, 0xa5a5ffeau, 4}, // Source 2 high: -3 * 5 - 7.
|
||||||
|
{a, b, c, 0xfff9beefu, 15}, // All high: -32768 * -2 - 7 wraps.
|
||||||
|
{a, b, c, 0xfff8fffdu, 8, false, 9}, // Destination aliases source 0.
|
||||||
|
{0x7fffu, 1, 1, 0xa5a58000u},
|
||||||
|
{0x7fffu, 1, 1, 0x7fffbeefu, 8, true}, // Positive saturation.
|
||||||
|
{0x8000u, 1, 0xffffu, 0xa5a57fffu},
|
||||||
|
{0x8000u, 1, 0xffffu, 0x8000beefu, 8, true}, // Negative saturation.
|
||||||
|
{0x8000u, 0x8000u, 0xffffu, 0xa5a5ffffu},
|
||||||
|
{0x8000u, 0x8000u, 0xffffu, 0xa5a57fffu, 0, true},
|
||||||
|
{200, 200, 0xd8f0u, 0xa5a57530u, 0, true}, // 40000 - 10000 = 30000.
|
||||||
|
{200, 0xff38u, 10000, 0xa5a58ad0u, 0, true}, // -40000 + 10000 = -30000.
|
||||||
|
}};
|
||||||
|
TestCase test;
|
||||||
|
test.name = "Vop3MadI16CapturedSelectorsAndSaturation";
|
||||||
|
for (const auto &entry : cases) {
|
||||||
|
test.initial.insert(test.initial.end(), {entry.lhs, entry.rhs, entry.addend});
|
||||||
|
}
|
||||||
|
test.expected = test.initial;
|
||||||
|
auto &code = test.code;
|
||||||
|
for (u32 i = 0; i < cases.size(); ++i) {
|
||||||
|
const auto &entry = cases[i];
|
||||||
|
u32 offset = i * 12u;
|
||||||
|
for (u32 reg : {9u, 6u, 15u}) {
|
||||||
|
AppendVMovU32(&code, 30, offset);
|
||||||
|
AppendBufferLoadDword(&code, reg, 30); // Runtime inputs prevent folding.
|
||||||
|
offset += 4u;
|
||||||
|
}
|
||||||
|
AppendVMovLiteral(&code, 1, 0xa5a5beefu);
|
||||||
|
if (i == 0u) {
|
||||||
|
code.insert(code.end(), {0xd75e0001u, 0x043e0d09u});
|
||||||
|
} else {
|
||||||
|
AppendVop3(&code, 0x35e, entry.dst, Vgpr(9), Vgpr(6), Vgpr(15), 0,
|
||||||
|
entry.selectors, entry.clamp);
|
||||||
|
}
|
||||||
|
AppendStoreVgpr(&code, entry.dst, static_cast<u32>(test.initial.size()) + i);
|
||||||
|
test.expected.push_back(entry.expected);
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_MAD_I16,
|
||||||
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
|
test.decoded_counts = {{"V_MAD_I16", cases.size()}};
|
||||||
|
test.required_spirv = {"OpIMul", "OpIAdd"};
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase Vop3Med3I16Captured() {
|
TestCase Vop3Med3I16Captured() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -27038,6 +27096,7 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(Vop2SdwaSubNcPreservesByteAndWordDestinations);
|
AddCase(Vop2SdwaSubNcPreservesByteAndWordDestinations);
|
||||||
AddCase(Vop3CvtPkI16I32Captured);
|
AddCase(Vop3CvtPkI16I32Captured);
|
||||||
AddCase(Vop3MulLoU16CapturedAndSelectors);
|
AddCase(Vop3MulLoU16CapturedAndSelectors);
|
||||||
|
AddCase(Vop3MadI16CapturedSelectorsAndSaturation);
|
||||||
AddCase(Vop3Med3I16Captured);
|
AddCase(Vop3Med3I16Captured);
|
||||||
AddCase(Vop2SdwaMinU32PreservesWordDestination);
|
AddCase(Vop2SdwaMinU32PreservesWordDestination);
|
||||||
AddCase(VectorShiftCountsMaskLowBits);
|
AddCase(VectorShiftCountsMaskLowBits);
|
||||||
@@ -32053,6 +32112,11 @@ int main(int argc, char **argv) {
|
|||||||
RunCase(&vulkan, Vop3MulLoU16CapturedAndSelectors());
|
RunCase(&vulkan, Vop3MulLoU16CapturedAndSelectors());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--mad-i16-only") == 0) {
|
||||||
|
VulkanHarness vulkan;
|
||||||
|
RunCase(&vulkan, Vop3MadI16CapturedSelectorsAndSaturation());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--waitcnt-depctr-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--waitcnt-depctr-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
RunCase(&vulkan, ScalarWaitcntDepctrCapturedVmVsrc());
|
RunCase(&vulkan, ScalarWaitcntDepctrCapturedVmVsrc());
|
||||||
|
|||||||
Reference in New Issue
Block a user