CPU/Interpreter: Use __builtin_{add,sub}_overflow for exceptions

Recompiler already does this.
This commit is contained in:
Stenzek 2025-03-07 15:48:25 +10:00
parent 7eb7ad684c
commit 9939f1cd05
No known key found for this signature in database

View File

@ -811,14 +811,26 @@ const std::array<CPU::DebuggerRegisterListEntry, CPU::NUM_DEBUGGER_REGISTER_LIST
{"ZSF4", &CPU::g_state.gte_regs.r32[62]}, {"ZSF4", &CPU::g_state.gte_regs.r32[62]},
{"FLAG", &CPU::g_state.gte_regs.r32[63]}}}; {"FLAG", &CPU::g_state.gte_regs.r32[63]}}};
ALWAYS_INLINE static constexpr bool AddOverflow(u32 old_value, u32 add_value, u32 new_value) ALWAYS_INLINE static constexpr bool AddOverflow(u32 old_value, u32 add_value, u32* new_value)
{ {
return (((new_value ^ old_value) & (new_value ^ add_value)) & UINT32_C(0x80000000)) != 0; #if defined(__clang__) || defined(__GNUC__)
return __builtin_add_overflow(static_cast<s32>(old_value), static_cast<s32>(add_value),
reinterpret_cast<s32*>(new_value));
#else
*new_value = old_value + add_value;
return (((*new_value ^ old_value) & (*new_value ^ add_value)) & UINT32_C(0x80000000)) != 0;
#endif
} }
ALWAYS_INLINE static constexpr bool SubOverflow(u32 old_value, u32 sub_value, u32 new_value) ALWAYS_INLINE static constexpr bool SubOverflow(u32 old_value, u32 sub_value, u32* new_value)
{ {
return (((new_value ^ old_value) & (old_value ^ sub_value)) & UINT32_C(0x80000000)) != 0; #if defined(__clang__) || defined(__GNUC__)
return __builtin_sub_overflow(static_cast<s32>(old_value), static_cast<s32>(sub_value),
reinterpret_cast<s32*>(new_value));
#else
*new_value = old_value - sub_value;
return (((*new_value ^ old_value) & (old_value ^ sub_value)) & UINT32_C(0x80000000)) != 0;
#endif
} }
void CPU::DisassembleAndPrint(u32 addr, bool regs, const char* prefix) void CPU::DisassembleAndPrint(u32 addr, bool regs, const char* prefix)
@ -999,8 +1011,8 @@ restart_instruction:
{ {
const u32 rsVal = ReadReg(inst.r.rs); const u32 rsVal = ReadReg(inst.r.rs);
const u32 rtVal = ReadReg(inst.r.rt); const u32 rtVal = ReadReg(inst.r.rt);
const u32 rdVal = rsVal + rtVal; u32 rdVal;
if (AddOverflow(rsVal, rtVal, rdVal)) if (AddOverflow(rsVal, rtVal, &rdVal)) [[unlikely]]
{ {
RaiseException(Exception::Ov); RaiseException(Exception::Ov);
return; return;
@ -1033,8 +1045,8 @@ restart_instruction:
{ {
const u32 rsVal = ReadReg(inst.r.rs); const u32 rsVal = ReadReg(inst.r.rs);
const u32 rtVal = ReadReg(inst.r.rt); const u32 rtVal = ReadReg(inst.r.rt);
const u32 rdVal = rsVal - rtVal; u32 rdVal;
if (SubOverflow(rsVal, rtVal, rdVal)) if (SubOverflow(rsVal, rtVal, &rdVal)) [[unlikely]]
{ {
RaiseException(Exception::Ov); RaiseException(Exception::Ov);
return; return;
@ -1296,8 +1308,8 @@ restart_instruction:
{ {
const u32 rsVal = ReadReg(inst.i.rs); const u32 rsVal = ReadReg(inst.i.rs);
const u32 imm = inst.i.imm_sext32(); const u32 imm = inst.i.imm_sext32();
const u32 rtVal = rsVal + imm; u32 rtVal;
if (AddOverflow(rsVal, imm, rtVal)) if (AddOverflow(rsVal, imm, &rtVal)) [[unlikely]]
{ {
RaiseException(Exception::Ov); RaiseException(Exception::Ov);
return; return;
@ -1844,7 +1856,7 @@ restart_instruction:
case InstructionOp::cop2: case InstructionOp::cop2:
{ {
if (!g_state.cop0_regs.sr.CE2) if (!g_state.cop0_regs.sr.CE2) [[unlikely]]
{ {
WARNING_LOG("Coprocessor 2 not enabled"); WARNING_LOG("Coprocessor 2 not enabled");
RaiseException(Exception::CpU); RaiseException(Exception::CpU);
@ -1916,7 +1928,7 @@ restart_instruction:
case InstructionOp::lwc2: case InstructionOp::lwc2:
{ {
if (!g_state.cop0_regs.sr.CE2) if (!g_state.cop0_regs.sr.CE2) [[unlikely]]
{ {
WARNING_LOG("Coprocessor 2 not enabled"); WARNING_LOG("Coprocessor 2 not enabled");
RaiseException(Exception::CpU); RaiseException(Exception::CpU);
@ -1937,7 +1949,7 @@ restart_instruction:
case InstructionOp::swc2: case InstructionOp::swc2:
{ {
if (!g_state.cop0_regs.sr.CE2) if (!g_state.cop0_regs.sr.CE2) [[unlikely]]
{ {
WARNING_LOG("Coprocessor 2 not enabled"); WARNING_LOG("Coprocessor 2 not enabled");
RaiseException(Exception::CpU); RaiseException(Exception::CpU);
@ -1969,6 +1981,7 @@ restart_instruction:
break; break;
// everything else is reserved/invalid // everything else is reserved/invalid
[[unlikely]]
default: default:
{ {
u32 ram_value; u32 ram_value;