mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-06 14:25:39 +00:00
CPU/Recompiler: Implement slt/sltu/slti/sltiu
This commit is contained in:
parent
bdc47319dc
commit
d2d0d5287b
|
@ -101,15 +101,20 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi)
|
||||||
result = Compile_Branch(cbi);
|
result = Compile_Branch(cbi);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstructionOp::lui:
|
|
||||||
result = Compile_lui(cbi);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case InstructionOp::addi:
|
case InstructionOp::addi:
|
||||||
case InstructionOp::addiu:
|
case InstructionOp::addiu:
|
||||||
result = Compile_Add(cbi);
|
result = Compile_Add(cbi);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::slti:
|
||||||
|
case InstructionOp::sltiu:
|
||||||
|
result = Compile_SetLess(cbi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::lui:
|
||||||
|
result = Compile_lui(cbi);
|
||||||
|
break;
|
||||||
|
|
||||||
case InstructionOp::funct:
|
case InstructionOp::funct:
|
||||||
{
|
{
|
||||||
switch (cbi.instruction.r.funct)
|
switch (cbi.instruction.r.funct)
|
||||||
|
@ -151,6 +156,11 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi)
|
||||||
result = Compile_Multiply(cbi);
|
result = Compile_Multiply(cbi);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InstructionFunct::slt:
|
||||||
|
case InstructionFunct::sltu:
|
||||||
|
result = Compile_SetLess(cbi);
|
||||||
|
break;
|
||||||
|
|
||||||
case InstructionFunct::jr:
|
case InstructionFunct::jr:
|
||||||
case InstructionFunct::jalr:
|
case InstructionFunct::jalr:
|
||||||
result = Compile_Branch(cbi);
|
result = Compile_Branch(cbi);
|
||||||
|
@ -1148,6 +1158,43 @@ bool CodeGenerator::Compile_Multiply(const CodeBlockInstruction& cbi)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CodeGenerator::Compile_SetLess(const CodeBlockInstruction& cbi)
|
||||||
|
{
|
||||||
|
InstructionPrologue(cbi, 1);
|
||||||
|
|
||||||
|
const bool signed_comparison =
|
||||||
|
(cbi.instruction.op == InstructionOp::slti ||
|
||||||
|
(cbi.instruction.op == InstructionOp::funct && cbi.instruction.r.funct == InstructionFunct::slt));
|
||||||
|
|
||||||
|
Reg dest;
|
||||||
|
Value lhs, rhs;
|
||||||
|
if (cbi.instruction.op == InstructionOp::slti || cbi.instruction.op == InstructionOp::sltiu)
|
||||||
|
{
|
||||||
|
// rt <- rs < {z,s}ext(imm)
|
||||||
|
dest = cbi.instruction.i.rt;
|
||||||
|
lhs = m_register_cache.ReadGuestRegister(cbi.instruction.i.rs, true, true);
|
||||||
|
rhs = Value::FromConstantU32(cbi.instruction.i.imm_sext32());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// rd <- rs < rt
|
||||||
|
dest = cbi.instruction.r.rd;
|
||||||
|
lhs = m_register_cache.ReadGuestRegister(cbi.instruction.r.rs, true, true);
|
||||||
|
rhs = m_register_cache.ReadGuestRegister(cbi.instruction.r.rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush the old value which might free up a register
|
||||||
|
m_register_cache.InvalidateGuestRegister(dest);
|
||||||
|
|
||||||
|
Value result = m_register_cache.AllocateScratch(RegSize_32);
|
||||||
|
EmitCmp(lhs.host_reg, rhs);
|
||||||
|
EmitSetConditionResult(result.host_reg, result.size, signed_comparison ? Condition::Less : Condition::Below);
|
||||||
|
m_register_cache.WriteGuestRegister(dest, std::move(result));
|
||||||
|
|
||||||
|
InstructionEpilogue(cbi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CodeGenerator::Compile_Branch(const CodeBlockInstruction& cbi)
|
bool CodeGenerator::Compile_Branch(const CodeBlockInstruction& cbi)
|
||||||
{
|
{
|
||||||
// Force sync since we branches are PC-relative.
|
// Force sync since we branches are PC-relative.
|
||||||
|
@ -1211,7 +1258,7 @@ bool CodeGenerator::Compile_Branch(const CodeBlockInstruction& cbi)
|
||||||
EmitCmp(lhs.host_reg, Value::FromConstantU32(0));
|
EmitCmp(lhs.host_reg, Value::FromConstantU32(0));
|
||||||
|
|
||||||
const Condition condition =
|
const Condition condition =
|
||||||
(cbi.instruction.op == InstructionOp::bgtz) ? Condition::Greater : Condition::LessOrEqual;
|
(cbi.instruction.op == InstructionOp::bgtz) ? Condition::Greater : Condition::LessEqual;
|
||||||
EmitBranch(condition, Reg::count, false, std::move(branch_target));
|
EmitBranch(condition, Reg::count, false, std::move(branch_target));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1253,4 +1300,5 @@ bool CodeGenerator::Compile_lui(const CodeBlockInstruction& cbi)
|
||||||
InstructionEpilogue(cbi);
|
InstructionEpilogue(cbi);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU::Recompiler
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
void EmitXor(HostReg to_reg, const Value& value);
|
void EmitXor(HostReg to_reg, const Value& value);
|
||||||
void EmitTest(HostReg to_reg, const Value& value);
|
void EmitTest(HostReg to_reg, const Value& value);
|
||||||
void EmitNot(HostReg to_reg, RegSize size);
|
void EmitNot(HostReg to_reg, RegSize size);
|
||||||
|
void EmitSetConditionResult(HostReg to_reg, RegSize to_size, Condition condition);
|
||||||
|
|
||||||
void EmitLoadGuestRegister(HostReg host_reg, Reg guest_reg);
|
void EmitLoadGuestRegister(HostReg host_reg, Reg guest_reg);
|
||||||
void EmitStoreGuestRegister(Reg guest_reg, const Value& value);
|
void EmitStoreGuestRegister(Reg guest_reg, const Value& value);
|
||||||
|
@ -181,6 +182,7 @@ private:
|
||||||
bool Compile_Add(const CodeBlockInstruction& cbi);
|
bool Compile_Add(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Subtract(const CodeBlockInstruction& cbi);
|
bool Compile_Subtract(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Multiply(const CodeBlockInstruction& cbi);
|
bool Compile_Multiply(const CodeBlockInstruction& cbi);
|
||||||
|
bool Compile_SetLess(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Branch(const CodeBlockInstruction& cbi);
|
bool Compile_Branch(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_lui(const CodeBlockInstruction& cbi);
|
bool Compile_lui(const CodeBlockInstruction& cbi);
|
||||||
|
|
||||||
|
|
|
@ -1081,6 +1081,75 @@ void CodeGenerator::EmitNot(HostReg to_reg, RegSize size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::EmitSetConditionResult(HostReg to_reg, RegSize to_size, Condition condition)
|
||||||
|
{
|
||||||
|
switch (condition)
|
||||||
|
{
|
||||||
|
case Condition::Always:
|
||||||
|
m_emit->mov(GetHostReg8(to_reg), 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::NotEqual:
|
||||||
|
m_emit->setne(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Equal:
|
||||||
|
m_emit->sete(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Overflow:
|
||||||
|
m_emit->seto(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Greater:
|
||||||
|
m_emit->setg(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::GreaterEqual:
|
||||||
|
m_emit->setge(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Less:
|
||||||
|
m_emit->setl(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::LessEqual:
|
||||||
|
m_emit->setle(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Negative:
|
||||||
|
m_emit->sets(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::PositiveOrZero:
|
||||||
|
m_emit->setns(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Above:
|
||||||
|
m_emit->seta(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::AboveEqual:
|
||||||
|
m_emit->setae(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Below:
|
||||||
|
m_emit->setb(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::BelowEqual:
|
||||||
|
m_emit->setbe(GetHostReg8(to_reg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
UnreachableCode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_size != RegSize_8)
|
||||||
|
EmitZeroExtend(to_reg, to_size, to_reg, RegSize_8);
|
||||||
|
}
|
||||||
|
|
||||||
u32 CodeGenerator::PrepareStackForCall()
|
u32 CodeGenerator::PrepareStackForCall()
|
||||||
{
|
{
|
||||||
// we assume that the stack is unaligned at this point
|
// we assume that the stack is unaligned at this point
|
||||||
|
@ -1634,7 +1703,7 @@ static void EmitConditionalJump(Condition condition, bool invert, Xbyak::CodeGen
|
||||||
invert ? emit->jnl(label) : emit->jl(label);
|
invert ? emit->jnl(label) : emit->jl(label);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Condition::LessOrEqual:
|
case Condition::LessEqual:
|
||||||
invert ? emit->jnle(label) : emit->jle(label);
|
invert ? emit->jnle(label) : emit->jle(label);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1646,6 +1715,22 @@ static void EmitConditionalJump(Condition condition, bool invert, Xbyak::CodeGen
|
||||||
invert ? emit->js(label) : emit->jns(label);
|
invert ? emit->js(label) : emit->jns(label);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Condition::Above:
|
||||||
|
invert ? emit->jna(label) : emit->ja(label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::AboveEqual:
|
||||||
|
invert ? emit->jnae(label) : emit->jae(label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Below:
|
||||||
|
invert ? emit->jnb(label) : emit->jb(label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::BelowEqual:
|
||||||
|
invert ? emit->jnbe(label) : emit->jbe(label);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UnreachableCode();
|
UnreachableCode();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -24,7 +24,7 @@ enum RegSize : u8
|
||||||
RegSize_64,
|
RegSize_64,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Condition: u8
|
enum class Condition : u8
|
||||||
{
|
{
|
||||||
Always,
|
Always,
|
||||||
NotEqual,
|
NotEqual,
|
||||||
|
@ -32,10 +32,14 @@ enum class Condition: u8
|
||||||
Overflow,
|
Overflow,
|
||||||
Greater,
|
Greater,
|
||||||
GreaterEqual,
|
GreaterEqual,
|
||||||
LessOrEqual,
|
LessEqual,
|
||||||
Less,
|
Less,
|
||||||
Negative,
|
Negative,
|
||||||
PositiveOrZero,
|
PositiveOrZero,
|
||||||
|
Above, // unsigned variant of Greater
|
||||||
|
AboveEqual, // unsigned variant of GreaterEqual
|
||||||
|
Below, // unsigned variant of Less
|
||||||
|
BelowEqual, // unsigned variant of LessEqual
|
||||||
|
|
||||||
NotZero = NotEqual,
|
NotZero = NotEqual,
|
||||||
Zero = Equal
|
Zero = Equal
|
||||||
|
|
Loading…
Reference in a new issue