diff --git a/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp b/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp index 425ef10a7..d25a94db5 100644 --- a/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp @@ -103,6 +103,7 @@ constexpr MemoryOpcodeInfo DS_OPCODE_LIST[] = { {0x4du, Opcode::DS_WRITE_B64, 2, 32}, {0x4eu, Opcode::DS_WRITE2_B64, 4, 32}, {0x4fu, Opcode::DS_WRITE2ST64_B64, 4, 32}, {0x76u, Opcode::DS_READ_B64, 2, 32}, {0x77u, Opcode::DS_READ2_B64, 4, 32}, {0x78u, Opcode::DS_READ2ST64_B64, 4, 32}, + {0xa1u, Opcode::DS_WRITE_B16_D16_HI, 1, 16}, {0xa6u, Opcode::DS_READ_U16_D16, 1, 16}, {0xa7u, Opcode::DS_READ_U16_D16_HI, 1, 16}, {0xb0u, Opcode::DS_WRITE_ADDTID_B32, 1, 32}, {0xb1u, Opcode::DS_READ_ADDTID_B32, 1, 32}, @@ -148,6 +149,7 @@ bool IsDsWriteOpcode(Opcode opcode) { switch (opcode) { case Opcode::DS_WRITE_B8: case Opcode::DS_WRITE_B16: + case Opcode::DS_WRITE_B16_D16_HI: case Opcode::DS_WRITE2_B32: case Opcode::DS_WRITE2ST64_B32: case Opcode::DS_WRITE2_B64: @@ -430,6 +432,9 @@ void DecodeDs(uint32_t pc, std::span code, uint32_t word_index, } DecodeVectorGpr(addr, inst.src0); DecodeVectorGpr(data0, inst.src1); + if (inst.opcode == Opcode::DS_WRITE_B16_D16_HI) { + inst.src1.sdwa_sel = 5u; + } DecodeVectorGpr(data1, inst.src2); inst.src_count = DsSourceCount(inst.opcode); } diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp index 771d6adc2..bd816435e 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp @@ -675,6 +675,7 @@ std::string InstructionToString(const Instruction& inst) { case Opcode::DS_READ_B128: case Opcode::DS_WRITE_B8: case Opcode::DS_WRITE_B16: + case Opcode::DS_WRITE_B16_D16_HI: case Opcode::DS_WRITE2_B32: case Opcode::DS_WRITE2ST64_B32: case Opcode::DS_WRITE2_B64: diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index 03bb8c06b..b4635ee65 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -510,6 +510,7 @@ enum class Opcode { DS_READ_B128, DS_WRITE_B8, DS_WRITE_B16, + DS_WRITE_B16_D16_HI, DS_WRITE2_B32, DS_WRITE2ST64_B32, DS_WRITE2_B64, diff --git a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp index c4ed21e13..f41e4b0bf 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp @@ -257,6 +257,7 @@ Decoder::Operand MemorySourceAt(const Decoder::Instruction& decoded, uint32_t in return index == 0u ? decoded.src1 : index == 1u ? decoded.src0 : decoded.src2; case Decoder::Opcode::DS_WRITE_B8: case Decoder::Opcode::DS_WRITE_B16: + case Decoder::Opcode::DS_WRITE_B16_D16_HI: case Decoder::Opcode::DS_WRITE_B32: case Decoder::Opcode::DS_WRITE_B64: case Decoder::Opcode::DS_WRITE_B96: @@ -1061,6 +1062,7 @@ bool Translator::EmitMemory(const Decoder::Instruction& inst, std::string* error case Decoder::Opcode::DS_WRITE2ST64_B64: return DS_WRITE2(inst); case Decoder::Opcode::DS_WRITE_B8: case Decoder::Opcode::DS_WRITE_B16: + case Decoder::Opcode::DS_WRITE_B16_D16_HI: case Decoder::Opcode::DS_WRITE_B32: case Decoder::Opcode::DS_WRITE_B64: case Decoder::Opcode::DS_WRITE_B96: diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 406d5a253..ddd0474c8 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -12027,6 +12027,7 @@ CoverageClass ClassifyOpcode(ShaderOpcode opcode, case Opcode::DS_READ_B128: case Opcode::DS_WRITE_B8: case Opcode::DS_WRITE_B16: + case Opcode::DS_WRITE_B16_D16_HI: case Opcode::DS_WRITE2_B32: case Opcode::DS_WRITE2ST64_B32: case Opcode::DS_WRITE_B32: @@ -18100,6 +18101,37 @@ TestCase DsReadU16D16CapturedPreservesHighHalf() { return test; } +TestCase DsWriteB16D16HiCapturedUsesHighHalf() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovU32(&code, 1, 0); + AppendVMovLiteral(&code, 3, 0xdeadbeefu); + code.push_back(EncodeDs0(0x0d)); + code.push_back(EncodeDs1(0, 3, 1)); // ds_write_b32 v1, v3 + + AppendVMovU32(&code, 20, 2); + AppendVMovLiteral(&code, 2, 0x1234abcdu); + AppendVMovLiteral(&code, 0, 0x87654321u); + code.push_back(0xda840000u); + code.push_back(0x00000214u); // captured ds_write_b16_d16_hi v20, v2 + + code.push_back(EncodeDs0(0x36)); + code.push_back(EncodeDs1(4, 0, 1)); // ds_read_b32 v4, v1 + AppendStoreVgpr(&code, 4, 0); + AppendStoreVgpr(&code, 0, 1); + AppendEnd(&code); + + TestCase test{"DsWriteB16D16HiCapturedUsesHighHalf", + code, + std::vector(2, 0), + {0x1234beefu, 0x87654321u}, + {O::V_MOV_B32, O::DS_WRITE_B32, O::DS_WRITE_B16_D16_HI, + O::DS_READ_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM}}; + test.decoded_counts = {{"DS_WRITE_B16_D16_HI", 1}}; + return test; +} + TestCase DsReadU16D16HiCapturedPreservesLowHalf() { using O = ShaderOpcode; @@ -20684,6 +20716,7 @@ std::vector MakeCases() { AddCase(ScratchIsPrivatePerInvocation); AddCase(FlatStoreVariants); AddCase(DsReadWriteVariants); + AddCase(DsWriteB16D16HiCapturedUsesHighHalf); AddCase(DsReadU16D16CapturedPreservesHighHalf); AddCase(DsReadU16D16HiCapturedPreservesLowHalf); AddCase(DsAppendConsumeUsesEncodedLdsSelector); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 5237b101d..62aa00173 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -4132,6 +4132,19 @@ void TestNewShaderDecoderArchitecture() { d16_hi.dst.sdwa_dst_unused == 2u && d16_hi.src0.reg == 6u, "DS decoder rejected the captured high-half D16 read"); + const uint32_t d16_hi_write_ds[] = {0xda840000u, 0x00000214u}; + Instruction d16_hi_write; + Check(DecodeInstruction(d16_hi_write_ds, 0u, d16_hi_write, &error), + error.c_str()); + Check(d16_hi_write.family == Family::DS && + d16_hi_write.opcode == Opcode::DS_WRITE_B16_D16_HI && + d16_hi_write.word_count == 2u && d16_hi_write.src_count == 2u && + d16_hi_write.data_dwords == 1u && d16_hi_write.data_bits == 16u && + d16_hi_write.offset == 0u && !d16_hi_write.gds && + d16_hi_write.src0.reg == 20u && d16_hi_write.src1.reg == 2u && + d16_hi_write.src1.sdwa_sel == 5u, + "DS decoder rejected the captured high-half D16 write"); + constexpr uint32_t packed_source_selectors[][2] = { {0xcc0e0000u, 0x0c0a0300u}, // Source 0: instruction bit 59. {0xcc0e0000u, 0x140a0300u}, // Source 1: instruction bit 60.