From 8859809ebdb75913bed868e04886dd9c57084c27 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 28 Nov 2025 15:11:16 +0100 Subject: [PATCH] [maxwell] ATOM() has cases where it acts like a NOP (#2907) ATOM should be NOP in these cases May break games? May not break games! - But it **should** be correct to do this Signed-off-by: lizzie Co-authored-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2907 Reviewed-by: MaranBr Reviewed-by: Caio Oliveira Co-authored-by: lizzie Co-committed-by: lizzie --- .../impl/atomic_operations_global_memory.cpp | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp index a6be7c97eb..75087777dd 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -29,8 +32,8 @@ enum class AtomSize : u64 { S64, }; -IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, - AtomOp op, bool is_signed) { +IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, AtomOp op, AtomSize size) { + bool const is_signed = size == AtomSize::S64 || size == AtomSize::S32; switch (op) { case AtomOp::ADD: return ir.GlobalAtomicIAdd(offset, op_b); @@ -70,7 +73,7 @@ IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Valu switch (op) { case AtomOp::ADD: return size == AtomSize::F32 ? ir.GlobalAtomicF32Add(offset, op_b, f32_control) - : ir.GlobalAtomicF16x2Add(offset, op_b, f16_control); + : ir.GlobalAtomicF16x2Add(offset, op_b, f16_control); case AtomOp::MIN: return ir.GlobalAtomicF16x2Min(offset, op_b, f16_control); case AtomOp::MAX: @@ -90,30 +93,34 @@ IR::U64 AtomOffset(TranslatorVisitor& v, u64 insn) { } const mem{insn}; const IR::U64 address{[&]() -> IR::U64 { - if (mem.e == 0) { + if (mem.e == 0) return v.ir.UConvert(64, v.X(mem.addr_reg)); - } return v.L(mem.addr_reg); }()}; const u64 addr_offset{[&]() -> u64 { if (mem.addr_reg == IR::Reg::RZ) { // When RZ is used, the address is an absolute address - return static_cast(mem.rz_addr_offset.Value()); + return u64(mem.rz_addr_offset.Value()); } else { - return static_cast(mem.addr_offset.Value()); + return u64(mem.addr_offset.Value()); } }()}; return v.ir.IAdd(address, v.ir.Imm64(addr_offset)); } +// INC, DEC for U32/S32/U64 does nothing +// ADD, INC, DEC for S64 does nothing +// Only ADD does something for F32 +// Only ADD, MIN and MAX does something for F16x2 bool AtomOpNotApplicable(AtomSize size, AtomOp op) { // TODO: SAFEADD switch (size) { + case AtomSize::U32: case AtomSize::S32: case AtomSize::U64: return (op == AtomOp::INC || op == AtomOp::DEC); case AtomSize::S64: - return !(op == AtomOp::MIN || op == AtomOp::MAX); + return (op == AtomOp::ADD || op == AtomOp::INC || op == AtomOp::DEC); case AtomSize::F32: return op != AtomOp::ADD; case AtomSize::F16x2: @@ -159,15 +166,14 @@ IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64& switch (size) { case AtomSize::U32: case AtomSize::S32: - return ApplyIntegerAtomOp(v.ir, offset, v.X(operand_reg), op, size == AtomSize::S32); + return ApplyIntegerAtomOp(v.ir, offset, v.X(operand_reg), op, size); case AtomSize::U64: case AtomSize::S64: - return ApplyIntegerAtomOp(v.ir, offset, v.L(operand_reg), op, size == AtomSize::S64); + return ApplyIntegerAtomOp(v.ir, offset, v.L(operand_reg), op, size); case AtomSize::F32: return ApplyFpAtomOp(v.ir, offset, v.F(operand_reg), op, size); - case AtomSize::F16x2: { + case AtomSize::F16x2: return ApplyFpAtomOp(v.ir, offset, v.ir.UnpackFloat2x16(v.X(operand_reg)), op, size); - } default: throw NotImplementedException("Atom Size {}", size); } @@ -175,15 +181,11 @@ IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64& void GlobalAtomic(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, const IR::U64& offset, AtomSize size, AtomOp op, bool write_dest) { - IR::Value result; - if (AtomOpNotApplicable(size, op)) { - result = LoadGlobal(v.ir, offset, size); - } else { - result = ApplyAtomOp(v, operand_reg, offset, size, op); - } - if (write_dest) { + IR::Value result = AtomOpNotApplicable(size, op) + ? LoadGlobal(v.ir, offset, size) + : ApplyAtomOp(v, operand_reg, offset, size, op); + if (write_dest) StoreResult(v, dest_reg, result, size); - } } } // Anonymous namespace