From ede158f995f5b836f71215d5b3fb30800294e408 Mon Sep 17 00:00:00 2001 From: Kravickas Date: Tue, 31 Mar 2026 15:14:01 +0200 Subject: [PATCH] Implement BUFFER_ATOMIC_FCMPSWAP Implement BUFFER_ATOMIC_FCMPSWAP via descriptor aliasing + bitcast --- .../backend/spirv/emit_spirv_atomic.cpp | 9 +++++++++ .../backend/spirv/emit_spirv_instructions.h | 2 ++ .../frontend/translate/vector_memory.cpp | 6 ++++++ src/shader_recompiler/ir/ir_emitter.cpp | 5 +++++ src/shader_recompiler/ir/ir_emitter.h | 3 +++ src/shader_recompiler/ir/microinstruction.cpp | 1 + src/shader_recompiler/ir/opcodes.inc | 1 + .../ir/passes/resource_tracking_pass.cpp | 1 + 8 files changed, 28 insertions(+) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 1055bf081..6155bdb29 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -351,6 +351,15 @@ Id EmitBufferAtomicCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id ad &Sirit::Module::OpAtomicCompareExchange); } +Id EmitBufferAtomicFCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, + Id cmp_value) { + const auto u32_value = ctx.OpBitcast(ctx.U32[1], value); + const auto u32_cmp = ctx.OpBitcast(ctx.U32[1], cmp_value); + const auto result = BufferAtomicU32CmpSwap(ctx, inst, handle, address, u32_value, u32_cmp, + &Sirit::Module::OpAtomicCompareExchange); + return ctx.OpBitcast(ctx.F32[1], result); +} + Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value) { return ImageAtomicU32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicIAdd); } diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 69fa36eaa..da84e253c 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -108,6 +108,8 @@ Id EmitBufferAtomicXor32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addres Id EmitBufferAtomicSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value); Id EmitBufferAtomicCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, Id cmp_value); +Id EmitBufferAtomicFCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, + Id cmp_value); Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, u32 comp, u32 index); Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, u32 comp); void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 comp); diff --git a/src/shader_recompiler/frontend/translate/vector_memory.cpp b/src/shader_recompiler/frontend/translate/vector_memory.cpp index 0d9e8f220..85ce2311a 100644 --- a/src/shader_recompiler/frontend/translate/vector_memory.cpp +++ b/src/shader_recompiler/frontend/translate/vector_memory.cpp @@ -116,6 +116,8 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { return BUFFER_ATOMIC(AtomicOp::Fmin, inst); case Opcode::BUFFER_ATOMIC_FMAX: return BUFFER_ATOMIC(AtomicOp::Fmax, inst); + case Opcode::BUFFER_ATOMIC_FCMPSWAP: + return BUFFER_ATOMIC(AtomicOp::FCmpSwap, inst); // MIMG // Image load operations @@ -379,6 +381,10 @@ void Translator::BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst) { const IR::Value cmp_val = ir.GetVectorReg(vdata + 1); return ir.BufferAtomicCmpSwap(handle, address, vdata_val, cmp_val, buffer_info); } + case AtomicOp::FCmpSwap: { + const IR::Value cmp_val = ir.GetVectorReg(vdata + 1); + return ir.BufferAtomicFCmpSwap(handle, address, vdata_val, cmp_val, buffer_info); + } case AtomicOp::Add: return ir.BufferAtomicIAdd(handle, address, vdata_val, buffer_info); case AtomicOp::Smin: diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index c681c3120..922f01b1f 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -627,6 +627,11 @@ Value IREmitter::BufferAtomicCmpSwap(const Value& handle, const Value& address, return Inst(Opcode::BufferAtomicCmpSwap32, Flags{info}, handle, address, vdata, cmp_value); } +Value IREmitter::BufferAtomicFCmpSwap(const Value& handle, const Value& address, const Value& vdata, + const Value& cmp_value, BufferInstInfo info) { + return Inst(Opcode::BufferAtomicFCmpSwap32, Flags{info}, handle, address, vdata, cmp_value); +} + U32 IREmitter::DataAppend(const U32& counter) { return Inst(Opcode::DataAppend, counter, Imm32(0)); } diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index adc8f5fb1..ec0edfed4 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -166,6 +166,9 @@ public: [[nodiscard]] Value BufferAtomicCmpSwap(const Value& handle, const Value& address, const Value& value, const Value& cmp_value, BufferInstInfo info); + [[nodiscard]] Value BufferAtomicFCmpSwap(const Value& handle, const Value& address, + const Value& value, const Value& cmp_value, + BufferInstInfo info); [[nodiscard]] U32 DataAppend(const U32& counter); [[nodiscard]] U32 DataConsume(const U32& counter); diff --git a/src/shader_recompiler/ir/microinstruction.cpp b/src/shader_recompiler/ir/microinstruction.cpp index cd0131770..837b9601e 100644 --- a/src/shader_recompiler/ir/microinstruction.cpp +++ b/src/shader_recompiler/ir/microinstruction.cpp @@ -82,6 +82,7 @@ bool Inst::MayHaveSideEffects() const noexcept { case Opcode::BufferAtomicXor32: case Opcode::BufferAtomicSwap32: case Opcode::BufferAtomicCmpSwap32: + case Opcode::BufferAtomicFCmpSwap32: case Opcode::DataAppend: case Opcode::DataConsume: case Opcode::WriteSharedU16: diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 6304a96fa..ebbc702b7 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -150,6 +150,7 @@ OPCODE(BufferAtomicOr32, U32, Opaq OPCODE(BufferAtomicXor32, U32, Opaque, Opaque, U32, ) OPCODE(BufferAtomicSwap32, U32, Opaque, Opaque, U32, ) OPCODE(BufferAtomicCmpSwap32, U32, Opaque, Opaque, U32, U32, ) +OPCODE(BufferAtomicFCmpSwap32, F32, Opaque, Opaque, F32, F32, ) // Vector utility OPCODE(CompositeConstructU32x2, U32x2, U32, U32, ) diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 3b7888ab3..0b256a349 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -39,6 +39,7 @@ bool IsBufferAtomic(const IR::Inst& inst) { case IR::Opcode::BufferAtomicXor32: case IR::Opcode::BufferAtomicSwap32: case IR::Opcode::BufferAtomicCmpSwap32: + case IR::Opcode::BufferAtomicFCmpSwap32: return true; default: return false;