diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index 7a537c77b..908134dab 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -90,10 +90,18 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi) result = Compile_sll(cbi); break; + case InstructionFunct::sllv: + result = Compile_sllv(cbi); + break; + case InstructionFunct::srl: result = Compile_srl(cbi); break; + case InstructionFunct::srlv: + result = Compile_srlv(cbi); + break; + default: result = Compile_Fallback(cbi); break; @@ -589,6 +597,22 @@ bool CodeGenerator::Compile_sll(const CodeBlockInstruction& cbi) return true; } +bool CodeGenerator::Compile_sllv(const CodeBlockInstruction& cbi) +{ + InstructionPrologue(cbi, 1); + + // rd <- rt << rs + Value shift_amount = m_register_cache.ReadGuestRegister(cbi.instruction.r.rs); + if constexpr (!SHIFTS_ARE_IMPLICITLY_MASKED) + EmitAnd(shift_amount.host_reg, Value::FromConstantU32(0x1F)); + + m_register_cache.WriteGuestRegister( + cbi.instruction.r.rd, ShlValues(m_register_cache.ReadGuestRegister(cbi.instruction.r.rt), shift_amount)); + + InstructionEpilogue(cbi); + return true; +} + bool CodeGenerator::Compile_srl(const CodeBlockInstruction& cbi) { InstructionPrologue(cbi, 1); @@ -602,6 +626,22 @@ bool CodeGenerator::Compile_srl(const CodeBlockInstruction& cbi) return true; } +bool CodeGenerator::Compile_srlv(const CodeBlockInstruction& cbi) +{ + InstructionPrologue(cbi, 1); + + // rd <- rt << rs + Value shift_amount = m_register_cache.ReadGuestRegister(cbi.instruction.r.rs); + if constexpr (!SHIFTS_ARE_IMPLICITLY_MASKED) + EmitAnd(shift_amount.host_reg, Value::FromConstantU32(0x1F)); + + m_register_cache.WriteGuestRegister( + cbi.instruction.r.rd, ShrValues(m_register_cache.ReadGuestRegister(cbi.instruction.r.rt), shift_amount)); + + InstructionEpilogue(cbi); + return true; +} + bool CodeGenerator::Compile_addiu(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 a7d76b108..7ae804f11 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -158,7 +158,9 @@ private: bool Compile_lui(const CodeBlockInstruction& cbi); bool Compile_ori(const CodeBlockInstruction& cbi); bool Compile_sll(const CodeBlockInstruction& cbi); + bool Compile_sllv(const CodeBlockInstruction& cbi); bool Compile_srl(const CodeBlockInstruction& cbi); + bool Compile_srlv(const CodeBlockInstruction& cbi); bool Compile_addiu(const CodeBlockInstruction& cbi); Core* m_cpu; diff --git a/src/core/cpu_recompiler_types.h b/src/core/cpu_recompiler_types.h index d9a5f6ea3..38c37223b 100644 --- a/src/core/cpu_recompiler_types.h +++ b/src/core/cpu_recompiler_types.h @@ -37,6 +37,9 @@ constexpr RegSize HostPointerSize = RegSize_64; // A reasonable "maximum" number of bytes per instruction. constexpr u32 MAX_HOST_BYTES_PER_INSTRUCTION = 128; +// Are shifts implicitly masked to 0..31? +constexpr bool SHIFTS_ARE_IMPLICITLY_MASKED = true; + #else using HostReg = void; using CodeEmitter = void; @@ -46,6 +49,7 @@ enum : u32 }; constexpr HostReg HostReg_Invalid = static_cast(HostReg_Count); constexpr OperandSize HostPointerSize = OperandSize_64; +constexpr bool SHIFTS_ARE_IMPLICITLY_MASKED = false; #endif } // namespace Recompiler