backend_x64/RegAlloc: Provide convenience function HostCall to save registers necessary as per host ABI
This commit is contained in:
parent
d92a771e3c
commit
cbcf61a9e6
2 changed files with 38 additions and 1 deletions
|
@ -133,6 +133,41 @@ Gen::X64Reg RegAlloc::ScratchRegister(std::initializer_list<HostLoc> desired_loc
|
||||||
return hostloc_to_x64.at(location);
|
return hostloc_to_x64.at(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegAlloc::HostCall(IR::Value* result_def, IR::Value* arg0_use, IR::Value* arg1_use, IR::Value* arg2_use, IR::Value* arg3_use) {
|
||||||
|
constexpr HostLoc AbiReturn = HostLoc::RAX;
|
||||||
|
#ifdef _WIN32
|
||||||
|
constexpr std::array<HostLoc, 4> AbiArgs = { HostLoc::RCX, HostLoc::RDX, HostLoc::R8, HostLoc::R9 };
|
||||||
|
/// Caller-saved registers other than AbiReturn or AbiArgs
|
||||||
|
constexpr std::array<HostLoc, 2> OtherCallerSave = { HostLoc::R10, HostLoc::R11 };
|
||||||
|
#else
|
||||||
|
constexpr std::array<HostLoc, 4> AbiArgs = { HostLoc::RDI, HostLoc::RSI, HostLoc::RDX, HostLoc::RCX };
|
||||||
|
/// Caller-saved registers other than AbiReturn or AbiArgs
|
||||||
|
constexpr std::array<HostLoc, 4> OtherCallerSave = { HostLoc::R8, HostLoc::R9, HostLoc::R10, HostLoc::R11 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const std::array<IR::Value*, 4> args = {arg0_use, arg1_use, arg2_use, arg3_use};
|
||||||
|
|
||||||
|
// TODO: This works but almost certainly leads to suboptimal generated code.
|
||||||
|
|
||||||
|
for (HostLoc caller_save : OtherCallerSave) {
|
||||||
|
ScratchRegister({caller_save});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result_def) {
|
||||||
|
DefRegister(result_def, {AbiReturn});
|
||||||
|
} else {
|
||||||
|
ScratchRegister({AbiReturn});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < AbiArgs.size(); i++) {
|
||||||
|
if (args[i]) {
|
||||||
|
UseRegister(args[i], {AbiArgs[i]});
|
||||||
|
} else {
|
||||||
|
ScratchRegister({AbiArgs[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HostLoc RegAlloc::SelectARegister(std::initializer_list<HostLoc> desired_locations) const {
|
HostLoc RegAlloc::SelectARegister(std::initializer_list<HostLoc> desired_locations) const {
|
||||||
std::vector<HostLoc> candidates = desired_locations;
|
std::vector<HostLoc> candidates = desired_locations;
|
||||||
|
|
||||||
|
@ -207,6 +242,5 @@ void RegAlloc::Reset() {
|
||||||
remaining_uses.clear();
|
remaining_uses.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace BackendX64
|
} // namespace BackendX64
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
||||||
|
|
|
@ -74,6 +74,9 @@ public:
|
||||||
/// Early-def, Late-use, single-use
|
/// Early-def, Late-use, single-use
|
||||||
Gen::X64Reg ScratchRegister(std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
Gen::X64Reg ScratchRegister(std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
||||||
|
|
||||||
|
/// Late-def for result register, Early-use for all arguments, Each value is placed into registers according to host ABI.
|
||||||
|
void HostCall(IR::Value* result_def = nullptr, IR::Value* arg0_use = nullptr, IR::Value* arg1_use = nullptr, IR::Value* arg2_use = nullptr, IR::Value* arg3_use = nullptr);
|
||||||
|
|
||||||
// TODO: Values in host flags
|
// TODO: Values in host flags
|
||||||
|
|
||||||
void EndOfAllocScope();
|
void EndOfAllocScope();
|
||||||
|
|
Loading…
Reference in a new issue