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)]); code.sub(code.ABI_PARAM2, qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
Devirtualize<&A32::UserCallbacks::AddTicks>(conf.callbacks).EmitCall(code); Devirtualize<&A32::UserCallbacks::AddTicks>(conf.callbacks).EmitCall(code);
ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.EndOfAllocScope();
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0]); ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
Devirtualize<&A32::UserCallbacks::CallSVC>(conf.callbacks).EmitCall(code); Devirtualize<&A32::UserCallbacks::CallSVC>(conf.callbacks).EmitCall(code);
Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(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_to_run)], code.ABI_RETURN);
code.mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 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) { void A32EmitX64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(nullptr); 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); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(args[0].IsImmediate() && args[1].IsImmediate()); ASSERT(args[0].IsImmediate() && args[1].IsImmediate());
const u32 pc = args[0].GetImmediateU32(); 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[0], pc);
code.mov(param[1], exception); 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) { static u32 GetFpscrImpl(A32JitState* jit_state) {

View file

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

View file

@ -14,6 +14,7 @@ enum class Cond;
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
class IREmitter; class IREmitter;
struct TranslatorVisitor;
enum class ConditionalState { enum class ConditionalState {
/// We haven't met any conditional instructions yet. /// 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 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 } // namespace Dynarmic::A32

View file

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

View file

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

View file

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

View file

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