From 3a8b6fccfc4fea7d1afd14ec6190a4ebd84aa2ef Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 4 Oct 2026 15:47:54 +1000 Subject: [PATCH] CPU/Recompiler: Trap constant signed arithmetic overflow Detect overflow in folded ADD, SUB and ADDI and use the interpreter exception path, including writes to zero and branch delay slots. --- src/core/cpu_recompiler.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/core/cpu_recompiler.cpp b/src/core/cpu_recompiler.cpp index 90d4a38ec..440d06b36 100644 --- a/src/core/cpu_recompiler.cpp +++ b/src/core/cpu_recompiler.cpp @@ -2117,10 +2117,14 @@ void CPU::Recompiler::Recompiler::Compile_divu_const(CompileFlags cf) void CPU::Recompiler::Recompiler::Compile_add_const(CompileFlags cf) { - // TODO: Overflow DebugAssert(HasConstantReg(cf.MipsS()) && HasConstantReg(cf.MipsT())); - if (MipsD() != Reg::zero) - SetConstantReg(MipsD(), GetConstantRegU32(cf.MipsS()) + GetConstantRegU32(cf.MipsT())); + const u32 rs = GetConstantRegU32(cf.MipsS()); + const u32 rt = GetConstantRegU32(cf.MipsT()); + const u32 result = rs + rt; + if (g_settings.cpu_recompiler_memory_exceptions && ((result ^ rs) & (result ^ rt) & 0x80000000u) != 0) + Compile_Fallback(); + else if (MipsD() != Reg::zero) + SetConstantReg(MipsD(), result); } void CPU::Recompiler::Recompiler::Compile_addu_const(CompileFlags cf) @@ -2131,10 +2135,14 @@ void CPU::Recompiler::Recompiler::Compile_addu_const(CompileFlags cf) void CPU::Recompiler::Recompiler::Compile_sub_const(CompileFlags cf) { - // TODO: Overflow DebugAssert(HasConstantReg(cf.MipsS()) && HasConstantReg(cf.MipsT())); - if (MipsD() != Reg::zero) - SetConstantReg(MipsD(), GetConstantRegU32(cf.MipsS()) - GetConstantRegU32(cf.MipsT())); + const u32 rs = GetConstantRegU32(cf.MipsS()); + const u32 rt = GetConstantRegU32(cf.MipsT()); + const u32 result = rs - rt; + if (g_settings.cpu_recompiler_memory_exceptions && ((result ^ rs) & (rs ^ rt) & 0x80000000u) != 0) + Compile_Fallback(); + else if (MipsD() != Reg::zero) + SetConstantReg(MipsD(), result); } void CPU::Recompiler::Recompiler::Compile_subu_const(CompileFlags cf) @@ -2145,10 +2153,14 @@ void CPU::Recompiler::Recompiler::Compile_subu_const(CompileFlags cf) void CPU::Recompiler::Recompiler::Compile_addi_const(CompileFlags cf) { - // TODO: Overflow DebugAssert(HasConstantReg(cf.MipsS())); - if (cf.MipsT() != Reg::zero) - SetConstantReg(cf.MipsT(), GetConstantRegU32(cf.MipsS()) + inst->i.imm_sext32()); + const u32 rs = GetConstantRegU32(cf.MipsS()); + const u32 imm = inst->i.imm_sext32(); + const u32 result = rs + imm; + if (g_settings.cpu_recompiler_memory_exceptions && ((result ^ rs) & (result ^ imm) & 0x80000000u) != 0) + Compile_Fallback(); + else if (cf.MipsT() != Reg::zero) + SetConstantReg(cf.MipsT(), result); } void CPU::Recompiler::Recompiler::Compile_addiu_const(CompileFlags cf)