diff --git a/src/core/arm/jit_x64/cond.cpp b/src/core/arm/jit_x64/cond.cpp index 376b27f26..873b139a1 100644 --- a/src/core/arm/jit_x64/cond.cpp +++ b/src/core/arm/jit_x64/cond.cpp @@ -24,6 +24,7 @@ void JitX64::CondManager::CompileCond(const ConditionCode new_cond) { if (current_cond != ConditionCode::AL && current_cond != ConditionCode::NV) { jit->reg_alloc.FlushEverything(); + jit->reg_alloc.AssertNoLocked(); ASSERT(current_cond_fixup.ptr); jit->code->SetJumpTarget(current_cond_fixup); current_cond_fixup.ptr = nullptr; @@ -123,6 +124,7 @@ void JitX64::CondManager::CompileCond(const ConditionCode new_cond) { } jit->reg_alloc.FlushEverything(); + jit->reg_alloc.AssertNoLocked(); this->current_cond_fixup = jit->code->J_CC(cc, true); } diff --git a/src/core/arm/jit_x64/instructions/data_processing.cpp b/src/core/arm/jit_x64/instructions/data_processing.cpp index aeec093a2..c1e76b61a 100644 --- a/src/core/arm/jit_x64/instructions/data_processing.cpp +++ b/src/core/arm/jit_x64/instructions/data_processing.cpp @@ -10,48 +10,41 @@ namespace JitX64 { using namespace Gen; -void JitX64::ADC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { - cond_manager.CompileCond((ConditionCode)cond); - - u32 immediate = _rotr(imm8, rotate * 2); +void JitX64::CompileDataProcessingHelper(ArmReg Rn_index, ArmReg Rd_index, std::function body) { + // The major consideration is if Rn and/or Rd == R15. if (Rd_index == 15) { X64Reg Rd = reg_alloc.AllocAndLockTemp(); reg_alloc.LockArm(Rn_index); if (Rn_index == 15) { + // TODO: In this case we can actually calculat the final result. + // We can also use CompileJumpToBB instead of having to use CompileReturnToDispatch. code->MOV(32, R(Rd), Imm32(GetReg15Value())); } else { - code->MOV(32, R(Rd), reg_alloc.ArmR(Rd_index)); + code->MOV(32, R(Rd), reg_alloc.ArmR(Rn_index)); } - code->BT(32, MJitStateCFlag(), Imm8(0)); - code->ADC(32, R(Rd), Imm32(immediate)); + + body(Rd); reg_alloc.UnlockArm(Rn_index); - if (S) - UNIMPLEMENTED(); - code->MOV(32, MJitStateArmPC(), R(Rd)); reg_alloc.UnlockTemp(Rd); - current.arm_pc += GetInstSize(); - CompileReturnToDispatch(); - return; } else if (Rn_index == 15) { X64Reg Rd = reg_alloc.BindNoLoadAndLockArm(Rd_index); reg_alloc.MarkDirty(Rd_index); code->MOV(32, R(Rd), Imm32(GetReg15Value())); - code->BT(32, MJitStateCFlag(), Imm8(0)); - code->ADC(32, R(Rd), Imm32(immediate)); + + body(Rd); reg_alloc.UnlockArm(Rd_index); } else if (Rn_index == Rd_index) { X64Reg Rd = reg_alloc.BindAndLockArm(Rd_index); reg_alloc.MarkDirty(Rd_index); - code->BT(32, MJitStateCFlag(), Imm8(0)); - code->ADC(32, R(Rd), Imm32(immediate)); + body(Rd); reg_alloc.UnlockArm(Rd_index); } else { @@ -60,67 +53,471 @@ void JitX64::ADC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int ro reg_alloc.LockArm(Rn_index); code->MOV(32, R(Rd), reg_alloc.ArmR(Rn_index)); - code->BT(32, MJitStateCFlag(), Imm8(0)); - code->ADC(32, R(Rd), Imm32(immediate)); + + body(Rd); reg_alloc.UnlockArm(Rd_index); reg_alloc.UnlockArm(Rn_index); } +} + +void JitX64::CompileDataProcessingHelper_Reverse(ArmReg Rn_index, ArmReg Rd_index, std::function body) { + // The major consideration is if Rn and/or Rd == R15. + + if (Rd_index != Rn_index) { + + X64Reg Rd = INVALID_REG; + + if (Rd_index == 15) { + Rd = reg_alloc.AllocAndLockTemp(); + } else { + Rd = reg_alloc.BindNoLoadAndLockArm(Rd_index); + reg_alloc.MarkDirty(Rd_index); + } + + body(Rd); + + if (Rd_index == 15) { + code->MOV(32, MJitStateArmPC(), R(Rd)); + reg_alloc.UnlockTemp(Rd); + } else { + reg_alloc.UnlockArm(Rd_index); + } + + } else { + + X64Reg tmp = reg_alloc.AllocAndLockTemp(); + + body(tmp); + + // TODO: Efficiency: Could implement this as a register rebind instead of needing to MOV. + reg_alloc.LockArm(Rd_index); + code->MOV(32, reg_alloc.ArmR(Rd_index), R(tmp)); + reg_alloc.UnlockArm(Rd_index); + reg_alloc.UnlockTemp(tmp); + + } +} + +void JitX64::ADC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->BT(32, MJitStateCFlag(), Imm8(0)); + code->ADC(32, R(Rd), Imm32(immediate)); + }); if (S) { cond_manager.FlagsDirty(); UpdateFlagsZVCN(); } + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::ADD_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->ADD(32, R(Rd), Imm32(immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZVCN(); + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::AND_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->AND(32, R(Rd), Imm32(immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::BIC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->AND(32, R(Rd), Imm32(~immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::CMN_imm(Cond cond, ArmReg Rn_index, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::CMP_imm(Cond cond, ArmReg Rn_index, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } + +void JitX64::EOR_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->XOR(32, R(Rd), Imm32(immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::MOV_imm(Cond cond, bool S, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + if (Rd_index != 15) { + reg_alloc.LockArm(Rd_index); + code->MOV(32, reg_alloc.ArmR(Rd_index), Imm32(immediate)); + reg_alloc.UnlockArm(Rd_index); + } else { + code->MOV(32, MJitStateArmPC(), Imm32(immediate)); + } + + if (S) { + cond_manager.FlagsDirty(); + reg_alloc.LockArm(Rd_index); + code->CMP(32, reg_alloc.ArmR(Rd_index), Imm32(0)); + reg_alloc.UnlockArm(Rd_index); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::MVN_imm(Cond cond, bool S, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + if (Rd_index != 15) { + reg_alloc.LockArm(Rd_index); + code->MOV(32, reg_alloc.ArmR(Rd_index), Imm32(~immediate)); + reg_alloc.UnlockArm(Rd_index); + } else { + code->MOV(32, MJitStateArmPC(), Imm32(~immediate)); + } + + if (S) { + cond_manager.FlagsDirty(); + reg_alloc.LockArm(Rd_index); + code->CMP(32, reg_alloc.ArmR(Rd_index), Imm32(0)); + reg_alloc.UnlockArm(Rd_index); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::ORR_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->OR(32, R(Rd), Imm32(immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::RSB_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper_Reverse(Rn_index, Rd_index, [&](X64Reg Rd) { + code->MOV(32, R(Rd), Imm32(immediate)); + + if (Rn_index == 15) { + code->SUB(32, R(Rd), Imm32(GetReg15Value())); + } else { + reg_alloc.LockArm(Rn_index); + code->SUB(32, R(Rd), reg_alloc.ArmR(Rn_index)); + reg_alloc.UnlockArm(Rn_index); + } + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZVN(); + UpdateFlagsC_complement(); + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::RSC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper_Reverse(Rn_index, Rd_index, [&](X64Reg Rd) { + code->MOV(32, R(Rd), Imm32(immediate)); + + code->BT(32, MJitStateCFlag(), Imm8(0)); + code->CMC(); + + if (Rn_index == 15) { + code->SBB(32, R(Rd), Imm32(GetReg15Value())); + } else { + reg_alloc.LockArm(Rn_index); + code->SBB(32, R(Rd), reg_alloc.ArmR(Rn_index)); + reg_alloc.UnlockArm(Rn_index); + } + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZVN(); + UpdateFlagsC_complement(); + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::SBC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->BT(32, MJitStateCFlag(), Imm8(0)); + code->CMC(); + code->SBB(32, R(Rd), Imm32(immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZVN(); + UpdateFlagsC_complement(); + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::SUB_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + CompileDataProcessingHelper(Rn_index, Rd_index, [&](X64Reg Rd) { + code->SUB(32, R(Rd), Imm32(immediate)); + }); + + if (S) { + cond_manager.FlagsDirty(); + UpdateFlagsZVN(); + UpdateFlagsC_complement(); + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); + if (Rd_index == 15) { + CompileReturnToDispatch(); + } +} + +void JitX64::TEQ_imm(Cond cond, ArmReg Rn_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + X64Reg Rn = reg_alloc.AllocAndLockTemp(); + + if (Rn_index == 15) { + code->MOV(32, R(Rn), Imm32(GetReg15Value())); + } else { + reg_alloc.LockArm(Rn_index); + code->MOV(32, R(Rn), reg_alloc.ArmR(Rn_index)); + reg_alloc.UnlockArm(Rn_index); + } + + code->XOR(32, R(Rn), Imm32(immediate)); + + reg_alloc.UnlockTemp(Rn); + + cond_manager.FlagsDirty(); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + + reg_alloc.AssertNoLocked(); + current.arm_pc += GetInstSize(); } -void JitX64::ADC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::ADC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::ADD_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::ADD_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::ADD_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::AND_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::AND_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::AND_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::BIC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::BIC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::BIC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::CMN_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::CMN_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::CMN_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::CMP_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::CMP_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::CMP_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::EOR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::EOR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::EOR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::MOV_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::MOV_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::MOV_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::MVN_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::MVN_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::MVN_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::ORR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::ORR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::ORR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::RSB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::RSB_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::RSB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::RSC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::RSC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::RSC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::SBC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::SBC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::SBC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::SUB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::SUB_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::SUB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::TEQ_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::TEQ_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::TEQ_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::TST_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } -void JitX64::TST_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } -void JitX64::TST_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TST_imm(Cond cond, ArmReg Rn_index, int rotate, ArmImm8 imm8) { + cond_manager.CompileCond((ConditionCode)cond); + + u32 immediate = _rotr(imm8, rotate * 2); + + X64Reg Rn; + + if (Rn_index == 15) { + Rn = reg_alloc.AllocAndLockTemp(); + code->MOV(32, R(Rn), Imm32(GetReg15Value())); + } else { + Rn = reg_alloc.BindAndLockArm(Rn_index); + } + + code->TEST(32, R(Rn), Imm32(immediate)); + + if (Rn_index == 15) { + reg_alloc.UnlockTemp(Rn); + } else { + reg_alloc.UnlockArm(Rn_index); + } + + cond_manager.FlagsDirty(); + UpdateFlagsZN(); + if (rotate != 0) { + code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0)); + } + + reg_alloc.AssertNoLocked(); + + current.arm_pc += GetInstSize(); +} + +void JitX64::ADC_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ADC_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ADD_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ADD_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::AND_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::AND_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::BIC_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::BIC_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMN_reg(Cond cond, ArmReg Rn_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMN_rsr(Cond cond, ArmReg Rn_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMP_reg(Cond cond, ArmReg Rn_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMP_rsr(Cond cond, ArmReg Rn_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::EOR_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::EOR_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MOV_reg(Cond cond, bool S, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MOV_rsr(Cond cond, bool S, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MVN_reg(Cond cond, bool S, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MVN_rsr(Cond cond, bool S, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ORR_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ORR_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSB_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSB_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSC_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSC_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SBC_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SBC_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SUB_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SUB_rsr(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TEQ_reg(Cond cond, ArmReg Rn_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TEQ_rsr(Cond cond, ArmReg Rn_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TST_reg(Cond cond, ArmReg Rn_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TST_rsr(Cond cond, ArmReg Rn_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } } diff --git a/src/core/arm/jit_x64/interface.cpp b/src/core/arm/jit_x64/interface.cpp index df5d9b27e..bbdc6b481 100644 --- a/src/core/arm/jit_x64/interface.cpp +++ b/src/core/arm/jit_x64/interface.cpp @@ -74,7 +74,7 @@ public: struct BlockOfCode : Gen::XCodeBlock { BlockOfCode() { - AllocCodeSpace(1024 * 1024 * 1024); + AllocCodeSpace(128 * 1024 * 1024); } }; @@ -222,4 +222,10 @@ void ARM_Jit::ClearCache() { state->cpu_state.instruction_cache.clear(); } +void ARM_Jit::FastClearCache() { + compiler.ClearCache(); + block_of_code.ResetCodePtr(); + state->cpu_state.instruction_cache.clear(); +} + } diff --git a/src/core/arm/jit_x64/interface.h b/src/core/arm/jit_x64/interface.h index 228dc4ac5..62fb0c65f 100644 --- a/src/core/arm/jit_x64/interface.h +++ b/src/core/arm/jit_x64/interface.h @@ -41,6 +41,7 @@ public: void ExecuteInstructions(int num_instructions) override; void ClearCache() override; + void FastClearCache(); private: bool reschedule; diff --git a/src/core/arm/jit_x64/jit_x64.h b/src/core/arm/jit_x64/jit_x64.h index 475cb7c8c..ffd2832cd 100644 --- a/src/core/arm/jit_x64/jit_x64.h +++ b/src/core/arm/jit_x64/jit_x64.h @@ -106,6 +106,11 @@ private: code->SETcc(Gen::CC_S, MJitStateNFlag()); } + FORCE_INLINE void UpdateFlagsZN() { + code->SETcc(Gen::CC_Z, MJitStateZFlag()); + code->SETcc(Gen::CC_S, MJitStateNFlag()); + } + FORCE_INLINE void UpdateFlagsC_complement() { code->SETcc(Gen::CC_NC, MJitStateCFlag()); } @@ -151,6 +156,8 @@ private: virtual void STC() override; // Data processing instructions + void CompileDataProcessingHelper(ArmReg Rn_index, ArmReg Rd_index, std::function body); + void CompileDataProcessingHelper_Reverse(ArmReg Rn_index, ArmReg Rd_index, std::function body); virtual void ADC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; virtual void ADC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; virtual void ADC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; diff --git a/src/core/arm/jit_x64/reg_alloc.cpp b/src/core/arm/jit_x64/reg_alloc.cpp index 1e7600afc..e43fbe5cb 100644 --- a/src/core/arm/jit_x64/reg_alloc.cpp +++ b/src/core/arm/jit_x64/reg_alloc.cpp @@ -71,11 +71,16 @@ void RegAlloc::FlushX64(Gen::X64Reg x64_reg) { switch (state.state) { case X64State::State::Free: - case X64State::State::CleanArmReg: case X64State::State::MemoryMap: case X64State::State::Temp: state.state = X64State::State::Free; break; + case X64State::State::CleanArmReg: { + state.state = X64State::State::Free; + ArmState& arm_state = arm_gpr[state.arm_reg]; + arm_state.location = MJitStateCpuReg(state.arm_reg); + break; + } case X64State::State::DirtyArmReg: FlushArm(state.arm_reg); break; @@ -92,14 +97,18 @@ void RegAlloc::LockX64(Gen::X64Reg x64_reg) { X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)]; ASSERT(!x64_state.locked); + ASSERT(x64_state.state == X64State::State::Free); x64_state.locked = true; + x64_state.state = X64State::State::UserManuallyLocked; } void RegAlloc::UnlockX64(Gen::X64Reg x64_reg) { X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)]; ASSERT(x64_state.locked); + ASSERT(x64_state.state == X64State::State::UserManuallyLocked); x64_state.locked = false; + x64_state.state = X64State::State::Free; } void RegAlloc::FlushArm(ArmReg arm_reg) { @@ -300,6 +309,23 @@ void RegAlloc::UnlockMemoryMap(Gen::X64Reg x64_reg) { x64_state.locked = false; } +void RegAlloc::AssertNoLocked() { + for (ArmReg arm_reg = 0; arm_reg < arm_gpr.size(); arm_reg++) { + ArmState& arm_state = arm_gpr[arm_reg]; + ASSERT(!arm_state.locked); + if (arm_state.location.IsSimpleReg()) { + X64State& x64_state = x64_gpr[x64_reg_to_index.at(arm_state.location.GetSimpleReg())]; + ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg); + ASSERT(x64_state.arm_reg == arm_reg); + } + } + + for (auto i : x64_reg_to_index) { + X64State& x64_state = x64_gpr[i.second]; + ASSERT(!x64_state.locked); + } +} + Gen::X64Reg RegAlloc::AllocReg() { // TODO: This is terrible. diff --git a/src/core/arm/jit_x64/reg_alloc.h b/src/core/arm/jit_x64/reg_alloc.h index 37ffb9a85..9472ad88d 100644 --- a/src/core/arm/jit_x64/reg_alloc.h +++ b/src/core/arm/jit_x64/reg_alloc.h @@ -32,7 +32,8 @@ private: Temp, DirtyArmReg, CleanArmReg, - MemoryMap + MemoryMap, + UserManuallyLocked }; bool locked; @@ -92,6 +93,8 @@ public: /// Returns the register in which the JitState pointer is stored. Gen::X64Reg JitStateReg(); + void AssertNoLocked(); + private: /// INTERNAL: Allocates a register that is free. Flushes registers that are not locked if necessary. Gen::X64Reg AllocReg(); diff --git a/src/tests/core/arm/jit_x64/fuzz_arm_data_processing.cpp b/src/tests/core/arm/jit_x64/fuzz_arm_data_processing.cpp index 60f8f0f63..865a94e2f 100644 --- a/src/tests/core/arm/jit_x64/fuzz_arm_data_processing.cpp +++ b/src/tests/core/arm/jit_x64/fuzz_arm_data_processing.cpp @@ -39,6 +39,56 @@ std::pair FromBitString(const char* str) { } TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { + const std::array, 48> instructions = {{ + FromBitString("cccc0010101Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000101Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000101Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0010100Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000100Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000100Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0010000Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000000Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000000Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0011110Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0001110Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0001110Snnnnddddssss0rr1mmmm"), + FromBitString("cccc00110111nnnn0000rrrrvvvvvvvv"), + FromBitString("cccc00010111nnnn0000vvvvvrr0mmmm"), + FromBitString("cccc00010111nnnn0000ssss0rr1mmmm"), + FromBitString("cccc00110101nnnn0000rrrrvvvvvvvv"), + FromBitString("cccc00010101nnnn0000vvvvvrr0mmmm"), + FromBitString("cccc00010101nnnn0000ssss0rr1mmmm"), + FromBitString("cccc0010001Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000001Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000001Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0011101S0000ddddrrrrvvvvvvvv"), + FromBitString("cccc0001101S0000ddddvvvvvrr0mmmm"), + FromBitString("cccc0001101S0000ddddssss0rr1mmmm"), + FromBitString("cccc0011111S0000ddddrrrrvvvvvvvv"), + FromBitString("cccc0001111S0000ddddvvvvvrr0mmmm"), + FromBitString("cccc0001111S0000ddddssss0rr1mmmm"), + FromBitString("cccc0011100Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0001100Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0001100Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0010011Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000011Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000011Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0010111Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000111Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000111Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0010110Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000110Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000110Snnnnddddssss0rr1mmmm"), + FromBitString("cccc0010010Snnnnddddrrrrvvvvvvvv"), + FromBitString("cccc0000010Snnnnddddvvvvvrr0mmmm"), + FromBitString("cccc0000010Snnnnddddssss0rr1mmmm"), + FromBitString("cccc00110011nnnn0000rrrrvvvvvvvv"), + FromBitString("cccc00010011nnnn0000vvvvvrr0mmmm"), + FromBitString("cccc00010011nnnn0000ssss0rr1mmmm"), + FromBitString("cccc00110001nnnn0000rrrrvvvvvvvv"), + FromBitString("cccc00010001nnnn0000vvvvvrr0mmmm"), + FromBitString("cccc00010001nnnn0000ssss0rr1mmmm"), + }}; // Init core Core::Init(); @@ -62,12 +112,12 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { JitX64::ARM_Jit jit(PrivilegeMode::USER32MODE); ARM_DynCom interp(PrivilegeMode::USER32MODE); SCOPE_EXIT({ - jit.ClearCache(); + jit.FastClearCache(); interp.ClearCache(); }); for (int run_number = 0; run_number < 10000; run_number++) { - jit.ClearCache(); + jit.FastClearCache(); interp.ClearCache(); u32 initial_regs[15]; @@ -87,57 +137,6 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { constexpr int NUM_INST = 5; for (int i = 0; i < NUM_INST; i++) { - const std::array, 48> instructions = {{ - FromBitString("cccc0010101Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000101Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000101Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0010100Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000100Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000100Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0010000Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000000Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000000Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0011110Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0001110Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0001110Snnnnddddssss0rr1mmmm"), - FromBitString("cccc00110111nnnn0000rrrrvvvvvvvv"), - FromBitString("cccc00010111nnnn0000vvvvvrr0mmmm"), - FromBitString("cccc00010111nnnn0000ssss0rr1mmmm"), - FromBitString("cccc00110101nnnn0000rrrrvvvvvvvv"), - FromBitString("cccc00010101nnnn0000vvvvvrr0mmmm"), - FromBitString("cccc00010101nnnn0000ssss0rr1mmmm"), - FromBitString("cccc0010001Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000001Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000001Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0011101S0000ddddrrrrvvvvvvvv"), - FromBitString("cccc0001101S0000ddddvvvvvrr0mmmm"), - FromBitString("cccc0001101S0000ddddssss0rr1mmmm"), - FromBitString("cccc0011111S0000ddddrrrrvvvvvvvv"), - FromBitString("cccc0001111S0000ddddvvvvvrr0mmmm"), - FromBitString("cccc0001111S0000ddddssss0rr1mmmm"), - FromBitString("cccc0011100Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0001100Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0001100Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0010011Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000011Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000011Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0010111Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000111Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000111Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0010110Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000110Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000110Snnnnddddssss0rr1mmmm"), - FromBitString("cccc0010010Snnnnddddrrrrvvvvvvvv"), - FromBitString("cccc0000010Snnnnddddvvvvvrr0mmmm"), - FromBitString("cccc0000010Snnnnddddssss0rr1mmmm"), - FromBitString("cccc00110011nnnn0000rrrrvvvvvvvv"), - FromBitString("cccc00010011nnnn0000vvvvvrr0mmmm"), - FromBitString("cccc00010011nnnn0000ssss0rr1mmmm"), - FromBitString("cccc00110001nnnn0000rrrrvvvvvvvv"), - FromBitString("cccc00010001nnnn0000vvvvvrr0mmmm"), - FromBitString("cccc00010001nnnn0000ssss0rr1mmmm"), - }}; - size_t inst_index = rand_int(0, instructions.size() - 1); u32 cond = rand_int(0x0, 0xE); u32 Rn = rand_int(0, 15); @@ -197,5 +196,7 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { FAIL(); } + + if (run_number % 100 == 0) printf("%i\r", run_number); } } \ No newline at end of file