diff --git a/src/backend_x64/reg_alloc.cpp b/src/backend_x64/reg_alloc.cpp index 79c7f047..5b72db36 100644 --- a/src/backend_x64/reg_alloc.cpp +++ b/src/backend_x64/reg_alloc.cpp @@ -133,6 +133,41 @@ Gen::X64Reg RegAlloc::ScratchRegister(std::initializer_list desired_loc 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 AbiArgs = { HostLoc::RCX, HostLoc::RDX, HostLoc::R8, HostLoc::R9 }; + /// Caller-saved registers other than AbiReturn or AbiArgs + constexpr std::array OtherCallerSave = { HostLoc::R10, HostLoc::R11 }; +#else + constexpr std::array AbiArgs = { HostLoc::RDI, HostLoc::RSI, HostLoc::RDX, HostLoc::RCX }; + /// Caller-saved registers other than AbiReturn or AbiArgs + constexpr std::array OtherCallerSave = { HostLoc::R8, HostLoc::R9, HostLoc::R10, HostLoc::R11 }; +#endif + + const std::array 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 desired_locations) const { std::vector candidates = desired_locations; @@ -207,6 +242,5 @@ void RegAlloc::Reset() { remaining_uses.clear(); } - } // namespace BackendX64 } // namespace Dynarmic diff --git a/src/backend_x64/reg_alloc.h b/src/backend_x64/reg_alloc.h index d5a25451..bf4d6ee6 100644 --- a/src/backend_x64/reg_alloc.h +++ b/src/backend_x64/reg_alloc.h @@ -74,6 +74,9 @@ public: /// Early-def, Late-use, single-use Gen::X64Reg ScratchRegister(std::initializer_list 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 void EndOfAllocScope();