[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 <lizzie@eden-emu.dev> Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2907 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com> Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
318998cbb5
commit
8859809ebd
|
|
@ -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);
|
||||
|
|
@ -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<u64>(mem.rz_addr_offset.Value());
|
||||
return u64(mem.rz_addr_offset.Value());
|
||||
} else {
|
||||
return static_cast<u64>(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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue