diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index 3346906f7..a4918eccd 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -138,6 +138,11 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi) result = Compile_Add(cbi); break; + case InstructionFunct::sub: + case InstructionFunct::subu: + result = Compile_Subtract(cbi); + break; + case InstructionFunct::mult: case InstructionFunct::multu: result = Compile_Multiply(cbi); @@ -312,6 +317,46 @@ Value CodeGenerator::AddValues(const Value& lhs, const Value& rhs, bool set_flag } } +Value CodeGenerator::SubValues(const Value& lhs, const Value& rhs, bool set_flags) +{ + DebugAssert(lhs.size == rhs.size); + if (lhs.IsConstant() && rhs.IsConstant() && !set_flags) + { + // compile-time + u64 new_cv = lhs.constant_value - rhs.constant_value; + switch (lhs.size) + { + case RegSize_8: + return Value::FromConstantU8(Truncate8(new_cv)); + + case RegSize_16: + return Value::FromConstantU16(Truncate16(new_cv)); + + case RegSize_32: + return Value::FromConstantU32(Truncate32(new_cv)); + + case RegSize_64: + return Value::FromConstantU64(new_cv); + + default: + return Value(); + } + } + + Value res = m_register_cache.AllocateScratch(lhs.size); + if (rhs.HasConstantValue(0) && !set_flags) + { + EmitCopyValue(res.host_reg, lhs); + return res; + } + else + { + EmitCopyValue(res.host_reg, lhs); + EmitSub(res.host_reg, rhs, set_flags); + return res; + } +} + std::pair CodeGenerator::MulValues(const Value& lhs, const Value& rhs, bool signed_multiply) { DebugAssert(lhs.size == rhs.size); @@ -1051,6 +1096,26 @@ bool CodeGenerator::Compile_Add(const CodeBlockInstruction& cbi) return true; } +bool CodeGenerator::Compile_Subtract(const CodeBlockInstruction& cbi) +{ + InstructionPrologue(cbi, 1); + + Assert(cbi.instruction.op == InstructionOp::funct); + const bool check_overflow = (cbi.instruction.r.funct == InstructionFunct::sub); + + Value lhs = m_register_cache.ReadGuestRegister(cbi.instruction.r.rs); + Value rhs = m_register_cache.ReadGuestRegister(cbi.instruction.r.rt); + + Value result = SubValues(lhs, rhs, check_overflow); + if (check_overflow) + EmitRaiseException(Exception::Ov, Condition::Overflow); + + m_register_cache.WriteGuestRegister(cbi.instruction.r.rd, std::move(result)); + + InstructionEpilogue(cbi); + return true; +} + bool CodeGenerator::Compile_Multiply(const CodeBlockInstruction& cbi) { InstructionPrologue(cbi, 1); diff --git a/src/core/cpu_recompiler_code_generator.h b/src/core/cpu_recompiler_code_generator.h index 162a973eb..d1ab8af87 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -48,7 +48,7 @@ public: void EmitZeroExtend(HostReg to_reg, RegSize to_size, HostReg from_reg, RegSize from_size); void EmitCopyValue(HostReg to_reg, const Value& value); void EmitAdd(HostReg to_reg, const Value& value, bool set_flags); - void EmitSub(HostReg to_reg, const Value& value); + void EmitSub(HostReg to_reg, const Value& value, bool set_flags); void EmitCmp(HostReg to_reg, const Value& value); void EmitMul(HostReg to_reg_hi, HostReg to_reg_lo, const Value& lhs, const Value& rhs, bool signed_multiply); void EmitInc(HostReg to_reg, RegSize size); @@ -134,6 +134,7 @@ public: // Value ops Value AddValues(const Value& lhs, const Value& rhs, bool set_flags); + Value SubValues(const Value& lhs, const Value& rhs, bool set_flags); std::pair MulValues(const Value& lhs, const Value& rhs, bool signed_multiply); Value ShlValues(const Value& lhs, const Value& rhs); Value ShrValues(const Value& lhs, const Value& rhs); @@ -179,6 +180,7 @@ private: bool Compile_Store(const CodeBlockInstruction& cbi); bool Compile_MoveHiLo(const CodeBlockInstruction& cbi); bool Compile_Add(const CodeBlockInstruction& cbi); + bool Compile_Subtract(const CodeBlockInstruction& cbi); bool Compile_Multiply(const CodeBlockInstruction& cbi); bool Compile_Branch(const CodeBlockInstruction& cbi); bool Compile_lui(const CodeBlockInstruction& cbi); diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index bc8d0f4b0..ac23c8dfb 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -396,7 +396,7 @@ void CodeGenerator::EmitAdd(HostReg to_reg, const Value& value, bool set_flags) } } -void CodeGenerator::EmitSub(HostReg to_reg, const Value& value) +void CodeGenerator::EmitSub(HostReg to_reg, const Value& value, bool set_flags) { DebugAssert(value.IsConstant() || value.IsInHostRegister());