emission focused on branch/bctr
This commit is contained in:
parent
41bf1c1379
commit
45af725f62
|
|
@ -373,6 +373,7 @@ struct Context {
|
|||
void MFCTR(GPR const rt) { MFSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
||||
void MTCTR(GPR const rt) { MTSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
||||
void BCTRL() { base[offset++] = 0x4e800421; } //BCCTRL(R0, CR0, R0);
|
||||
void BCTR() { base[offset++] = 0x4e800420; } //BCCTR(R0, CR0, R0);
|
||||
|
||||
// TODO: PowerPC 11 stuff
|
||||
void ISEL(GPR const rd, GPR const ra, GPR const rb, uint32_t d) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ struct A32JitState {
|
|||
u32 cpsr_nzcv = 0;
|
||||
u32 fpscr = 0;
|
||||
u8 check_bit = 0;
|
||||
void* run_fn = nullptr;
|
||||
|
||||
IR::LocationDescriptor GetLocationDescriptor() const {
|
||||
return IR::LocationDescriptor{regs[15] | (u64(upper_location_descriptor) << 32)};
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ struct A32Core final {
|
|||
auto const loc = thread_ctx.GetLocationDescriptor();
|
||||
auto const entry = process.GetOrEmit(loc);
|
||||
using CodeFn = HaltReason (*)(A32AddressSpace*, A32JitState*, volatile u32*, void*);
|
||||
thread_ctx.run_fn = (void*)&A32Core::Run;
|
||||
return (CodeFn(entry))(&process, &thread_ctx, halt_reason, reinterpret_cast<void*>(&A32Core::Run));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ struct A64JitState {
|
|||
u32 fpsr = 0;
|
||||
volatile u32 halt_reason = 0;
|
||||
u8 check_bit = 0;
|
||||
void* run_fn = nullptr;
|
||||
|
||||
IR::LocationDescriptor GetLocationDescriptor() const {
|
||||
const u64 fpcr_u64 = u64(fpcr & A64::LocationDescriptor::fpcr_mask) << A64::LocationDescriptor::fpcr_shift;
|
||||
|
|
|
|||
|
|
@ -71,13 +71,18 @@ struct A64AddressSpace final {
|
|||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> block_infos;
|
||||
};
|
||||
|
||||
__attribute__((noinline)) HaltReason test_thunk(A64AddressSpace* a, A64JitState* b, volatile u32* c, void* d) {
|
||||
printf("%p,%p,%p,%p\n", a, b, c, d);
|
||||
return HaltReason::UserDefined2;
|
||||
}
|
||||
|
||||
struct A64Core final {
|
||||
static HaltReason Run(A64AddressSpace& process, A64JitState& thread_ctx, volatile u32* halt_reason) {
|
||||
const auto loc = thread_ctx.GetLocationDescriptor();
|
||||
const auto entry = process.GetOrEmit(loc);
|
||||
using CodeFn = HaltReason (*)(A64AddressSpace*, A64JitState*, volatile u32*, void*);
|
||||
thread_ctx.run_fn = (void*)&A64Core::Run;
|
||||
return (CodeFn(entry))(&process, &thread_ctx, halt_reason, reinterpret_cast<void*>(&A64Core::Run));
|
||||
using AbstractCodeFn = HaltReason (*)(A64AddressSpace*, A64JitState*, volatile u32*, void (*fn)());
|
||||
using CodeFn = HaltReason (*)(A64AddressSpace*, A64JitState*, volatile u32*, AbstractCodeFn fn);
|
||||
return (CodeFn(entry))(&process, &thread_ctx, halt_reason, AbstractCodeFn(test_thunk));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,10 @@ vrsave Non-volatile 32-bit register
|
|||
constexpr powah::GPR RPROCESS = powah::R3;
|
||||
constexpr powah::GPR RJIT = powah::R4;
|
||||
constexpr powah::GPR RHALTREASON = powah::R5;
|
||||
constexpr powah::GPR RNZCV = powah::R31;
|
||||
constexpr powah::GPR RTOCPTR = powah::R6;
|
||||
// temporals
|
||||
constexpr powah::GPR RNZCV = powah::R7;
|
||||
constexpr powah::GPR RCHECKBIT = powah::R8;
|
||||
|
||||
constexpr powah::GPR ABI_PARAM1 = powah::R3;
|
||||
constexpr powah::GPR ABI_PARAM2 = powah::R4;
|
||||
|
|
@ -55,7 +58,6 @@ constexpr powah::GPR ABI_PARAM4 = powah::R6;
|
|||
|
||||
// See https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#REG
|
||||
constexpr std::initializer_list<u32> GPR_ORDER{
|
||||
//6, 7, 8, 9, 10, 11, 12, //volatile
|
||||
// r13 is thread-id
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 //non-volatile
|
||||
};
|
||||
|
|
|
|||
|
|
@ -159,10 +159,11 @@ void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LinkBlock te
|
|||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
||||
code.LI(tmp, terminal.next.Value());
|
||||
code.STD(tmp, PPC64::RJIT, offsetof(A64JitState, pc));
|
||||
code.LD(tmp, PPC64::RJIT, offsetof(A64JitState, run_fn));
|
||||
code.LD(tmp, PPC64::RTOCPTR, 0);
|
||||
code.MTCTR(tmp);
|
||||
code.BCTRL();
|
||||
code.LD(powah::R2, powah::R1, offsetof(StackLayout, sp));
|
||||
code.LD(powah::R2, PPC64::RTOCPTR, 8);
|
||||
code.LD(powah::R11, PPC64::RTOCPTR, 16);
|
||||
code.BCTR();
|
||||
} else {
|
||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
||||
code.LI(tmp, terminal.next.Value());
|
||||
|
|
@ -191,7 +192,7 @@ void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::CheckBit ter
|
|||
powah::Label const l_else = code.DefineLabel();
|
||||
powah::Label const l_end = code.DefineLabel();
|
||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
||||
code.LD(tmp, powah::R1, offsetof(StackLayout, check_bit));
|
||||
code.MR(tmp, PPC64::RCHECKBIT);
|
||||
code.CMPLDI(tmp, 0);
|
||||
code.BEQ(powah::CR0, l_else);
|
||||
// CheckBit == 1
|
||||
|
|
@ -219,51 +220,53 @@ EmittedBlockInfo EmitPPC64(powah::Context& code, IR::Block block, const EmitConf
|
|||
RegAlloc reg_alloc{code};
|
||||
EmitContext ctx{block, reg_alloc, emit_conf, ebi};
|
||||
|
||||
size_t const stack_size = 112 + ABI_CALLEE_SAVED.size() * 8;
|
||||
auto const start_offset = code.offset;
|
||||
ebi.entry_point = &code.base[start_offset];
|
||||
if (!block.empty()) {
|
||||
code.MFLR(powah::R0);
|
||||
code.STD(powah::R0, powah::R1, 16);
|
||||
// Non-volatile saves
|
||||
std::vector<powah::GPR> gp_regs{ABI_CALLEE_SAVED};
|
||||
for (size_t i = 0; i < gp_regs.size(); ++i)
|
||||
code.STD(gp_regs[i], powah::R1, -int32_t(gp_regs.size() - i) * 8);
|
||||
code.STDU(powah::R1, powah::R1, uint32_t(-stack_size));
|
||||
code.STD(powah::R2, powah::R1, 40);
|
||||
|
||||
code.MFLR(powah::R0);
|
||||
code.STD(powah::R0, powah::R1, offsetof(StackLayout, lr));
|
||||
// Non-volatile saves
|
||||
std::vector<powah::GPR> abi_callee_saved{ABI_CALLEE_SAVED};
|
||||
for (size_t i = 0; i < abi_callee_saved.size(); ++i)
|
||||
code.STD(abi_callee_saved[i], powah::R1, -(8 + i * 8));
|
||||
code.STDU(powah::R1, powah::R1, -sizeof(StackLayout));
|
||||
code.STD(powah::R2, powah::R1, offsetof(StackLayout, sp));
|
||||
|
||||
for (auto iter = block.begin(); iter != block.end(); ++iter) {
|
||||
IR::Inst* inst = &*iter;
|
||||
switch (inst->GetOpcode()) {
|
||||
for (auto iter = block.begin(); iter != block.end(); ++iter) {
|
||||
IR::Inst* inst = &*iter;
|
||||
switch (inst->GetOpcode()) {
|
||||
#define OPCODE(name, type, ...) \
|
||||
case IR::Opcode::name: \
|
||||
EmitIR<IR::Opcode::name>(code, ctx, inst); \
|
||||
break;
|
||||
case IR::Opcode::name: \
|
||||
EmitIR<IR::Opcode::name>(code, ctx, inst); \
|
||||
break;
|
||||
#define A32OPC(name, type, ...) \
|
||||
case IR::Opcode::A32##name: \
|
||||
EmitIR<IR::Opcode::A32##name>(code, ctx, inst); \
|
||||
break;
|
||||
case IR::Opcode::A32##name: \
|
||||
EmitIR<IR::Opcode::A32##name>(code, ctx, inst); \
|
||||
break;
|
||||
#define A64OPC(name, type, ...) \
|
||||
case IR::Opcode::A64##name: \
|
||||
EmitIR<IR::Opcode::A64##name>(code, ctx, inst); \
|
||||
break;
|
||||
case IR::Opcode::A64##name: \
|
||||
EmitIR<IR::Opcode::A64##name>(code, ctx, inst); \
|
||||
break;
|
||||
#include "dynarmic/ir/opcodes.inc"
|
||||
#undef OPCODE
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
default:
|
||||
UNREACHABLE();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// auto const cycles_to_add = block.CycleCount();
|
||||
code.ADDI(powah::R1, powah::R1, stack_size);
|
||||
for (size_t i = 0; i < gp_regs.size(); ++i)
|
||||
code.LD(gp_regs[i], powah::R1, -int32_t(gp_regs.size() - i) * 8);
|
||||
code.LD(powah::R0, powah::R1, 16);
|
||||
code.MTLR(powah::R0);
|
||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
||||
} else {
|
||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
||||
}
|
||||
|
||||
// auto const cycles_to_add = block.CycleCount();
|
||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
||||
|
||||
code.ADDI(powah::R1, powah::R1, sizeof(StackLayout));
|
||||
code.LD(powah::R0, powah::R1, offsetof(StackLayout, lr));
|
||||
code.MTLR(powah::R0);
|
||||
for (size_t i = 0; i < abi_callee_saved.size(); ++i)
|
||||
code.LD(abi_callee_saved[i], powah::R1, -(8 + i * 8));
|
||||
code.BLR();
|
||||
code.ApplyRelocs();
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dynarmic::Backend::PPC64 {
|
|||
template<>
|
||||
void EmitIR<IR::Opcode::A64SetCheckBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
||||
code.STD(value, powah::R1, offsetof(StackLayout, check_bit));
|
||||
code.MR(PPC64::RCHECKBIT, value);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -49,15 +49,15 @@ struct RegAlloc;
|
|||
/// this basically means that we can use temporals and not need to go thru
|
||||
/// any weird deallocation stuffs :)
|
||||
template<typename T> struct RegLock {
|
||||
inline RegLock(RegAlloc& reg_alloc, T const value) noexcept
|
||||
constexpr RegLock(RegAlloc& reg_alloc, T const value) noexcept
|
||||
: reg_alloc{reg_alloc}
|
||||
, value{value}
|
||||
{
|
||||
SetLock(true);
|
||||
}
|
||||
inline ~RegLock() noexcept { SetLock(false); }
|
||||
operator T const&() { return value; }
|
||||
operator T() const { return value; }
|
||||
constexpr operator T const&() noexcept { return value; }
|
||||
constexpr operator T() const noexcept { return value; }
|
||||
inline void SetLock(bool v) noexcept;
|
||||
RegAlloc& reg_alloc;
|
||||
const T value;
|
||||
|
|
@ -94,7 +94,6 @@ private:
|
|||
std::array<HostLocInfo, 32> fprs;
|
||||
std::array<HostLocInfo, 32> vprs;
|
||||
std::array<HostLocInfo, SpillCount> spills;
|
||||
uint32_t lru_counter = 0;
|
||||
};
|
||||
|
||||
template<> inline void RegLock<powah::GPR>::SetLock(bool v) noexcept {
|
||||
|
|
|
|||
|
|
@ -12,12 +12,7 @@ namespace Dynarmic::Backend::PPC64 {
|
|||
constexpr size_t SpillCount = 16;
|
||||
|
||||
struct alignas(16) StackLayout {
|
||||
u64 resv0; //0
|
||||
u64 resv1; //8
|
||||
u64 lr; //16
|
||||
u64 sp; //24
|
||||
std::array<u64, SpillCount> spill;
|
||||
u64 check_bit;
|
||||
};
|
||||
|
||||
static_assert(sizeof(StackLayout) % 16 == 0);
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@
|
|||
|
||||
namespace Dynarmic::IR {
|
||||
|
||||
Block::Block(const LocationDescriptor& location)
|
||||
: location{location},
|
||||
end_location{location},
|
||||
cond{Cond::AL}
|
||||
Block::Block(const LocationDescriptor& location) noexcept :
|
||||
location{location}
|
||||
, end_location{location}
|
||||
, cond{Cond::AL}
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ public:
|
|||
using reverse_iterator = instruction_list_type::reverse_iterator;
|
||||
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
||||
|
||||
explicit Block(const LocationDescriptor& location);
|
||||
~Block() = default;
|
||||
explicit Block(const LocationDescriptor& location) noexcept;
|
||||
~Block() noexcept = default;
|
||||
Block(const Block&) = delete;
|
||||
Block& operator=(const Block&) = delete;
|
||||
Block(Block&&) = default;
|
||||
|
|
|
|||
Loading…
Reference in New Issue