reg_alloc: New register allocation interface
This commit is contained in:
parent
13ac0c234e
commit
f883bad2cc
2 changed files with 127 additions and 0 deletions
|
@ -22,6 +22,8 @@ static u64 ImmediateToU64(const IR::Value& imm) {
|
|||
return u64(imm.GetU1());
|
||||
case IR::Type::U8:
|
||||
return u64(imm.GetU8());
|
||||
case IR::Type::U16:
|
||||
return u64(imm.GetU16());
|
||||
case IR::Type::U32:
|
||||
return u64(imm.GetU32());
|
||||
case IR::Type::U64:
|
||||
|
@ -80,6 +82,49 @@ static void EmitExchange(BlockOfCode* code, HostLoc a, HostLoc b) {
|
|||
}
|
||||
}
|
||||
|
||||
u8 Argument::GetImmediateU8() const {
|
||||
u64 imm = ImmediateToU64(value);
|
||||
ASSERT(imm < 0x100);
|
||||
return u8(imm);
|
||||
}
|
||||
|
||||
u16 Argument::GetImmediateU16() const {
|
||||
u64 imm = ImmediateToU64(value);
|
||||
ASSERT(imm < 0x10000);
|
||||
return u16(imm);
|
||||
}
|
||||
|
||||
u32 Argument::GetImmediateU32() const {
|
||||
u64 imm = ImmediateToU64(value);
|
||||
ASSERT(imm < 0x100000000);
|
||||
return u32(imm);
|
||||
}
|
||||
|
||||
u64 Argument::GetImmediateU64() const {
|
||||
return ImmediateToU64(value);
|
||||
}
|
||||
|
||||
bool Argument::IsInGpr() const {
|
||||
return HostLocIsGPR(*reg_alloc.ValueLocation(value.GetInst()));
|
||||
}
|
||||
|
||||
bool Argument::IsInXmm() const {
|
||||
return HostLocIsXMM(*reg_alloc.ValueLocation(value.GetInst()));
|
||||
}
|
||||
|
||||
bool Argument::IsInMemory() const {
|
||||
return HostLocIsSpill(*reg_alloc.ValueLocation(value.GetInst()));
|
||||
}
|
||||
|
||||
std::array<Argument, 3> RegAlloc::GetArgumentInfo(IR::Inst* inst) {
|
||||
std::array<Argument, 3> ret = { Argument{*this}, Argument{*this}, Argument{*this}};
|
||||
for (size_t i = 0; i < inst->NumArgs(); i++) {
|
||||
IR::Value arg = inst->GetArg(i);
|
||||
ret[i].value = arg;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RegAlloc::RegisterAddDef(IR::Inst* def_inst, const IR::Value& use_inst) {
|
||||
DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined");
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
namespace Dynarmic {
|
||||
namespace BackendX64 {
|
||||
|
||||
class RegAlloc;
|
||||
|
||||
struct HostLocInfo {
|
||||
public:
|
||||
bool IsLocked() const {
|
||||
|
@ -65,10 +67,88 @@ private:
|
|||
bool is_scratch = false;
|
||||
};
|
||||
|
||||
struct Argument {
|
||||
public:
|
||||
IR::Type GetType() const {
|
||||
return value.GetType();
|
||||
}
|
||||
bool IsImmediate() const {
|
||||
return value.IsImmediate();
|
||||
}
|
||||
|
||||
u8 GetImmediateU8() const;
|
||||
u16 GetImmediateU16() const;
|
||||
u32 GetImmediateU32() const;
|
||||
u64 GetImmediateU64() const;
|
||||
|
||||
/// Is this value currently in a GPR?
|
||||
bool IsInGpr() const;
|
||||
/// Is this value currently in a XMM?
|
||||
bool IsInXmm() const;
|
||||
/// Is this value currently in memory?
|
||||
bool IsInMemory() const;
|
||||
|
||||
private:
|
||||
friend class RegAlloc;
|
||||
Argument(RegAlloc& reg_alloc) : reg_alloc(reg_alloc) {}
|
||||
|
||||
bool allocated = false;
|
||||
RegAlloc& reg_alloc;
|
||||
IR::Value value;
|
||||
};
|
||||
|
||||
class RegAlloc final {
|
||||
public:
|
||||
explicit RegAlloc(BlockOfCode* code) : code(code) {}
|
||||
|
||||
std::array<Argument, 3> GetArgumentInfo(IR::Inst* inst);
|
||||
|
||||
Xbyak::Reg64 UseGpr(Argument& arg) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
return HostLocToReg64(UseHostLocReg(arg.value, any_gpr));
|
||||
}
|
||||
Xbyak::Xmm UseXmm(Argument& arg) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
return HostLocToXmm(UseHostLocReg(arg.value, any_xmm));
|
||||
}
|
||||
void Use(Argument& arg, HostLoc host_loc) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
UseHostLocReg(arg.value, {host_loc});
|
||||
}
|
||||
|
||||
Xbyak::Reg64 UseScratchGpr(Argument& arg) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
return HostLocToReg64(UseScratchHostLocReg(arg.value, any_gpr));
|
||||
}
|
||||
Xbyak::Xmm UseScratchXmm(Argument& arg) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
return HostLocToXmm(UseScratchHostLocReg(arg.value, any_xmm));
|
||||
}
|
||||
void UseScratch(Argument& arg, HostLoc host_loc) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
UseScratchHostLocReg(arg.value, {host_loc});
|
||||
}
|
||||
|
||||
void DefineValue(IR::Inst* inst, const Xbyak::Reg64& reg) {
|
||||
HostLoc hostloc = static_cast<HostLoc>(reg.getIdx() + static_cast<size_t>(HostLoc::RAX));
|
||||
DefineValue(inst, hostloc);
|
||||
}
|
||||
void DefineValue(IR::Inst* inst, const Xbyak::Xmm& reg) {
|
||||
HostLoc hostloc = static_cast<HostLoc>(reg.getIdx() + static_cast<size_t>(HostLoc::XMM0));
|
||||
DefineValue(inst, hostloc);
|
||||
}
|
||||
void DefineValue(IR::Inst* inst, Argument& arg) {
|
||||
ASSERT(!arg.allocated);
|
||||
arg.allocated = true;
|
||||
RegisterAddDef(inst, arg.value);
|
||||
}
|
||||
|
||||
/// Late-def
|
||||
Xbyak::Reg64 DefGpr(IR::Inst* def_inst, HostLocList desired_locations = any_gpr) {
|
||||
HostLoc location = ScratchHostLocReg(desired_locations);
|
||||
|
@ -139,6 +219,8 @@ public:
|
|||
void Reset();
|
||||
|
||||
private:
|
||||
friend struct Argument;
|
||||
|
||||
HostLoc SelectARegister(HostLocList desired_locations) const;
|
||||
boost::optional<HostLoc> ValueLocation(const IR::Inst* value) const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue