mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 09:40:15 +00:00
JitX64: Implement register allocator
This commit is contained in:
parent
a8dec47797
commit
e34c66d62b
@ -264,6 +264,18 @@ set(HEADERS
|
|||||||
system.h
|
system.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(ARCHITECTURE_x86_64)
|
||||||
|
set(SRCS ${SRCS}
|
||||||
|
arm/jit_x64/reg_alloc.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
arm/jit_x64/common.h
|
||||||
|
arm/jit_x64/reg_alloc.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
create_directory_groups(${SRCS} ${HEADERS})
|
create_directory_groups(${SRCS} ${HEADERS})
|
||||||
|
|
||||||
add_library(core STATIC ${SRCS} ${HEADERS})
|
add_library(core STATIC ${SRCS} ${HEADERS})
|
||||||
|
39
src/core/arm/jit_x64/common.h
Normal file
39
src/core/arm/jit_x64/common.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
#include "core/arm/decoder/decoder.h"
|
||||||
|
#include "core/arm/skyeye_common/armstate.h"
|
||||||
|
|
||||||
|
namespace JitX64 {
|
||||||
|
|
||||||
|
using ArmReg = ArmDecoder::Register;
|
||||||
|
using ArmImm5 = ArmDecoder::Imm5;
|
||||||
|
using ArmImm8 = ArmDecoder::Imm8;
|
||||||
|
using ArmImm11 = ArmDecoder::Imm11;
|
||||||
|
using ArmImm24 = ArmDecoder::Imm24;
|
||||||
|
using Cond = ArmDecoder::Cond;
|
||||||
|
using ShiftType = ArmDecoder::ShiftType;
|
||||||
|
|
||||||
|
struct JitState {
|
||||||
|
JitState() : cpu_state(PrivilegeMode::USER32MODE) {}
|
||||||
|
void Reset() {
|
||||||
|
cpu_state.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
ARMul_State cpu_state;
|
||||||
|
|
||||||
|
void* bb;
|
||||||
|
|
||||||
|
u64 save_host_RSP;
|
||||||
|
u64 return_RIP;
|
||||||
|
|
||||||
|
void* page_table;
|
||||||
|
s32 cycles_remaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
335
src/core/arm/jit_x64/reg_alloc.cpp
Normal file
335
src/core/arm/jit_x64/reg_alloc.cpp
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
|
||||||
|
#include "core/arm/jit_x64/reg_alloc.h"
|
||||||
|
|
||||||
|
namespace JitX64 {
|
||||||
|
|
||||||
|
static const std::map<Gen::X64Reg, size_t> x64_reg_to_index = {
|
||||||
|
{ Gen::RAX, 0 },
|
||||||
|
{ Gen::RBX, 1 },
|
||||||
|
{ Gen::RCX, 2 },
|
||||||
|
{ Gen::RDX, 3 },
|
||||||
|
{ Gen::RBP, 4 },
|
||||||
|
{ Gen::RSI, 5 },
|
||||||
|
{ Gen::RDI, 6 },
|
||||||
|
{ Gen::RSP, 7 },
|
||||||
|
{ Gen::R8, 8 },
|
||||||
|
{ Gen::R9, 9 },
|
||||||
|
{ Gen::R10, 10 },
|
||||||
|
{ Gen::R11, 11 },
|
||||||
|
{ Gen::R12, 12 },
|
||||||
|
{ Gen::R13, 13 },
|
||||||
|
{ Gen::R14, 14 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Gen::X64Reg jit_state_reg = Gen::R15;
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::JitStateReg() {
|
||||||
|
return jit_state_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Gen::OpArg MJitStateCpuReg(ArmReg arm_reg) {
|
||||||
|
// The below pointer arithmetic assumes the following:
|
||||||
|
static_assert(std::is_same<decltype(JitState::cpu_state), ARMul_State>::value, "JitState::cpu_state must be ARMul_State");
|
||||||
|
static_assert(std::is_same<decltype(ARMul_State::Reg), std::array<u32, 16>>::value, "ARMul_State::Reg must be std::array<u32, 16>");
|
||||||
|
|
||||||
|
ASSERT(arm_reg >= 0 && arm_reg <= 14);
|
||||||
|
|
||||||
|
return Gen::MDisp(jit_state_reg, offsetof(JitState, cpu_state) + offsetof(ARMul_State, Reg) + (arm_reg) * sizeof(u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Gen::OpArg MJitStateMemoryMap() {
|
||||||
|
return Gen::MDisp(jit_state_reg, offsetof(JitState, page_table));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::Init(Gen::XEmitter* emitter) {
|
||||||
|
code = emitter;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arm_gpr.size(); i++) {
|
||||||
|
arm_gpr[i].locked = false;
|
||||||
|
arm_gpr[i].location = MJitStateCpuReg(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < x64_gpr.size(); i++) {
|
||||||
|
x64_gpr[i].locked = false;
|
||||||
|
x64_gpr[i].state = X64State::State::Free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::FlushX64(Gen::X64Reg x64_reg) {
|
||||||
|
const size_t x64_index = x64_reg_to_index.at(x64_reg);
|
||||||
|
X64State& state = x64_gpr[x64_index];
|
||||||
|
|
||||||
|
ASSERT(!state.locked);
|
||||||
|
|
||||||
|
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::DirtyArmReg:
|
||||||
|
FlushArm(state.arm_reg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(state.state == X64State::State::Free);
|
||||||
|
ASSERT(!state.locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::LockX64(Gen::X64Reg x64_reg) {
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
|
||||||
|
ASSERT(!x64_state.locked);
|
||||||
|
x64_state.locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::UnlockX64(Gen::X64Reg x64_reg) {
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
|
||||||
|
ASSERT(x64_state.locked);
|
||||||
|
x64_state.locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::FlushArm(ArmReg arm_reg) {
|
||||||
|
ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
Gen::X64Reg x64_reg = GetX64For(arm_reg);
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
|
||||||
|
ASSERT(!arm_state.locked);
|
||||||
|
ASSERT(!x64_state.locked);
|
||||||
|
ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg);
|
||||||
|
ASSERT(x64_state.arm_reg == arm_reg);
|
||||||
|
|
||||||
|
if (x64_state.state == X64State::State::DirtyArmReg) {
|
||||||
|
code->MOV(32, MJitStateCpuReg(arm_reg), R(x64_reg));
|
||||||
|
}
|
||||||
|
x64_state.state = X64State::State::Free;
|
||||||
|
arm_state.location = MJitStateCpuReg(arm_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::LockArm(ArmReg arm_reg) {
|
||||||
|
ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
|
||||||
|
ASSERT(!arm_state.locked);
|
||||||
|
arm_state.locked = true;
|
||||||
|
|
||||||
|
if (arm_state.location.IsSimpleReg()) {
|
||||||
|
Gen::X64Reg x64_reg = arm_state.location.GetSimpleReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
ASSERT(!x64_state.locked);
|
||||||
|
ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg);
|
||||||
|
ASSERT(x64_state.arm_reg == arm_reg);
|
||||||
|
|
||||||
|
x64_state.locked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::BindMaybeLoadAndLockArm(ArmReg arm_reg, bool load) {
|
||||||
|
ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
|
||||||
|
ASSERT(!arm_state.locked);
|
||||||
|
arm_state.locked = true;
|
||||||
|
|
||||||
|
if (arm_state.location.IsSimpleReg()) {
|
||||||
|
const Gen::X64Reg x64_reg = arm_state.location.GetSimpleReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
ASSERT(!x64_state.locked);
|
||||||
|
ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg);
|
||||||
|
ASSERT(x64_state.arm_reg == arm_reg);
|
||||||
|
|
||||||
|
x64_state.locked = true;
|
||||||
|
return x64_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Gen::X64Reg x64_reg = AllocReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
x64_state.locked = true;
|
||||||
|
x64_state.arm_reg = arm_reg;
|
||||||
|
x64_state.state = X64State::State::CleanArmReg;
|
||||||
|
|
||||||
|
if (load)
|
||||||
|
code->MOV(32, R(x64_reg), MJitStateCpuReg(arm_reg));
|
||||||
|
|
||||||
|
arm_state.location = R(x64_reg);
|
||||||
|
|
||||||
|
return x64_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::BindAndLockArm(ArmReg arm_reg) {
|
||||||
|
return BindMaybeLoadAndLockArm(arm_reg, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::BindNoLoadAndLockArm(ArmReg arm_reg) {
|
||||||
|
return BindMaybeLoadAndLockArm(arm_reg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::UnlockArm(ArmReg arm_reg) {
|
||||||
|
ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
|
||||||
|
ASSERT(arm_state.locked);
|
||||||
|
arm_state.locked = false;
|
||||||
|
|
||||||
|
if (arm_state.location.IsSimpleReg()) {
|
||||||
|
const Gen::X64Reg x64_reg = arm_state.location.GetSimpleReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
ASSERT(x64_state.locked);
|
||||||
|
ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg);
|
||||||
|
ASSERT(x64_state.arm_reg == arm_reg);
|
||||||
|
|
||||||
|
x64_state.locked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::FlushAllArm() {
|
||||||
|
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()) {
|
||||||
|
FlushArm(arm_reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::MarkDirty(ArmReg arm_reg) {
|
||||||
|
const ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
|
||||||
|
ASSERT(arm_state.locked);
|
||||||
|
ASSERT(arm_state.location.IsSimpleReg());
|
||||||
|
|
||||||
|
const Gen::X64Reg x64_reg = arm_state.location.GetSimpleReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
|
||||||
|
ASSERT(x64_state.locked);
|
||||||
|
ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg);
|
||||||
|
ASSERT(x64_state.arm_reg == arm_reg);
|
||||||
|
|
||||||
|
x64_state.state = X64State::State::DirtyArmReg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::FlushEverything() {
|
||||||
|
for (auto i : x64_reg_to_index) {
|
||||||
|
X64State& x64_state = x64_gpr[i.second];
|
||||||
|
ASSERT(!x64_state.locked);
|
||||||
|
FlushX64(i.first);
|
||||||
|
ASSERT(x64_state.state == X64State::State::Free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::GetX64For(ArmReg arm_reg) {
|
||||||
|
const ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
|
||||||
|
ASSERT(arm_state.location.IsSimpleReg());
|
||||||
|
|
||||||
|
const Gen::X64Reg x64_reg = arm_state.location.GetSimpleReg();
|
||||||
|
const X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
|
||||||
|
ASSERT(x64_state.state == X64State::State::CleanArmReg || x64_state.state == X64State::State::DirtyArmReg);
|
||||||
|
ASSERT(x64_state.arm_reg == arm_reg);
|
||||||
|
|
||||||
|
return x64_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::OpArg RegAlloc::ArmR(ArmReg arm_reg) {
|
||||||
|
const ArmState& arm_state = arm_gpr[arm_reg];
|
||||||
|
|
||||||
|
ASSERT(arm_state.locked);
|
||||||
|
|
||||||
|
return arm_state.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::AllocAndLockTemp() {
|
||||||
|
const Gen::X64Reg x64_reg = AllocReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
x64_state.locked = true;
|
||||||
|
x64_state.state = X64State::State::Temp;
|
||||||
|
|
||||||
|
return x64_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::UnlockTemp(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::Temp);
|
||||||
|
|
||||||
|
x64_state.locked = false;
|
||||||
|
x64_state.state = X64State::State::Free;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::BindAndLockMemoryMap() {
|
||||||
|
// First check to see if it exists.
|
||||||
|
for (auto i : x64_reg_to_index) {
|
||||||
|
X64State& x64_state = x64_gpr[i.second];
|
||||||
|
|
||||||
|
if (x64_state.state == X64State::State::MemoryMap) {
|
||||||
|
ASSERT(!x64_state.locked);
|
||||||
|
x64_state.locked = true;
|
||||||
|
return i.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise allocate it.
|
||||||
|
const Gen::X64Reg x64_reg = AllocReg();
|
||||||
|
X64State& x64_state = x64_gpr[x64_reg_to_index.at(x64_reg)];
|
||||||
|
x64_state.locked = true;
|
||||||
|
x64_state.state = X64State::State::MemoryMap;
|
||||||
|
|
||||||
|
code->MOV(64, R(x64_reg), MJitStateMemoryMap());
|
||||||
|
|
||||||
|
return x64_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegAlloc::UnlockMemoryMap(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::MemoryMap);
|
||||||
|
|
||||||
|
x64_state.locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen::X64Reg RegAlloc::AllocReg() {
|
||||||
|
// TODO: This is terrible.
|
||||||
|
|
||||||
|
// First check to see if there anything free.
|
||||||
|
for (auto i : x64_reg_to_index) {
|
||||||
|
X64State& x64_state = x64_gpr[i.second];
|
||||||
|
|
||||||
|
if (x64_state.locked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ASSERT(x64_state.state != X64State::State::Temp); // This can never happen.
|
||||||
|
|
||||||
|
if (x64_state.state == X64State::State::Free) {
|
||||||
|
return i.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise flush something.
|
||||||
|
for (auto i : x64_reg_to_index) {
|
||||||
|
X64State& x64_state = x64_gpr[i.second];
|
||||||
|
|
||||||
|
if (x64_state.locked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FlushX64(i.first);
|
||||||
|
return i.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_MSG(false, "Ran out of x64 registers");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
102
src/core/arm/jit_x64/reg_alloc.h
Normal file
102
src/core/arm/jit_x64/reg_alloc.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/x64/emitter.h"
|
||||||
|
|
||||||
|
#include "core/arm/decoder/decoder.h"
|
||||||
|
#include "core/arm/jit_x64/common.h"
|
||||||
|
|
||||||
|
namespace JitX64 {
|
||||||
|
|
||||||
|
// This is the register allocator
|
||||||
|
// TODO: Better algorithm required, ideally something that does reigster usage lookahead.
|
||||||
|
// (Designed so it should be simple to implement later.)
|
||||||
|
|
||||||
|
class RegAlloc final {
|
||||||
|
private:
|
||||||
|
struct ArmState {
|
||||||
|
Gen::OpArg location;
|
||||||
|
bool locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X64State {
|
||||||
|
enum class State {
|
||||||
|
Free,
|
||||||
|
Temp,
|
||||||
|
DirtyArmReg,
|
||||||
|
CleanArmReg,
|
||||||
|
MemoryMap
|
||||||
|
};
|
||||||
|
|
||||||
|
bool locked;
|
||||||
|
State state;
|
||||||
|
ArmReg arm_reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<ArmState, 15> arm_gpr;
|
||||||
|
std::array<X64State, 16> x64_gpr;
|
||||||
|
|
||||||
|
Gen::XEmitter* code = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Initialise register allocator (call compiling a basic block as it resets internal state)
|
||||||
|
void Init(Gen::XEmitter* emitter);
|
||||||
|
|
||||||
|
/// Ensures that the state of that register is State::Free.
|
||||||
|
void FlushX64(Gen::X64Reg x64_reg);
|
||||||
|
/// Locks a register: Marks it as in-use so it isn't allocated.
|
||||||
|
void LockX64(Gen::X64Reg x64_reg);
|
||||||
|
/// Unlocks a register: Allows it to be used for allocation again.
|
||||||
|
void UnlockX64(Gen::X64Reg x64_reg);
|
||||||
|
|
||||||
|
/// Ensures that this ARM register is not in an x64 register.
|
||||||
|
void FlushArm(ArmReg arm_reg);
|
||||||
|
/// Locks an ARM register so it doesn't move.
|
||||||
|
void LockArm(ArmReg arm_reg);
|
||||||
|
/// Allocates a x64 register for an ARM register and loads its value into it if necessary.
|
||||||
|
Gen::X64Reg BindAndLockArm(ArmReg arm_reg);
|
||||||
|
/// Allocates a x64 register for an ARM register but does not load a value.
|
||||||
|
Gen::X64Reg BindNoLoadAndLockArm(ArmReg arm_reg);
|
||||||
|
/// Unlock ARM register so the register is free to move and the underlying x64 register is available (if any).
|
||||||
|
void UnlockArm(ArmReg arm_reg);
|
||||||
|
/// Flush all ARM registers.
|
||||||
|
void FlushAllArm();
|
||||||
|
/// Marks an ARM register as dirty.
|
||||||
|
void MarkDirty(ArmReg arm_reg);
|
||||||
|
|
||||||
|
/// Flush absolutely everything.
|
||||||
|
void FlushEverything();
|
||||||
|
|
||||||
|
/// Gets the x64 register which corresponds to that ARM register. (ASSERTS IF NOT IN A x64 REG OR NOT LOCKED!)
|
||||||
|
Gen::X64Reg GetX64For(ArmReg arm_reg);
|
||||||
|
/// Gets the current location of this ARM register. (ASSERTS IF NOT LOCKED!)
|
||||||
|
Gen::OpArg ArmR(ArmReg arm_reg);
|
||||||
|
|
||||||
|
/// Allocates a temporary register
|
||||||
|
Gen::X64Reg AllocAndLockTemp();
|
||||||
|
/// Releases a temporary register
|
||||||
|
void UnlockTemp(Gen::X64Reg x64_reg);
|
||||||
|
|
||||||
|
/// Gets the x64 register with the address of the memory map in it. Allocates one if one doesn't already exist.
|
||||||
|
Gen::X64Reg BindAndLockMemoryMap();
|
||||||
|
/// Releases the memory map register.
|
||||||
|
void UnlockMemoryMap(Gen::X64Reg x64_reg);
|
||||||
|
|
||||||
|
/// Returns the register in which the JitState pointer is stored.
|
||||||
|
Gen::X64Reg JitStateReg();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// INTERNAL: Allocates a register that is free. Flushes registers that are not locked if necessary.
|
||||||
|
Gen::X64Reg AllocReg();
|
||||||
|
/// INTERNAL: Implementation of BindNoLoadAndLockArm and BindAndLockArm
|
||||||
|
Gen::X64Reg BindMaybeLoadAndLockArm(ArmReg arm_reg, bool load);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user