diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h index ec77d3268..b4add49be 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h @@ -291,6 +291,7 @@ inline constexpr auto EmitBufferAtomicIAdd32 = EmitAtomic32; inline constexpr auto EmitBufferAtomicISub32 = EmitAtomic32; inline constexpr auto EmitBufferAtomicSMin32 = EmitAtomic32; inline constexpr auto EmitBufferAtomicUMin32 = EmitAtomic32; +inline constexpr auto EmitBufferAtomicUMin64 = EmitBufferAtomic64; inline constexpr auto EmitBufferAtomicSMax32 = EmitAtomic32; inline constexpr auto EmitBufferAtomicUMax32 = EmitAtomic32; inline constexpr auto EmitBufferAtomicAnd32 = EmitAtomic32; diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp index e8ad71d9a..1dd1ee6a1 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp @@ -585,6 +585,7 @@ spv::Op SpirvAtomicOpcode(IR::ValueOpcode opcode) { case IR::ValueOpcode::ImageAtomicUMin32: case IR::ValueOpcode::ImageAtomicUMin64: case IR::ValueOpcode::BufferAtomicUMin32: + case IR::ValueOpcode::BufferAtomicUMin64: case IR::ValueOpcode::SharedAtomicUMin32: return spv::OpAtomicUMin; case IR::ValueOpcode::ImageAtomicSMax32: case IR::ValueOpcode::BufferAtomicSMax32: diff --git a/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp b/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp index 8ab805419..c3003ab15 100644 --- a/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/MemoryOps.cpp @@ -69,6 +69,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = { {0x40u, Opcode::BUFFER_ATOMIC_FMAX, 1, 32}, {0x50u, Opcode::BUFFER_ATOMIC_SWAP_X2, 2, 32}, {0x52u, Opcode::BUFFER_ATOMIC_ADD_X2, 2, 32}, + {0x56u, Opcode::BUFFER_ATOMIC_UMIN_X2, 2, 32}, {0x59u, Opcode::BUFFER_ATOMIC_AND_X2, 2, 32}, {0x5au, Opcode::BUFFER_ATOMIC_OR_X2, 2, 32}, {0x71u, Opcode::BUFFER_GL0_INV, 0, 0}, diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp index 2792f4cf6..d77c02b07 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp @@ -664,6 +664,7 @@ std::string InstructionToString(const Instruction& inst) { case Opcode::BUFFER_ATOMIC_SUB: case Opcode::BUFFER_ATOMIC_SMIN: case Opcode::BUFFER_ATOMIC_UMIN: + case Opcode::BUFFER_ATOMIC_UMIN_X2: case Opcode::BUFFER_ATOMIC_SMAX: case Opcode::BUFFER_ATOMIC_UMAX: case Opcode::BUFFER_ATOMIC_AND: diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index b62d4b89d..6b9032877 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -596,6 +596,7 @@ enum class Opcode { BUFFER_ATOMIC_SUB, BUFFER_ATOMIC_SMIN, BUFFER_ATOMIC_UMIN, + BUFFER_ATOMIC_UMIN_X2, BUFFER_ATOMIC_SMAX, BUFFER_ATOMIC_UMAX, BUFFER_ATOMIC_AND, diff --git a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp index 6e91cfac3..b4058ce4a 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp @@ -1029,6 +1029,8 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) { return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicSMin32); case Decoder::Opcode::BUFFER_ATOMIC_UMIN: return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicUMin32); + case Decoder::Opcode::BUFFER_ATOMIC_UMIN_X2: + return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicUMin64); case Decoder::Opcode::BUFFER_ATOMIC_SMAX: return BUFFER_ATOMIC(inst, IR::ValueOpcode::BufferAtomicSMax32); case Decoder::Opcode::BUFFER_ATOMIC_UMAX: diff --git a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp index 10fb4b79a..3beebab9b 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp +++ b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp @@ -123,6 +123,7 @@ BufferAccess BufferAccessOf(ValueOpcode opcode) { case ValueOpcode::BufferAtomicISub32: case ValueOpcode::BufferAtomicSMin32: case ValueOpcode::BufferAtomicUMin32: + case ValueOpcode::BufferAtomicUMin64: case ValueOpcode::BufferAtomicSMax32: case ValueOpcode::BufferAtomicUMax32: case ValueOpcode::BufferAtomicAnd32: @@ -140,6 +141,7 @@ uint32_t BufferComponentCount(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::BufferAtomicSwap64: case ValueOpcode::BufferAtomicIAdd64: + case ValueOpcode::BufferAtomicUMin64: case ValueOpcode::BufferAtomicAnd64: case ValueOpcode::BufferAtomicOr64: case ValueOpcode::LoadBufferU32x2: diff --git a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc index c3e6440af..5cff6d0dd 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc +++ b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc @@ -269,6 +269,7 @@ VALUE_OPCODE(BufferAtomicIAdd64, U64, BufferResource, U32, U32, U32, U64, U1) VALUE_OPCODE(BufferAtomicISub32, U32, BufferResource, U32, U32, U32, U32, U1) VALUE_OPCODE(BufferAtomicSMin32, U32, BufferResource, U32, U32, U32, U32, U1) VALUE_OPCODE(BufferAtomicUMin32, U32, BufferResource, U32, U32, U32, U32, U1) +VALUE_OPCODE(BufferAtomicUMin64, U64, BufferResource, U32, U32, U32, U64, U1) VALUE_OPCODE(BufferAtomicSMax32, U32, BufferResource, U32, U32, U32, U32, U1) VALUE_OPCODE(BufferAtomicUMax32, U32, BufferResource, U32, U32, U32, U32, U1) VALUE_OPCODE(BufferAtomicAnd32, U32, BufferResource, U32, U32, U32, U32, U1) diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 9dbbed904..bfd4bad7a 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -22674,6 +22674,7 @@ CoverageClass ClassifyOpcode(ShaderOpcode opcode, case Opcode::BUFFER_ATOMIC_SUB: case Opcode::BUFFER_ATOMIC_SMIN: case Opcode::BUFFER_ATOMIC_UMIN: + case Opcode::BUFFER_ATOMIC_UMIN_X2: case Opcode::BUFFER_ATOMIC_SMAX: case Opcode::BUFFER_ATOMIC_UMAX: case Opcode::BUFFER_ATOMIC_AND: @@ -38260,6 +38261,41 @@ TestCase BufferAtomicAddX2GlcAndExec() { return test; } +TestCase BufferAtomicUMinX2GlcAndExec() { + using O = ShaderOpcode; + TestCase test; + test.name = "BufferAtomicUMinX2GlcAndExec"; + auto &code = test.code; + code.push_back(EncodeSop1(0x04, 12, 126)); + AppendVMovU32(&code, 20, 0); + const u32 values[][2] = {{0xffffffffu, 0x80000000u}, + {0xffffffffu, 0x7fffffffu}, + {0xfffffffeu, 0x7fffffffu}, + {0u, 0u}}; + for (u32 i = 0; i < std::size(values); ++i) { + AppendVMovLiteral(&code, 2, values[i][0]); + AppendVMovLiteral(&code, 3, values[i][1]); + if (i == 3) { + code.push_back(EncodeSop1(0x04, 126, InlineU32(0))); + } + AppendBufferStoreOpcode(&code, 0x56, 2, 20, i != 1); + code.push_back(EncodeSop1(0x04, 126, 12)); + AppendStoreVgpr(&code, 2, 2 + i * 2); + AppendStoreVgpr(&code, 3, 3 + i * 2); + } + AppendEnd(&code); + test.initial = {0u, 0x80000001u, 0, 0, 0, 0, 0, 0, 1, 1}; + // The high dwords decide the first two mins, the second only when compared + // unsigned, and the low dwords the third. GLC returns the old value, the + // second min keeps its operand, and EXEC = 0 suppresses the fourth min. + test.expected = {0xfffffffeu, 0x7fffffffu, 0u, 0x80000001u, + 0xffffffffu, 0x7fffffffu, 0xffffffffu, 0x7fffffffu, 0, 0}; + test.opcodes = {O::V_MOV_B32, O::S_MOV_B64, O::BUFFER_ATOMIC_UMIN_X2, + O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.required_spirv = {"OpAtomicUMin %ulong", "Int64Atomics"}; + return test; +} + TestCase BufferAtomicCmpSwapExactRaw() { using O = ShaderOpcode; @@ -46013,6 +46049,7 @@ std::vector MakeCases() { } AddCase(BufferAtomicAndX2GlcAndExec); AddCase(BufferAtomicAddX2GlcAndExec); + AddCase(BufferAtomicUMinX2GlcAndExec); AddCase(ImageAtomicSignedMinMax); AddCase(ImageAtomicSignedMinMax); AddCase(ImageAtomicSignedMinMax); @@ -52221,6 +52258,7 @@ int main(int argc, char **argv) { RunCase(&vulkan, DsAtomicReturn64()); RunCase(&vulkan, BufferAtomicAndX2GlcAndExec()); RunCase(&vulkan, BufferAtomicAddX2GlcAndExec()); + RunCase(&vulkan, BufferAtomicUMinX2GlcAndExec()); RunCase(&vulkan, ImageAtomicSignedMinMax()); RunCase(&vulkan, ImageAtomicSignedMinMax()); return 0; diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 9971d0231..99a8489f0 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -10809,6 +10809,8 @@ void TestCapturedBufferAtomicsX2() { "BufferAtomicIAdd64", "OpAtomicIAdd", ValueOpcode::BufferAtomicIAdd64}, {{0xe1680018u, 0x80000000u}, 0u, 241u, "BUFFER_ATOMIC_OR_X2", "BufferAtomicOr64", "OpAtomicOr", ValueOpcode::BufferAtomicOr64}, + {{0xe1582000u, 0x8003092au}, 9u, 237u, "BUFFER_ATOMIC_UMIN_X2", + "BufferAtomicUMin64", "OpAtomicUMin", ValueOpcode::BufferAtomicUMin64}, {{0xe1402000u, 0x80000913u}, 9u, 229u, "BUFFER_ATOMIC_SWAP_X2", "BufferAtomicSwap64", "OpAtomicExchange", ValueOpcode::BufferAtomicSwap64}, };