diff --git a/src/graphics/shader/recompiler/frontend/decode/ScalarAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/ScalarAluOps.cpp index 5d39f9d8d..ee22e6c0f 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ScalarAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ScalarAluOps.cpp @@ -74,7 +74,8 @@ constexpr OpcodeMap SOPP_OPS[] = { {0x04u, Opcode::SCbranchScc0}, {0x05u, Opcode::SCbranchScc1}, {0x06u, Opcode::SCbranchVccz}, {0x07u, Opcode::SCbranchVccnz}, {0x08u, Opcode::SCbranchExecz}, {0x09u, Opcode::SCbranchExecnz}, {0x0au, Opcode::SBarrier}, {0x0cu, Opcode::SWaitcnt}, {0x0eu, Opcode::SSleep}, - {0x10u, Opcode::SSendmsg}, {0x16u, Opcode::STtraceData}, {0x20u, Opcode::SInstPrefetch}, + {0x10u, Opcode::SSendmsg}, {0x12u, Opcode::STrap}, {0x16u, Opcode::STtraceData}, + {0x20u, Opcode::SInstPrefetch}, }; static_assert(Detail::HasUniqueEncodings(SOP1_OPS)); static_assert(Detail::HasUniqueEncodings(SOP2_OPS)); @@ -257,15 +258,18 @@ bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index inst.opcode_id = opcode; inst.opcode = Detail::LookupOpcode(SOPP_OPS, opcode); inst.src0.kind = OperandKind::LiteralConstant; - inst.src0.value = simm; - inst.src0.signed_val = static_cast(simm); - inst.src_count = (inst.opcode == Opcode::SNop || inst.opcode == Opcode::SWaitcnt || - inst.opcode == Opcode::SSleep || inst.opcode == Opcode::SSendmsg || - inst.opcode == Opcode::STtraceData || inst.opcode == Opcode::SInstPrefetch) - ? 1 - : 0; - inst.branch_offset = static_cast(static_cast(simm)) * 4; - inst.branch_target = pc + 4u + static_cast(inst.branch_offset); + inst.src0.value = inst.opcode == Opcode::STrap ? simm & 0xffu : simm; + inst.src0.signed_val = inst.opcode == Opcode::STrap + ? static_cast(inst.src0.value) + : static_cast(static_cast(simm)); + inst.src_count = (inst.opcode == Opcode::SNop || inst.opcode == Opcode::SWaitcnt || + inst.opcode == Opcode::SSleep || inst.opcode == Opcode::SSendmsg || + inst.opcode == Opcode::STrap || inst.opcode == Opcode::STtraceData || + inst.opcode == Opcode::SInstPrefetch) + ? 1 + : 0; + inst.branch_offset = static_cast(static_cast(simm)) * 4; + inst.branch_target = pc + 4u + static_cast(inst.branch_offset); SetRawWords(inst, code, word_index, 1); if (inst.opcode == Opcode::Unsupported) { diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp index e2aa67bf0..712092a4c 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp @@ -937,6 +937,7 @@ std::string OpcodeToString(Opcode opcode) { case Opcode::SSendmsg: return "s_sendmsg"; case Opcode::SSetregB32: return "s_setreg_b32"; case Opcode::SSleep: return "s_sleep"; + case Opcode::STrap: return "s_trap"; case Opcode::STtraceData: return "s_ttracedata"; case Opcode::SInstPrefetch: return "s_inst_prefetch"; case Opcode::SEndpgm: return "s_endpgm"; @@ -1039,6 +1040,7 @@ std::string InstructionToString(const Instruction& inst) { case Opcode::SNop: case Opcode::SWaitcnt: case Opcode::SSleep: + case Opcode::STrap: case Opcode::SSendmsg: case Opcode::STtraceData: case Opcode::SInstPrefetch: diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index d83adb239..d56c4b562 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -537,6 +537,7 @@ enum class Opcode { SSendmsg, SSetregB32, SSleep, + STrap, STtraceData, SInstPrefetch, SEndpgm, diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.cpp b/src/graphics/shader/recompiler/ir/ShaderIR.cpp index 19004e9da..ef6824e3d 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIR.cpp @@ -1000,6 +1000,9 @@ bool LowerControlInstruction(const Decoder::Instruction& decoded, BasicBlock& bl case Decoder::Opcode::SSetregB32: case Decoder::Opcode::SSleep: return LowerControlMarker(decoded, block, Opcode::ControlNop, true, error); + case Decoder::Opcode::STrap: + // RDNA2 converts S_TRAP to a NOP when the unmodeled trap state is disabled. + return LowerControlMarker(decoded, block, Opcode::ControlNop, true, error); case Decoder::Opcode::STtraceData: return LowerControlMarker(decoded, block, Opcode::TtraceData, true, error); case Decoder::Opcode::SInstPrefetch: @@ -1076,6 +1079,7 @@ bool IsControlOpcode(Decoder::Opcode opcode) { case Decoder::Opcode::SSendmsg: case Decoder::Opcode::SSetregB32: case Decoder::Opcode::SSleep: + case Decoder::Opcode::STrap: case Decoder::Opcode::STtraceData: case Decoder::Opcode::SInstPrefetch: return true; default: return false; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 2806e0fb1..eb65ab57a 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -35,11 +35,11 @@ #include "graphics/host_gpu/vulkanCommon.h" #include "graphics/presentation/window/windowInternal.h" #include "graphics/shader/recompiler/ShaderRecompiler.h" -#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h" #include "graphics/shader/recompiler/backend/spirv/SpirvBuilder.h" #include "graphics/shader/recompiler/backend/spirv/SpirvEmitter.h" -#include "graphics/shader/recompiler/ir/passes/BindingLayout.h" +#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h" #include "graphics/shader/recompiler/ir/ValueProgram.h" +#include "graphics/shader/recompiler/ir/passes/BindingLayout.h" #include "graphics/shader/rectListShader.h" #include "graphics/shader/shader.h" #include "kernel/memory.h" @@ -1080,15 +1080,13 @@ CompiledShader CompileCase(const TestCase &test) { } for (const auto &[text, expected] : test.decoded_counts) { const auto actual = CountText(result.decoded_dump, text); - Require(test.name, "decoded RDNA2", - actual == expected, + Require(test.name, "decoded RDNA2", actual == expected, text + " count=" + std::to_string(actual) + ", expected=" + std::to_string(expected)); } for (const auto &[text, expected] : test.ir_counts) { const auto actual = CountText(result.ir_dump, text); - Require(test.name, "typed IR", - actual == expected, + Require(test.name, "typed IR", actual == expected, text + " count=" + std::to_string(actual) + ", expected=" + std::to_string(expected)); } @@ -10556,6 +10554,30 @@ TestCase Rdna2ScalarOpcodes() { O::VMovB32, O::BufferStoreDword, O::SEndpgm}}; } +TestCase ScalarTrapDisabledFallsThroughExactRaw() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovU32(&code, 0, 7); + code.push_back(0xbf920001u); // s_trap 1 from the game shader + AppendVMovU32(&code, 0, 42); + AppendStoreVgpr(&code, 0, 0); + AppendEnd(&code); + + TestCase test; + test.name = "ScalarTrapDisabledFallsThroughExactRaw"; + test.code = code; + test.expected = {42}; + test.opcodes = {O::VMovB32, O::STrap, O::BufferStoreDword, O::SEndpgm}; + test.decoded_counts = {{"s_trap 0x00000001", 1}}; + test.compute_info.threads_num[0] = 1; + test.compute_info.threads_num[1] = 1; + test.compute_info.threads_num[2] = 1; + test.compute_info.wave_size = 32; + test.has_compute_info = true; + return test; +} + TestCase ScalarExtendedArithmetic() { using O = ShaderOpcode; @@ -11721,9 +11743,9 @@ TestCase VectorSubrevCoCiU32ExactRawOnGpu() { test.name = "VectorSubrevCoCiU32ExactRawOnGpu"; test.code = code; test.expected = {0xdeadbeefu, 0, 2, 3, 0, 0, 0, 0}; - test.opcodes = {O::VMovB32, O::VLshlrevB32, O::VAddNcU32, - O::VCmpLtU32, O::SMovB64, O::VCmpNeU32, - O::VSubrevCoCiU32, O::VCndmaskB32, O::BufferStoreDword, + test.opcodes = {O::VMovB32, O::VLshlrevB32, O::VAddNcU32, + O::VCmpLtU32, O::SMovB64, O::VCmpNeU32, + O::VSubrevCoCiU32, O::VCndmaskB32, O::BufferStoreDword, O::SEndpgm}; test.required_spirv = {"OpISub", "OpUGreaterThan"}; test.compute_info.threads_num[0] = 4; @@ -16851,6 +16873,7 @@ std::vector MakeCases() { AddCase(ExactPushConstantExtent); AddCase(ScalarShiftCountsMaskLowBits); AddCase(Rdna2ScalarOpcodes); + AddCase(ScalarTrapDisabledFallsThroughExactRaw); AddCase(ScalarExtendedArithmetic); AddCase(ScalarArithmeticSccCarryBorrowOverflow); AddCase(ScalarMinMaxSccComparisonEdges);