reg_alloc: Reimplement UseHostLocReg

This commit is contained in:
MerryMage 2017-02-24 19:42:36 +00:00
parent aefe550428
commit 2b078152e7
2 changed files with 104 additions and 54 deletions

View file

@ -42,6 +42,44 @@ static Xbyak::Reg HostLocToX64(HostLoc hostloc) {
ASSERT_MSG(false, "This should never happen.");
}
static bool IsSameHostLocClass(HostLoc a, HostLoc b) {
return (HostLocIsGPR(a) && HostLocIsGPR(b))
|| (HostLocIsXMM(a) && HostLocIsXMM(b))
|| (HostLocIsSpill(a) && HostLocIsSpill(b));
}
static void EmitMove(BlockOfCode* code, HostLoc to, HostLoc from) {
if (HostLocIsXMM(to) && HostLocIsXMM(from)) {
code->movaps(HostLocToXmm(to), HostLocToXmm(from));
} else if (HostLocIsGPR(to) && HostLocIsGPR(from)) {
code->mov(HostLocToReg64(to), HostLocToReg64(from));
} else if (HostLocIsXMM(to) && HostLocIsGPR(from)) {
ASSERT_MSG(false, "TODO");
} else if (HostLocIsGPR(to) && HostLocIsXMM(from)) {
ASSERT_MSG(false, "TODO");
} else if (HostLocIsXMM(to) && HostLocIsSpill(from)) {
code->movsd(HostLocToXmm(to), SpillToOpArg(from));
} else if (HostLocIsSpill(to) && HostLocIsXMM(from)) {
code->movsd(SpillToOpArg(to), HostLocToXmm(from));
} else if (HostLocIsGPR(to) && HostLocIsSpill(from)) {
code->mov(HostLocToReg64(to), SpillToOpArg(from));
} else if (HostLocIsSpill(to) && HostLocIsGPR(from)) {
code->mov(SpillToOpArg(to), HostLocToReg64(from));
} else {
ASSERT_MSG(false, "Invalid RegAlloc::EmitMove");
}
}
static void EmitExchange(BlockOfCode* code, HostLoc a, HostLoc b) {
if (HostLocIsGPR(a) && HostLocIsGPR(b)) {
code->xchg(HostLocToReg64(a), HostLocToReg64(b));
} else if (HostLocIsXMM(a) && HostLocIsXMM(b)) {
ASSERT_MSG(false, "Check your code: Exchanging XMM registers is unnecessary");
} else {
ASSERT_MSG(false, "Invalid RegAlloc::EmitExchange");
}
}
void RegAlloc::RegisterAddDef(IR::Inst* def_inst, const IR::Value& use_inst) {
DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined");
@ -100,30 +138,29 @@ HostLoc RegAlloc::UseHostLocReg(IR::Value use_value, HostLocList desired_locatio
}
HostLoc RegAlloc::UseHostLocReg(IR::Inst* use_inst, HostLocList desired_locations) {
HostLoc current_location;
bool was_being_used;
std::tie(current_location, was_being_used) = UseHostLoc(use_inst, desired_locations);
use_inst->DecrementRemainingUses();
if (HostLocIsRegister(current_location)) {
const HostLoc current_location = *ValueLocation(use_inst);
const bool can_use_current_location = std::find(desired_locations.begin(), desired_locations.end(), current_location) != desired_locations.end();
if (can_use_current_location) {
LocInfo(current_location).Lock();
return current_location;
} else if (HostLocIsSpill(current_location)) {
HostLoc new_location = SelectARegister(desired_locations);
if (IsRegisterOccupied(new_location)) {
SpillRegister(new_location);
}
EmitMove(new_location, current_location);
if (!was_being_used) {
LocInfo(new_location) = LocInfo(current_location);
LocInfo(current_location) = {};
DEBUG_ASSERT(LocInfo(new_location).IsUse());
} else {
LocInfo(new_location).Lock();
DEBUG_ASSERT(LocInfo(new_location).IsScratch());
}
return new_location;
}
ASSERT_MSG(false, "Unknown current_location type");
if (LocInfo(current_location).IsLocked()) {
return UseScratchHostLocReg(use_inst, desired_locations);
}
const HostLoc destination_location = SelectARegister(desired_locations);
if (IsSameHostLocClass(destination_location, current_location)) {
Exchange(destination_location, current_location);
} else {
MoveOutOfTheWay(destination_location);
Move(destination_location, current_location);
}
LocInfo(destination_location).Lock();
return destination_location;
}
OpArg RegAlloc::UseOpArg(IR::Value use_value, HostLocList desired_locations) {
@ -167,7 +204,7 @@ HostLoc RegAlloc::UseScratchHostLocReg(IR::Inst* use_inst, HostLocList desired_l
}
if (HostLocIsSpill(current_location)) {
EmitMove(new_location, current_location);
EmitMove(code, new_location, current_location);
LocInfo(new_location).Lock();
use_inst->DecrementRemainingUses();
DEBUG_ASSERT(LocInfo(new_location).IsScratch());
@ -177,7 +214,7 @@ HostLoc RegAlloc::UseScratchHostLocReg(IR::Inst* use_inst, HostLocList desired_l
|| LocInfo(current_location).IsUse());
if (current_location != new_location) {
EmitMove(new_location, current_location);
EmitMove(code, new_location, current_location);
} else {
ASSERT(LocInfo(current_location).IsIdle());
}
@ -300,7 +337,7 @@ void RegAlloc::SpillRegister(HostLoc loc) {
HostLoc new_loc = FindFreeSpill();
EmitMove(new_loc, loc);
EmitMove(code, new_loc, loc);
LocInfo(new_loc) = LocInfo(loc);
LocInfo(loc) = {};
@ -330,34 +367,6 @@ void RegAlloc::Reset() {
hostloc_info.fill({});
}
void RegAlloc::EmitMove(HostLoc to, HostLoc from) {
if (HostLocIsXMM(to) && HostLocIsSpill(from)) {
code->movsd(HostLocToXmm(to), SpillToOpArg(from));
} else if (HostLocIsSpill(to) && HostLocIsXMM(from)) {
code->movsd(SpillToOpArg(to), HostLocToXmm(from));
} else if (HostLocIsXMM(to) && HostLocIsXMM(from)) {
code->movaps(HostLocToXmm(to), HostLocToXmm(from));
} else if (HostLocIsGPR(to) && HostLocIsSpill(from)) {
code->mov(HostLocToReg64(to), SpillToOpArg(from));
} else if (HostLocIsSpill(to) && HostLocIsGPR(from)) {
code->mov(SpillToOpArg(to), HostLocToReg64(from));
} else if (HostLocIsGPR(to) && HostLocIsGPR(from)){
code->mov(HostLocToReg64(to), HostLocToReg64(from));
} else {
ASSERT_MSG(false, "Invalid RegAlloc::EmitMove");
}
}
void RegAlloc::EmitExchange(HostLoc a, HostLoc b) {
if (HostLocIsGPR(a) && HostLocIsGPR(b)) {
code->xchg(HostLocToReg64(a), HostLocToReg64(b));
} else if (HostLocIsXMM(a) && HostLocIsXMM(b)) {
ASSERT_MSG(false, "Exchange is unnecessary for XMM registers");
} else {
ASSERT_MSG(false, "Invalid RegAlloc::EmitExchange");
}
}
std::tuple<HostLoc, bool> RegAlloc::UseHostLoc(IR::Inst* use_inst, HostLocList desired_locations) {
DEBUG_ASSERT(std::all_of(desired_locations.begin(), desired_locations.end(), HostLocIsRegister));
DEBUG_ASSERT_MSG(ValueLocation(use_inst), "use_inst has not been defined");
@ -382,7 +391,7 @@ std::tuple<HostLoc, bool> RegAlloc::UseHostLoc(IR::Inst* use_inst, HostLocList d
} else if (HostLocIsRegister(current_location)) {
HostLoc new_location = SelectARegister(desired_locations);
ASSERT(LocInfo(current_location).IsIdle());
EmitExchange(new_location, current_location);
EmitExchange(code, new_location, current_location);
std::swap(LocInfo(new_location), LocInfo(current_location));
LocInfo(new_location).Lock();
use_inst->DecrementRemainingUses();
@ -407,5 +416,44 @@ HostLoc RegAlloc::LoadImmediateIntoHostLocReg(IR::Value imm, HostLoc host_loc) {
return host_loc;
}
void RegAlloc::Move(HostLoc to, HostLoc from) {
ASSERT(LocInfo(to).IsEmpty() && !LocInfo(from).IsLocked());
if (LocInfo(from).IsEmpty()) {
return;
}
LocInfo(to) = LocInfo(from);
LocInfo(from) = {};
EmitMove(code, to, from);
}
void RegAlloc::Exchange(HostLoc a, HostLoc b) {
ASSERT(!LocInfo(a).IsLocked() && !LocInfo(b).IsLocked());
if (LocInfo(a).IsEmpty()) {
Move(a, b);
return;
}
if (LocInfo(b).IsEmpty()) {
Move(b, a);
return;
}
std::swap(LocInfo(a), LocInfo(b));
EmitExchange(code, a, b);
}
void RegAlloc::MoveOutOfTheWay(HostLoc reg) {
ASSERT(!LocInfo(reg).IsLocked());
if (IsRegisterOccupied(reg)) {
SpillRegister(reg);
}
}
} // namespace BackendX64
} // namespace Dynarmic

View file

@ -153,10 +153,12 @@ private:
HostLoc UseScratchHostLocReg(IR::Inst* use_inst, HostLocList desired_locations);
HostLoc ScratchHostLocReg(HostLocList desired_locations);
void EmitMove(HostLoc to, HostLoc from);
void EmitExchange(HostLoc a, HostLoc b);
HostLoc LoadImmediateIntoHostLocReg(IR::Value imm, HostLoc reg);
void Move(HostLoc to, HostLoc from);
void Exchange(HostLoc a, HostLoc b);
void MoveOutOfTheWay(HostLoc reg);
void SpillRegister(HostLoc loc);
HostLoc FindFreeSpill() const;