@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-License-Identifier: GPL-2.0-or-later
@ -29,8 +32,8 @@ enum class AtomSize : u64 {
S64 ,
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 ) {
switch ( op ) {
case AtomOp : : ADD :
case AtomOp : : ADD :
return ir . GlobalAtomicIAdd ( offset , op_b ) ;
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 ) {
switch ( op ) {
case AtomOp : : ADD :
case AtomOp : : ADD :
return size = = AtomSize : : F32 ? ir . GlobalAtomicF32Add ( offset , op_b , f32_control )
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 :
case AtomOp : : MIN :
return ir . GlobalAtomicF16x2Min ( offset , op_b , f16_control ) ;
return ir . GlobalAtomicF16x2Min ( offset , op_b , f16_control ) ;
case AtomOp : : MAX :
case AtomOp : : MAX :
@ -90,30 +93,34 @@ IR::U64 AtomOffset(TranslatorVisitor& v, u64 insn) {
} const mem { insn } ;
} const mem { insn } ;
const IR : : U64 address { [ & ] ( ) - > IR : : U64 {
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 . ir . UConvert ( 64 , v . X ( mem . addr_reg ) ) ;
}
return v . L ( mem . addr_reg ) ;
return v . L ( mem . addr_reg ) ;
} ( ) } ;
} ( ) } ;
const u64 addr_offset { [ & ] ( ) - > u64 {
const u64 addr_offset { [ & ] ( ) - > u64 {
if ( mem . addr_reg = = IR : : Reg : : RZ ) {
if ( mem . addr_reg = = IR : : Reg : : RZ ) {
// When RZ is used, the address is an absolute address
// 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 {
} 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 ) ) ;
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 ) {
bool AtomOpNotApplicable ( AtomSize size , AtomOp op ) {
// TODO: SAFEADD
// TODO: SAFEADD
switch ( size ) {
switch ( size ) {
case AtomSize : : U32 :
case AtomSize : : S32 :
case AtomSize : : S32 :
case AtomSize : : U64 :
case AtomSize : : U64 :
return ( op = = AtomOp : : INC | | op = = AtomOp : : DEC ) ;
return ( op = = AtomOp : : INC | | op = = AtomOp : : DEC ) ;
case AtomSize : : S64 :
case AtomSize : : S64 :
return ! ( op = = AtomOp : : M IN | | op = = AtomOp : : MAX ) ;
return ( op = = AtomOp : : ADD | | op = = AtomOp : : INC | | op = = AtomOp : : DEC ) ;
case AtomSize : : F32 :
case AtomSize : : F32 :
return op ! = AtomOp : : ADD ;
return op ! = AtomOp : : ADD ;
case AtomSize : : F16x2 :
case AtomSize : : F16x2 :
@ -159,15 +166,14 @@ IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64&
switch ( size ) {
switch ( size ) {
case AtomSize : : U32 :
case AtomSize : : U32 :
case AtomSize : : S32 :
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 : : U64 :
case AtomSize : : S64 :
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 :
case AtomSize : : F32 :
return ApplyFpAtomOp ( v . ir , offset , v . F ( operand_reg ) , op , size ) ;
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 ) ;
return ApplyFpAtomOp ( v . ir , offset , v . ir . UnpackFloat2x16 ( v . X ( operand_reg ) ) , op , size ) ;
}
default :
default :
throw NotImplementedException ( " Atom Size {} " , size ) ;
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 ,
void GlobalAtomic ( TranslatorVisitor & v , IR : : Reg dest_reg , IR : : Reg operand_reg ,
const IR : : U64 & offset , AtomSize size , AtomOp op , bool write_dest ) {
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 ) ;
StoreResult ( v , dest_reg , result , size ) ;
}
}
}
} // Anonymous namespace
} // Anonymous namespace