JitX64: Implement immediate data processing instructions

This commit is contained in:
MerryMage 2016-03-20 22:05:57 +00:00
parent a80f9d8a66
commit 52558ae8be
8 changed files with 565 additions and 122 deletions

View File

@ -24,6 +24,7 @@ void JitX64::CondManager::CompileCond(const ConditionCode new_cond) {
if (current_cond != ConditionCode::AL && current_cond != ConditionCode::NV) { if (current_cond != ConditionCode::AL && current_cond != ConditionCode::NV) {
jit->reg_alloc.FlushEverything(); jit->reg_alloc.FlushEverything();
jit->reg_alloc.AssertNoLocked();
ASSERT(current_cond_fixup.ptr); ASSERT(current_cond_fixup.ptr);
jit->code->SetJumpTarget(current_cond_fixup); jit->code->SetJumpTarget(current_cond_fixup);
current_cond_fixup.ptr = nullptr; current_cond_fixup.ptr = nullptr;
@ -123,6 +124,7 @@ void JitX64::CondManager::CompileCond(const ConditionCode new_cond) {
} }
jit->reg_alloc.FlushEverything(); jit->reg_alloc.FlushEverything();
jit->reg_alloc.AssertNoLocked();
this->current_cond_fixup = jit->code->J_CC(cc, true); this->current_cond_fixup = jit->code->J_CC(cc, true);
} }

View File

@ -10,48 +10,41 @@ namespace JitX64 {
using namespace Gen; using namespace Gen;
void JitX64::ADC_imm(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, int rotate, ArmImm8 imm8) { void JitX64::CompileDataProcessingHelper(ArmReg Rn_index, ArmReg Rd_index, std::function<void(X64Reg)> body) {
cond_manager.CompileCond((ConditionCode)cond); // The major consideration is if Rn and/or Rd == R15.
u32 immediate = _rotr(imm8, rotate * 2);
if (Rd_index == 15) { if (Rd_index == 15) {
X64Reg Rd = reg_alloc.AllocAndLockTemp(); X64Reg Rd = reg_alloc.AllocAndLockTemp();
reg_alloc.LockArm(Rn_index); reg_alloc.LockArm(Rn_index);
if (Rn_index == 15) { 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())); code->MOV(32, R(Rd), Imm32(GetReg15Value()));
} else { } 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); reg_alloc.UnlockArm(Rn_index);
if (S)
UNIMPLEMENTED();
code->MOV(32, MJitStateArmPC(), R(Rd)); code->MOV(32, MJitStateArmPC(), R(Rd));
reg_alloc.UnlockTemp(Rd); reg_alloc.UnlockTemp(Rd);
current.arm_pc += GetInstSize();
CompileReturnToDispatch();
return;
} else if (Rn_index == 15) { } else if (Rn_index == 15) {
X64Reg Rd = reg_alloc.BindNoLoadAndLockArm(Rd_index); X64Reg Rd = reg_alloc.BindNoLoadAndLockArm(Rd_index);
reg_alloc.MarkDirty(Rd_index); reg_alloc.MarkDirty(Rd_index);
code->MOV(32, R(Rd), Imm32(GetReg15Value())); 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); reg_alloc.UnlockArm(Rd_index);
} else if (Rn_index == Rd_index) { } else if (Rn_index == Rd_index) {
X64Reg Rd = reg_alloc.BindAndLockArm(Rd_index); X64Reg Rd = reg_alloc.BindAndLockArm(Rd_index);
reg_alloc.MarkDirty(Rd_index); reg_alloc.MarkDirty(Rd_index);
code->BT(32, MJitStateCFlag(), Imm8(0)); body(Rd);
code->ADC(32, R(Rd), Imm32(immediate));
reg_alloc.UnlockArm(Rd_index); reg_alloc.UnlockArm(Rd_index);
} else { } 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); reg_alloc.LockArm(Rn_index);
code->MOV(32, R(Rd), reg_alloc.ArmR(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(Rd_index);
reg_alloc.UnlockArm(Rn_index); reg_alloc.UnlockArm(Rn_index);
} }
}
void JitX64::CompileDataProcessingHelper_Reverse(ArmReg Rn_index, ArmReg Rd_index, std::function<void(X64Reg)> 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) { if (S) {
cond_manager.FlagsDirty(); cond_manager.FlagsDirty();
UpdateFlagsZVCN(); 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(); 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::TST_imm(Cond cond, ArmReg Rn_index, int rotate, ArmImm8 imm8) {
void JitX64::ADC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } cond_manager.CompileCond((ConditionCode)cond);
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(); } u32 immediate = _rotr(imm8, rotate * 2);
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(); } X64Reg Rn;
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(); } if (Rn_index == 15) {
void JitX64::BIC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } Rn = reg_alloc.AllocAndLockTemp();
void JitX64::BIC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } code->MOV(32, R(Rn), Imm32(GetReg15Value()));
void JitX64::BIC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } } else {
void JitX64::CMN_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } Rn = reg_alloc.BindAndLockArm(Rn_index);
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(); } code->TEST(32, R(Rn), Imm32(immediate));
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(); } if (Rn_index == 15) {
void JitX64::EOR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } reg_alloc.UnlockTemp(Rn);
void JitX64::EOR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } } else {
void JitX64::EOR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } reg_alloc.UnlockArm(Rn_index);
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(); } cond_manager.FlagsDirty();
void JitX64::MVN_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } UpdateFlagsZN();
void JitX64::MVN_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } if (rotate != 0) {
void JitX64::MVN_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } code->MOV(32, MJitStateCFlag(), Imm32(immediate & 0x80000000 ? 1 : 0));
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(); } reg_alloc.AssertNoLocked();
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(); } current.arm_pc += GetInstSize();
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::ADC_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, ArmReg Rd, ArmReg Rs, 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::SBC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } void JitX64::ADD_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); }
void JitX64::SBC_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_index, ArmReg Rd_index, ArmReg Rs, 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::AND_reg(Cond cond, bool S, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); }
void JitX64::SUB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } void JitX64::AND_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, ArmReg Rd, ArmImm5 imm5, 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::SUB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, 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::TEQ_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } void JitX64::CMN_reg(Cond cond, ArmReg Rn_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); }
void JitX64::TEQ_reg(Cond cond, ArmReg Rn, 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::TEQ_rsr(Cond cond, ArmReg Rn, 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::TST_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } void JitX64::CMP_rsr(Cond cond, ArmReg Rn_index, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); }
void JitX64::TST_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, 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::TST_rsr(Cond cond, ArmReg Rn, ArmReg Rs, 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(); }
} }

View File

@ -74,7 +74,7 @@ public:
struct BlockOfCode : Gen::XCodeBlock { struct BlockOfCode : Gen::XCodeBlock {
BlockOfCode() { BlockOfCode() {
AllocCodeSpace(1024 * 1024 * 1024); AllocCodeSpace(128 * 1024 * 1024);
} }
}; };
@ -222,4 +222,10 @@ void ARM_Jit::ClearCache() {
state->cpu_state.instruction_cache.clear(); state->cpu_state.instruction_cache.clear();
} }
void ARM_Jit::FastClearCache() {
compiler.ClearCache();
block_of_code.ResetCodePtr();
state->cpu_state.instruction_cache.clear();
}
} }

View File

@ -41,6 +41,7 @@ public:
void ExecuteInstructions(int num_instructions) override; void ExecuteInstructions(int num_instructions) override;
void ClearCache() override; void ClearCache() override;
void FastClearCache();
private: private:
bool reschedule; bool reschedule;

View File

@ -106,6 +106,11 @@ private:
code->SETcc(Gen::CC_S, MJitStateNFlag()); 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() { FORCE_INLINE void UpdateFlagsC_complement() {
code->SETcc(Gen::CC_NC, MJitStateCFlag()); code->SETcc(Gen::CC_NC, MJitStateCFlag());
} }
@ -151,6 +156,8 @@ private:
virtual void STC() override; virtual void STC() override;
// Data processing instructions // Data processing instructions
void CompileDataProcessingHelper(ArmReg Rn_index, ArmReg Rd_index, std::function<void(Gen::X64Reg)> body);
void CompileDataProcessingHelper_Reverse(ArmReg Rn_index, ArmReg Rd_index, std::function<void(Gen::X64Reg)> body);
virtual void ADC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; 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_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; virtual void ADC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override;

View File

@ -71,11 +71,16 @@ void RegAlloc::FlushX64(Gen::X64Reg x64_reg) {
switch (state.state) { switch (state.state) {
case X64State::State::Free: case X64State::State::Free:
case X64State::State::CleanArmReg:
case X64State::State::MemoryMap: case X64State::State::MemoryMap:
case X64State::State::Temp: case X64State::State::Temp:
state.state = X64State::State::Free; state.state = X64State::State::Free;
break; 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: case X64State::State::DirtyArmReg:
FlushArm(state.arm_reg); FlushArm(state.arm_reg);
break; break;
@ -92,14 +97,18 @@ void RegAlloc::LockX64(Gen::X64Reg x64_reg) {
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)]; X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
ASSERT(!x64_state.locked); ASSERT(!x64_state.locked);
ASSERT(x64_state.state == X64State::State::Free);
x64_state.locked = true; x64_state.locked = true;
x64_state.state = X64State::State::UserManuallyLocked;
} }
void RegAlloc::UnlockX64(Gen::X64Reg x64_reg) { void RegAlloc::UnlockX64(Gen::X64Reg x64_reg) {
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)]; X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
ASSERT(x64_state.locked); ASSERT(x64_state.locked);
ASSERT(x64_state.state == X64State::State::UserManuallyLocked);
x64_state.locked = false; x64_state.locked = false;
x64_state.state = X64State::State::Free;
} }
void RegAlloc::FlushArm(ArmReg arm_reg) { void RegAlloc::FlushArm(ArmReg arm_reg) {
@ -300,6 +309,23 @@ void RegAlloc::UnlockMemoryMap(Gen::X64Reg x64_reg) {
x64_state.locked = false; 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() { Gen::X64Reg RegAlloc::AllocReg() {
// TODO: This is terrible. // TODO: This is terrible.

View File

@ -32,7 +32,8 @@ private:
Temp, Temp,
DirtyArmReg, DirtyArmReg,
CleanArmReg, CleanArmReg,
MemoryMap MemoryMap,
UserManuallyLocked
}; };
bool locked; bool locked;
@ -92,6 +93,8 @@ public:
/// Returns the register in which the JitState pointer is stored. /// Returns the register in which the JitState pointer is stored.
Gen::X64Reg JitStateReg(); Gen::X64Reg JitStateReg();
void AssertNoLocked();
private: private:
/// INTERNAL: Allocates a register that is free. Flushes registers that are not locked if necessary. /// INTERNAL: Allocates a register that is free. Flushes registers that are not locked if necessary.
Gen::X64Reg AllocReg(); Gen::X64Reg AllocReg();

View File

@ -39,54 +39,6 @@ std::pair<u32, u32> FromBitString(const char* str) {
} }
TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
// Init core
Core::Init();
SCOPE_EXIT({ Core::Shutdown(); });
// Prepare random numbers
std::random_device rd;
std::mt19937 mt(rd());
auto rand_int = [&mt](u32 min, u32 max) -> u32 {
std::uniform_int<u32> rand(min, max);
return rand(mt);
};
// Prepare memory
u8* test_mem = new u8[4096 * 2];
std::memset(test_mem, 0, 4096 * 2);
Memory::MapMemoryRegion(0, 4096 * 2, test_mem);
SCOPE_EXIT({ Memory::UnmapRegion(0, 4096 * 2); });
// Prepare test subjects
JitX64::ARM_Jit jit(PrivilegeMode::USER32MODE);
ARM_DynCom interp(PrivilegeMode::USER32MODE);
SCOPE_EXIT({
jit.ClearCache();
interp.ClearCache();
});
for (int run_number = 0; run_number < 10000; run_number++) {
jit.ClearCache();
interp.ClearCache();
u32 initial_regs[15];
for (int i = 0; i < 15; i++) {
u32 val = rand_int(0, 0xFFFFFFFF);
interp.SetReg(i, val);
jit.SetReg(i, val);
initial_regs[i] = val;
}
interp.SetCPSR(0x000001d0);
jit.SetCPSR(0x000001d0);
interp.SetPC(0);
jit.SetPC(0);
constexpr int NUM_INST = 5;
for (int i = 0; i < NUM_INST; i++) {
const std::array<std::pair<u32, u32>, 48> instructions = {{ const std::array<std::pair<u32, u32>, 48> instructions = {{
FromBitString("cccc0010101Snnnnddddrrrrvvvvvvvv"), FromBitString("cccc0010101Snnnnddddrrrrvvvvvvvv"),
FromBitString("cccc0000101Snnnnddddvvvvvrr0mmmm"), FromBitString("cccc0000101Snnnnddddvvvvvrr0mmmm"),
@ -138,6 +90,53 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
FromBitString("cccc00010001nnnn0000ssss0rr1mmmm"), FromBitString("cccc00010001nnnn0000ssss0rr1mmmm"),
}}; }};
// Init core
Core::Init();
SCOPE_EXIT({ Core::Shutdown(); });
// Prepare random numbers
std::random_device rd;
std::mt19937 mt(rd());
auto rand_int = [&mt](u32 min, u32 max) -> u32 {
std::uniform_int<u32> rand(min, max);
return rand(mt);
};
// Prepare memory
u8* test_mem = new u8[4096 * 2];
std::memset(test_mem, 0, 4096 * 2);
Memory::MapMemoryRegion(0, 4096 * 2, test_mem);
SCOPE_EXIT({ Memory::UnmapRegion(0, 4096 * 2); });
// Prepare test subjects
JitX64::ARM_Jit jit(PrivilegeMode::USER32MODE);
ARM_DynCom interp(PrivilegeMode::USER32MODE);
SCOPE_EXIT({
jit.FastClearCache();
interp.ClearCache();
});
for (int run_number = 0; run_number < 10000; run_number++) {
jit.FastClearCache();
interp.ClearCache();
u32 initial_regs[15];
for (int i = 0; i < 15; i++) {
u32 val = rand_int(0, 0xFFFFFFFF);
interp.SetReg(i, val);
jit.SetReg(i, val);
initial_regs[i] = val;
}
interp.SetCPSR(0x000001d0);
jit.SetCPSR(0x000001d0);
interp.SetPC(0);
jit.SetPC(0);
constexpr int NUM_INST = 5;
for (int i = 0; i < NUM_INST; i++) {
size_t inst_index = rand_int(0, instructions.size() - 1); size_t inst_index = rand_int(0, instructions.size() - 1);
u32 cond = rand_int(0x0, 0xE); u32 cond = rand_int(0x0, 0xE);
u32 Rn = rand_int(0, 15); u32 Rn = rand_int(0, 15);
@ -197,5 +196,7 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
FAIL(); FAIL();
} }
if (run_number % 100 == 0) printf("%i\r", run_number);
} }
} }