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.
This commit is contained in:
Stenzek
2026-10-10 21:47:41 +10:00
parent bd29ee475f
commit 3a8b6fccfc
+21 -9
View File
@@ -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)