mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 08:41:20 +00:00
shader: implement V_ASHRREV_I64 (VOP3 0x301)
This commit is contained in:
1 parent
c528324d27
commit
a8e3c29b2e
6 files changed
+120
-5
No files matched your search
@@ -354,6 +354,7 @@ enum class Opcode {
|
||||
V_ASHRREV_I32,
|
||||
V_LSHLREV_B64,
|
||||
V_LSHRREV_B64,
|
||||
V_ASHRREV_I64,
|
||||
V_LSHLREV_B16,
|
||||
V_LSHRREV_B16,
|
||||
V_ASHRREV_I16,
|
||||
|
||||
@@ -354,6 +354,7 @@ constexpr OpcodeMap VOP3_OPCODE_LIST[] = {
|
||||
{0x16cu, Opcode::V_MUL_HI_I32},
|
||||
{0x2ffu, Opcode::V_LSHLREV_B64},
|
||||
{0x300u, Opcode::V_LSHRREV_B64},
|
||||
{0x301u, Opcode::V_ASHRREV_I64},
|
||||
{0x303u, Opcode::V_ADD_NC_U16},
|
||||
{0x304u, Opcode::V_SUB_NC_U16},
|
||||
{0x305u, Opcode::V_MUL_LO_U16},
|
||||
@@ -1335,6 +1336,7 @@ uint32_t NativeVop3SourceCount(Opcode opcode) {
|
||||
case Opcode::V_SUB_NC_I16:
|
||||
case Opcode::V_LSHLREV_B64:
|
||||
case Opcode::V_LSHRREV_B64:
|
||||
case Opcode::V_ASHRREV_I64:
|
||||
case Opcode::V_LSHLREV_B16:
|
||||
case Opcode::V_LSHRREV_B16:
|
||||
case Opcode::V_ASHRREV_I16:
|
||||
|
||||
@@ -147,6 +147,12 @@ void Translator::SimpleInteger(const Decoder::Instruction& inst, IR::ValueOpcode
|
||||
const auto arg_type = IR::ArgTypeOf(opcode, index);
|
||||
const auto& operand = SourceAt(inst, reverse && index < 2u ? 1u - index : index);
|
||||
args[index] = ReadOperand(operand, arg_type == IR::Type::Void ? type : arg_type);
|
||||
if (opcode == IR::ValueOpcode::ShiftRightArithmetic64 && index == 0u &&
|
||||
operand.kind == Decoder::OperandKind::LiteralConstant) {
|
||||
args[index] = ir.ConstructU64(
|
||||
ReadU32(operand),
|
||||
IR::U32(IR::Value((operand.value & 0x80000000u) ? 0xffffffffu : 0u)));
|
||||
}
|
||||
if (mask_shift_count && index == 1u) {
|
||||
args[index] = ir.BitwiseAnd(IR::U32(args[index]), IR::U32(IR::Value(31u)));
|
||||
}
|
||||
|
||||
@@ -565,6 +565,9 @@ void Translator::EmitVector(const Decoder::Instruction& inst) {
|
||||
case O::V_LSHRREV_B64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightLogical64, IR::Type::U64, true,
|
||||
false, false);
|
||||
case O::V_ASHRREV_I64:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::ShiftRightArithmetic64, IR::Type::U64, true,
|
||||
false, false);
|
||||
|
||||
case O::V_XNOR_B32:
|
||||
return ComposedIntegerBinary(inst, IR::ValueOpcode::BitwiseXor32, false, true, false);
|
||||
|
||||
@@ -26927,6 +26927,67 @@ TestCase VectorVop3LshlrevB64Captured() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorVop3AshrrevI64Operands() {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = "VectorVop3AshrrevI64Operands";
|
||||
test.initial = {33u, 0x89abcdefu, 0xfedcba98u};
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
const auto store_result = [&](u32 dst, uint64_t value, u32 count) {
|
||||
const auto output = static_cast<u32>(test.expected.size());
|
||||
AppendStoreVgpr(&code, dst, output);
|
||||
AppendStoreVgpr(&code, dst + 1u, output + 1u);
|
||||
const auto expected = ReferenceAshrI64(value, count);
|
||||
test.expected.push_back(static_cast<u32>(expected));
|
||||
test.expected.push_back(static_cast<u32>(expected >> 32u));
|
||||
};
|
||||
|
||||
constexpr uint64_t value = 0xfedcba9889abcdefull;
|
||||
AppendVMovU32(&code, 30, sizeof(u32));
|
||||
AppendBufferLoadDword(&code, 2, 30);
|
||||
AppendVMovU32(&code, 30, 2u * sizeof(u32));
|
||||
AppendBufferLoadDword(&code, 3, 30);
|
||||
code.push_back(0xd7010007u);
|
||||
code.push_back(0x00020498u);
|
||||
store_result(7, value, 24u);
|
||||
|
||||
AppendSMovLiteral(&code, 106, static_cast<u32>(value));
|
||||
AppendSMovLiteral(&code, 107, static_cast<u32>(value >> 32u));
|
||||
AppendVMovU32(&code, 12, 68);
|
||||
code.push_back(0xd7010001u);
|
||||
code.push_back(0x0000d50cu);
|
||||
store_result(1, value, 68u);
|
||||
|
||||
AppendVMovU32(&code, 30, 0);
|
||||
AppendBufferLoadDword(&code, 12, 30);
|
||||
for (const u32 literal : {0u, 0x7fffffffu, 0x80000000u, 0xffffffffu}) {
|
||||
const uint64_t extended =
|
||||
literal | ((literal & 0x80000000u) != 0 ? 0xffffffff00000000ull : 0ull);
|
||||
for (const u32 count : {0u, 1u, 31u, 32u, 63u, 64u}) {
|
||||
AppendVop3(&code, 0x301, 7, InlineU32(count), 255u);
|
||||
code.push_back(literal);
|
||||
store_result(7, extended, count);
|
||||
}
|
||||
AppendVop3(&code, 0x301, 7, Vgpr(12), 255u);
|
||||
code.push_back(literal);
|
||||
store_result(7, extended, 33u);
|
||||
}
|
||||
AppendVop3(&code, 0x301, 7, Vgpr(12), 193u);
|
||||
store_result(7, UINT64_MAX, 33u);
|
||||
AppendVMovLiteral(&code, 7, static_cast<u32>(value));
|
||||
AppendVMovLiteral(&code, 8, static_cast<u32>(value >> 32u));
|
||||
AppendVop3(&code, 0x301, 7, Vgpr(12), Vgpr(7));
|
||||
store_result(7, value, 33u);
|
||||
|
||||
AppendEnd(&code);
|
||||
test.initial.resize(test.expected.size());
|
||||
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::BUFFER_LOAD_DWORD,
|
||||
O::V_ASHRREV_I64, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"OpShiftRightArithmetic", "OpTypeInt 64 0"};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorDynamicU64ShiftEdges() {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
@@ -26944,10 +27005,12 @@ TestCase VectorDynamicU64ShiftEdges() {
|
||||
// A buffer load prevents the constant-shift specialization.
|
||||
AppendVMovU32(&code, 30, index * sizeof(u32));
|
||||
AppendBufferLoadDword(&code, 3, 30);
|
||||
for (const bool left : {true, false}) {
|
||||
AppendVop3(&code, left ? 0x2ff : 0x300, 33, Vgpr(3), Vgpr(4));
|
||||
for (const u32 opcode : {0x2ffu, 0x300u, 0x301u}) {
|
||||
AppendVop3(&code, opcode, 33, Vgpr(3), Vgpr(4));
|
||||
const auto amount = test.initial[index] & 63u;
|
||||
const auto expected = left ? source << amount : source >> amount;
|
||||
const auto expected = opcode == 0x2ffu ? source << amount
|
||||
: opcode == 0x300u ? source >> amount
|
||||
: ReferenceAshrI64(source, amount);
|
||||
const auto output = static_cast<u32>(test.expected.size());
|
||||
AppendStoreVgpr(&code, 33, output);
|
||||
AppendStoreVgpr(&code, 34, output + 1u);
|
||||
@@ -26959,9 +27022,10 @@ TestCase VectorDynamicU64ShiftEdges() {
|
||||
AppendEnd(&code);
|
||||
test.initial.resize(test.expected.size());
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_LSHLREV_B64,
|
||||
O::V_LSHRREV_B64, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
O::V_LSHRREV_B64, O::V_ASHRREV_I64,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"OpShiftLeftLogical", "OpShiftRightLogical",
|
||||
"OpTypeInt 64 0"};
|
||||
"OpShiftRightArithmetic", "OpTypeInt 64 0"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -45911,6 +45975,7 @@ std::vector<TestCase> MakeCases() {
|
||||
cases.push_back(ScalarAshrI64Masks(32));
|
||||
cases.push_back(ScalarAshrI64Masks(64));
|
||||
AddCase(VectorDynamicU64ShiftEdges);
|
||||
AddCase(VectorVop3AshrrevI64Operands);
|
||||
AddCase(ScalarConditionalMoveB64);
|
||||
AddCase(ScalarConditionalMoveB64PreservesMasks);
|
||||
AddCase(ScalarAndn2B64SccUsesMaskShadow);
|
||||
@@ -53094,6 +53159,7 @@ int main(int argc, char **argv) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, ScalarDynamic64BitOps());
|
||||
RunCase(&vulkan, VectorDynamicU64ShiftEdges());
|
||||
RunCase(&vulkan, VectorVop3AshrrevI64Operands());
|
||||
RunCase(&vulkan, ScalarAshrI64Edges(false));
|
||||
RunCase(&vulkan, ScalarAshrI64Edges(true));
|
||||
RunCase(&vulkan, VectorCompareInteger64Edges());
|
||||
|
||||
@@ -10550,6 +10550,43 @@ void TestNewShaderRecompilerNativeU64Translation() {
|
||||
"captured VOP3 V_LSHLREV_B64 was not present in the decoded dump");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const uint32_t ashrrev_i64_shader[] = {
|
||||
0xd7010001u, 0x0000d50cu,
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
Decoder::Instruction decoded_ashrrev_i64;
|
||||
ShaderRecompiler::Decoder::DecodeInstruction(ashrrev_i64_shader, 0u,
|
||||
decoded_ashrrev_i64);
|
||||
Check(decoded_ashrrev_i64.opcode == Decoder::Opcode::V_ASHRREV_I64 &&
|
||||
decoded_ashrrev_i64.dst.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded_ashrrev_i64.dst.reg == 1u &&
|
||||
decoded_ashrrev_i64.src_count == 2u &&
|
||||
decoded_ashrrev_i64.src0.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded_ashrrev_i64.src0.reg == 12u &&
|
||||
decoded_ashrrev_i64.src1.kind == Decoder::OperandKind::VccLo,
|
||||
"decoder rejected VOP3 V_ASHRREV_I64 fields");
|
||||
result = RecompileForTest(ashrrev_i64_shader, options);
|
||||
Check((result.decoded_dump.find("V_ASHRREV_I64 v1, v12, vcc_lo") != std::string::npos),
|
||||
"VOP3 V_ASHRREV_I64 was not present in the decoded dump");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const uint32_t ashrrev_captured[] = {0xd7010007u, 0x00020498u, EncodeSopp(0x01)};
|
||||
Decoder::Instruction decoded_ashrrev_captured;
|
||||
ShaderRecompiler::Decoder::DecodeInstruction(ashrrev_captured, 0u,
|
||||
decoded_ashrrev_captured);
|
||||
Check(decoded_ashrrev_captured.opcode == Decoder::Opcode::V_ASHRREV_I64 &&
|
||||
decoded_ashrrev_captured.family == Decoder::Family::VOP3 &&
|
||||
decoded_ashrrev_captured.src_count == 2u &&
|
||||
decoded_ashrrev_captured.dst.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded_ashrrev_captured.dst.reg == 7u &&
|
||||
decoded_ashrrev_captured.src0.kind == Decoder::OperandKind::IntegerInlineConstant &&
|
||||
decoded_ashrrev_captured.src0.value == 24u &&
|
||||
decoded_ashrrev_captured.src1.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded_ashrrev_captured.src1.reg == 2u,
|
||||
"captured VOP3 V_ASHRREV_I64 opcode 0x301 was not decoded");
|
||||
result = RecompileForTest(ashrrev_captured, options);
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const uint32_t cmpx_i64_shader[] = {
|
||||
0xd4b5007eu, 0x00020e80u, // v_cmpx_ne_i64 exec, 0, v[7:8]
|
||||
EncodeSopp(0x01),
|
||||
|
||||
Reference in new issue
Block a user