frontend: Standardize emitted IR for exception raising

This commit is contained in:
MerryMage 2021-05-04 15:53:32 +01:00
parent 3b2c6afdc2
commit c5f5c1d40f
7 changed files with 42 additions and 33 deletions

View file

@ -791,9 +791,11 @@ void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
code.sub(code.ABI_PARAM2, qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
Devirtualize<&A32::UserCallbacks::AddTicks>(conf.callbacks).EmitCall(code);
ctx.reg_alloc.EndOfAllocScope();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
Devirtualize<&A32::UserCallbacks::CallSVC>(conf.callbacks).EmitCall(code);
Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(conf.callbacks).EmitCall(code);
code.mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], code.ABI_RETURN);
code.mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], code.ABI_RETURN);
@ -802,6 +804,13 @@ void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
void A32EmitX64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(nullptr);
code.SwitchMxcsrOnExit();
code.mov(code.ABI_PARAM2, qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)]);
code.sub(code.ABI_PARAM2, qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
Devirtualize<&A32::UserCallbacks::AddTicks>(conf.callbacks).EmitCall(code);
ctx.reg_alloc.EndOfAllocScope();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(args[0].IsImmediate() && args[1].IsImmediate());
const u32 pc = args[0].GetImmediateU32();
@ -810,6 +819,11 @@ void A32EmitX64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
code.mov(param[0], pc);
code.mov(param[1], exception);
});
Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(conf.callbacks).EmitCall(code);
code.mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], code.ABI_RETURN);
code.mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], code.ABI_RETURN);
code.SwitchMxcsrOnEntry();
}
static u32 GetFpscrImpl(A32JitState* jit_state) {

View file

@ -11,6 +11,7 @@
#include "common/common_types.h"
#include "frontend/A32/ir_emitter.h"
#include "frontend/A32/translate/conditional_state.h"
#include "frontend/A32/translate/impl/translate.h"
#include "ir/cond.h"
namespace Dynarmic::A32 {
@ -25,29 +26,29 @@ bool CondCanContinue(ConditionalState cond_state, const A32::IREmitter& ir) {
return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); });
}
bool IsConditionPassed(IR::Cond cond, ConditionalState& cond_state, A32::IREmitter& ir, int instruction_size) {
ASSERT_MSG(cond_state != ConditionalState::Break,
bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) {
ASSERT_MSG(v.cond_state != ConditionalState::Break,
"This should never happen. We requested a break but that wasn't honored.");
if (cond == IR::Cond::NV) {
// NV conditional is obsolete
ir.ExceptionRaised(Exception::UnpredictableInstruction);
v.RaiseException(Exception::UnpredictableInstruction);
return false;
}
if (cond_state == ConditionalState::Translating) {
if (ir.block.ConditionFailedLocation() != ir.current_location || cond == IR::Cond::AL) {
cond_state = ConditionalState::Trailing;
if (v.cond_state == ConditionalState::Translating) {
if (v.ir.block.ConditionFailedLocation() != v.ir.current_location || cond == IR::Cond::AL) {
v.cond_state = ConditionalState::Trailing;
} else {
if (cond == ir.block.GetCondition()) {
ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(instruction_size).AdvanceIT());
ir.block.ConditionFailedCycleCount()++;
if (cond == v.ir.block.GetCondition()) {
v.ir.block.SetConditionFailedLocation(v.ir.current_location.AdvancePC(v.current_instruction_size).AdvanceIT());
v.ir.block.ConditionFailedCycleCount()++;
return true;
}
// cond has changed, abort
cond_state = ConditionalState::Break;
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location});
v.cond_state = ConditionalState::Break;
v.ir.SetTerm(IR::Term::LinkBlockFast{v.ir.current_location});
return false;
}
}
@ -59,20 +60,20 @@ bool IsConditionPassed(IR::Cond cond, ConditionalState& cond_state, A32::IREmitt
// non-AL cond
if (!ir.block.empty()) {
if (!v.ir.block.empty()) {
// We've already emitted instructions. Quit for now, we'll make a new block here later.
cond_state = ConditionalState::Break;
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location});
v.cond_state = ConditionalState::Break;
v.ir.SetTerm(IR::Term::LinkBlockFast{v.ir.current_location});
return false;
}
// We've not emitted instructions yet.
// We'll emit one instruction, and set the block-entry conditional appropriately.
cond_state = ConditionalState::Translating;
ir.block.SetCondition(cond);
ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(instruction_size).AdvanceIT());
ir.block.ConditionFailedCycleCount() = ir.block.CycleCount() + 1;
v.cond_state = ConditionalState::Translating;
v.ir.block.SetCondition(cond);
v.ir.block.SetConditionFailedLocation(v.ir.current_location.AdvancePC(v.current_instruction_size).AdvanceIT());
v.ir.block.ConditionFailedCycleCount() = v.ir.block.CycleCount() + 1;
return true;
}

View file

@ -14,6 +14,7 @@ enum class Cond;
namespace Dynarmic::A32 {
class IREmitter;
struct TranslatorVisitor;
enum class ConditionalState {
/// We haven't met any conditional instructions yet.
@ -27,6 +28,6 @@ enum class ConditionalState {
};
bool CondCanContinue(ConditionalState cond_state, const A32::IREmitter& ir);
bool IsConditionPassed(IR::Cond cond, ConditionalState& cond_state, A32::IREmitter& ir, int instruction_size);
bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond);
} // namespace Dynarmic::A32

View file

@ -20,9 +20,7 @@ bool TranslatorVisitor::arm_BKPT(Cond cond, Imm<12> /*imm12*/, Imm<4> /*imm4*/)
return true;
}
ir.ExceptionRaised(Exception::Breakpoint);
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
return false;
return RaiseException(Exception::Breakpoint);
}
// SVC<c> #<imm24>

View file

@ -903,11 +903,7 @@ bool TranslatorVisitor::thumb16_REVSH(Reg m, Reg d) {
// BKPT #<imm8>
bool TranslatorVisitor::thumb16_BKPT(Imm<8> /*imm8*/) {
ir.ExceptionRaised(Exception::Breakpoint);
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(ir.Imm32(ir.current_location.PC()));
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
return false;
return RaiseException(Exception::Breakpoint);
}
// STM <Rn>!, <reg_list>

View file

@ -12,12 +12,12 @@
namespace Dynarmic::A32 {
bool TranslatorVisitor::ArmConditionPassed(Cond cond) {
return IsConditionPassed(cond, cond_state, ir, 4);
return IsConditionPassed(*this, cond);
}
bool TranslatorVisitor::ThumbConditionPassed() {
const Cond cond = ir.current_location.IT().Cond();
return IsConditionPassed(cond, cond_state, ir, static_cast<int>(current_instruction_size));
return IsConditionPassed(*this, cond);
}
bool TranslatorVisitor::VFPConditionPassed(Cond cond) {
@ -46,6 +46,7 @@ bool TranslatorVisitor::DecodeError() {
}
bool TranslatorVisitor::RaiseException(Exception exception) {
ir.UpdateUpperLocationDescriptor();
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + static_cast<u32>(current_instruction_size)));
ir.ExceptionRaised(exception);
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});

View file

@ -7,10 +7,8 @@
namespace Dynarmic::A64 {
bool TranslatorVisitor::BRK([[maybe_unused]] Imm<16> imm16) {
ir.ExceptionRaised(Exception::Breakpoint);
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
return false;
bool TranslatorVisitor::BRK(Imm<16> /*imm16*/) {
return RaiseException(Exception::Breakpoint);
}
bool TranslatorVisitor::SVC(Imm<16> imm16) {