From e3a6e70d6028d5d6b2313b7f11fe377180a6f064 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 30 Jul 2025 10:22:26 +0200 Subject: [PATCH 1/2] Implement BufferAtomicFCmpSwap --- .../backend/spirv/emit_spirv_atomic.cpp | 21 +++++++++++++++++++ .../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, 40 insertions(+) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index fe2d64d2f0b..7ba14f1e344 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -111,6 +111,21 @@ Id BufferAtomicU32CmpSwap(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre }); } +Id BufferAtomicF32CmpSwap(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, + Id cmp_value, + Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id, Id, Id)) { + const auto& buffer = ctx.buffers[handle]; + if (const Id offset = buffer.Offset(PointerSize::B32); Sirit::ValidId(offset)) { + address = ctx.OpIAdd(ctx.F32[1], address, offset); + } + const auto [id, pointer_type] = buffer.Alias(PointerType::U32); + const Id ptr = ctx.OpAccessChain(pointer_type, id, ctx.f32_zero_value, address); + const auto [scope, semantics]{AtomicArgs(ctx)}; + return AccessBoundsCheck<32>(ctx, address, buffer.Size(PointerSize::B32), [&] { + return (ctx.*atomic_func)(ctx.F32[1], ptr, scope, semantics, semantics, value, cmp_value); + }); +} + Id BufferAtomicU64(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) { const auto& buffer = ctx.buffers[handle]; @@ -342,6 +357,12 @@ 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) { + return BufferAtomicF32CmpSwap(ctx, inst, handle, address, value, cmp_value, + &Sirit::Module::OpAtomicCompareExchange); +} + 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 a8c58bdba82..149c4231f20 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 ec9bc200dff..3de648552f8 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 @@ -415,6 +417,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 a6d43d10213..db32a464682 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -628,6 +628,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 e4afb8739b6..8b83cd15b56 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -166,6 +166,9 @@ class IREmitter { [[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 eaab05cb7da..d4f51748d4a 100644 --- a/src/shader_recompiler/ir/microinstruction.cpp +++ b/src/shader_recompiler/ir/microinstruction.cpp @@ -86,6 +86,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 280cd47ec9d..58f30a9dd67 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, U32, 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 2cf39c98e51..2b7926ac1a7 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -36,6 +36,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; From 932cde5975bf66b541be3c4e9abceda338a16e11 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 30 Jul 2025 10:40:33 +0200 Subject: [PATCH 2/2] clang --- src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp | 2 +- src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | 2 +- src/shader_recompiler/ir/ir_emitter.cpp | 2 +- src/shader_recompiler/ir/ir_emitter.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 7ba14f1e344..b4019e6e127 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -358,7 +358,7 @@ Id EmitBufferAtomicCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id ad } Id EmitBufferAtomicFCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, - Id cmp_value) { + Id cmp_value) { return BufferAtomicF32CmpSwap(ctx, inst, handle, address, value, cmp_value, &Sirit::Module::OpAtomicCompareExchange); } diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 149c4231f20..b716fc5d891 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -109,7 +109,7 @@ Id EmitBufferAtomicSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre 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 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/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index db32a464682..484fa9d7e5e 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -629,7 +629,7 @@ Value IREmitter::BufferAtomicCmpSwap(const Value& handle, const Value& address, } Value IREmitter::BufferAtomicFCmpSwap(const Value& handle, const Value& address, const Value& vdata, - const Value& cmp_value, BufferInstInfo info) { + const Value& cmp_value, BufferInstInfo info) { return Inst(Opcode::BufferAtomicFCmpSwap32, Flags{info}, handle, address, vdata, cmp_value); } diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 8b83cd15b56..40d8f39d60c 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -167,8 +167,8 @@ class IREmitter { 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); + const Value& value, const Value& cmp_value, + BufferInstInfo info); [[nodiscard]] U32 DataAppend(const U32& counter); [[nodiscard]] U32 DataConsume(const U32& counter);