From 7bdabeb94277d1d9a30c4596c94a4c49d7293ec9 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 16 May 2026 01:07:50 +0000 Subject: [PATCH] [xbyak] fix odr violation on MSVC Signed-off-by: lizzie --- src/common/x64/xbyak.h | 277 +----------------- .../backend/x64/a32_emit_x64_memory.cpp | 2 +- .../backend/x64/a64_emit_x64_memory.cpp | 2 +- src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 2 +- .../dynarmic/backend/x64/block_of_code.cpp | 2 +- .../src/dynarmic/backend/x64/block_of_code.h | 2 +- .../src/dynarmic/backend/x64/callback.h | 2 +- .../src/dynarmic/backend/x64/constant_pool.h | 2 +- .../src/dynarmic/backend/x64/emit_x64.h | 2 +- .../backend/x64/emit_x64_floating_point.cpp | 2 +- .../dynarmic/backend/x64/emit_x64_memory.h | 2 +- .../dynarmic/backend/x64/emit_x64_vector.cpp | 2 +- .../x64/emit_x64_vector_floating_point.cpp | 2 +- .../src/dynarmic/backend/x64/hostloc.h | 2 +- src/dynarmic/src/dynarmic/backend/x64/oparg.h | 2 +- .../src/dynarmic/backend/x64/reg_alloc.cpp | 2 +- .../src/dynarmic/backend/x64/reg_alloc.h | 2 +- src/dynarmic/src/dynarmic/backend/x64/xbyak.h | 13 - .../src/dynarmic/common/spin_lock_x64.cpp | 2 +- .../src/dynarmic/common/spin_lock_x64.h | 2 +- src/dynarmic/tests/x64_cpu_info.cpp | 2 +- src/video_core/macro.cpp | 260 ++++++++++++++++ 22 files changed, 280 insertions(+), 308 deletions(-) delete mode 100644 src/dynarmic/src/dynarmic/backend/x64/xbyak.h diff --git a/src/common/x64/xbyak.h b/src/common/x64/xbyak.h index 5ee12576e9..c16c1ef5db 100644 --- a/src/common/x64/xbyak.h +++ b/src/common/x64/xbyak.h @@ -1,287 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: 2016 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - #pragma once -#include -#include -#include -#include "common/assert.h" - -// xbyak hates human beings -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wshadow" -#endif -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wshadow" -#endif - // You must ensure this matches with src/common/x64/xbyak.h on root dir #include -#include #define XBYAK_STD_UNORDERED_SET ankerl::unordered_dense::set #define XBYAK_STD_UNORDERED_MAP ankerl::unordered_dense::map -#define XBYAK_STD_UNORDERED_MULTIMAP boost::unordered_multimap +#define XBYAK_STD_UNORDERED_MULTIMAP std::multimap #include #include - -#include - -namespace Common::X64 { - -constexpr size_t RegToIndex(const Xbyak::Reg& reg) { - using Kind = Xbyak::Reg::Kind; - ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, - "RegSet only support GPRs and XMM registers."); - ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15."); - return static_cast(reg.getIdx()) + (reg.getKind() == Kind::REG ? 0 : 16); -} - -constexpr Xbyak::Reg64 IndexToReg64(size_t reg_index) { - ASSERT(reg_index < 16); - return Xbyak::Reg64(static_cast(reg_index)); -} - -constexpr Xbyak::Xmm IndexToXmm(size_t reg_index) { - ASSERT(reg_index >= 16 && reg_index < 32); - return Xbyak::Xmm(static_cast(reg_index - 16)); -} - -constexpr Xbyak::Reg IndexToReg(size_t reg_index) { - if (reg_index < 16) { - return IndexToReg64(reg_index); - } else { - return IndexToXmm(reg_index); - } -} - -constexpr std::bitset<32> BuildRegSet(std::initializer_list regs) { - size_t bits = 0; - for (const Xbyak::Reg& reg : regs) { - bits |= size_t{1} << RegToIndex(reg); - } - return {bits}; -} - -constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF); -constexpr inline std::bitset<32> ABI_ALL_XMMS(0xFFFF0000); - -constexpr inline Xbyak::Reg ABI_JIT_REG = Xbyak::util::rbx; -#ifdef _WIN32 - -// Microsoft x64 ABI -constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax; -constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx; -constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx; -constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8; -constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9; - -constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({ - // GPRs - Xbyak::util::rcx, - Xbyak::util::rdx, - Xbyak::util::r8, - Xbyak::util::r9, - Xbyak::util::r10, - Xbyak::util::r11, - // XMMs - Xbyak::util::xmm0, - Xbyak::util::xmm1, - Xbyak::util::xmm2, - Xbyak::util::xmm3, - Xbyak::util::xmm4, - Xbyak::util::xmm5, -}); - -constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({ - // GPRs - Xbyak::util::rbx, - Xbyak::util::rsi, - Xbyak::util::rdi, - Xbyak::util::rbp, - Xbyak::util::r12, - Xbyak::util::r13, - Xbyak::util::r14, - Xbyak::util::r15, - // XMMs - Xbyak::util::xmm6, - Xbyak::util::xmm7, - Xbyak::util::xmm8, - Xbyak::util::xmm9, - Xbyak::util::xmm10, - Xbyak::util::xmm11, - Xbyak::util::xmm12, - Xbyak::util::xmm13, - Xbyak::util::xmm14, - Xbyak::util::xmm15, -}); - -constexpr size_t ABI_SHADOW_SPACE = 0x20; - -#else - -// System V x86-64 ABI -constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax; -constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi; -constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi; -constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx; -constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx; - -constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({ - // GPRs - Xbyak::util::rcx, - Xbyak::util::rdx, - Xbyak::util::rdi, - Xbyak::util::rsi, - Xbyak::util::r8, - Xbyak::util::r9, - Xbyak::util::r10, - Xbyak::util::r11, - // XMMs - Xbyak::util::xmm0, - Xbyak::util::xmm1, - Xbyak::util::xmm2, - Xbyak::util::xmm3, - Xbyak::util::xmm4, - Xbyak::util::xmm5, - Xbyak::util::xmm6, - Xbyak::util::xmm7, - Xbyak::util::xmm8, - Xbyak::util::xmm9, - Xbyak::util::xmm10, - Xbyak::util::xmm11, - Xbyak::util::xmm12, - Xbyak::util::xmm13, - Xbyak::util::xmm14, - Xbyak::util::xmm15, -}); - -constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({ - // GPRs - Xbyak::util::rbx, - Xbyak::util::rbp, - Xbyak::util::r12, - Xbyak::util::r13, - Xbyak::util::r14, - Xbyak::util::r15, -}); - -constexpr size_t ABI_SHADOW_SPACE = 0; - -#endif - -struct ABIFrameInfo { - s32 subtraction; - s32 xmm_offset; -}; - -inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<32> regs, size_t rsp_alignment, - size_t needed_frame_size) { - const auto count = (regs & ABI_ALL_GPRS).count(); - rsp_alignment -= count * 8; - size_t subtraction = 0; - const auto xmm_count = (regs & ABI_ALL_XMMS).count(); - if (xmm_count) { - // If we have any XMMs to save, we must align the stack here. - subtraction = rsp_alignment & 0xF; - } - subtraction += 0x10 * xmm_count; - size_t xmm_base_subtraction = subtraction; - subtraction += needed_frame_size; - subtraction += ABI_SHADOW_SPACE; - // Final alignment. - rsp_alignment -= subtraction; - subtraction += rsp_alignment & 0xF; - - return ABIFrameInfo{ - s32(subtraction), - s32(subtraction - xmm_base_subtraction) - }; -} - -inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size = 0) { - auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); - - for (size_t i = 0; i < regs.size(); ++i) { - if (regs[i] && ABI_ALL_GPRS[i]) { - code.push(IndexToReg64(i)); - } - } - - if (frame_info.subtraction != 0) { - code.sub(code.rsp, frame_info.subtraction); - } - - for (size_t i = 0; i < regs.size(); ++i) { - if (regs[i] && ABI_ALL_XMMS[i]) { - code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i)); - frame_info.xmm_offset += 0x10; - } - } - - return ABI_SHADOW_SPACE; -} - -inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size = 0) { - auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); - - for (size_t i = 0; i < regs.size(); ++i) { - if (regs[i] && ABI_ALL_XMMS[i]) { - code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]); - frame_info.xmm_offset += 0x10; - } - } - - if (frame_info.subtraction != 0) { - code.add(code.rsp, frame_info.subtraction); - } - - // GPRs need to be popped in reverse order - for (size_t j = 0; j < regs.size(); ++j) { - const size_t i = regs.size() - j - 1; - if (regs[i] && ABI_ALL_GPRS[i]) { - code.pop(IndexToReg64(i)); - } - } -} - -// Constants for use with cmpps/cmpss -enum { - CMP_EQ = 0, - CMP_LT = 1, - CMP_LE = 2, - CMP_UNORD = 3, - CMP_NEQ = 4, - CMP_NLT = 5, - CMP_NLE = 6, - CMP_ORD = 7, -}; - -constexpr bool IsWithin2G(uintptr_t ref, uintptr_t target) { - const u64 distance = target - (ref + 5); - return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL); -} - -inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { - return IsWithin2G(reinterpret_cast(code.getCurr()), target); -} - -template -inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { - static_assert(std::is_pointer_v, "Argument must be a (function) pointer."); - size_t addr = reinterpret_cast(f); - if (IsWithin2G(code, addr)) { - code.call(f); - } else { - // ABI_RETURN is a safe temp register to use before a call - code.mov(ABI_RETURN, addr); - code.call(ABI_RETURN); - } -} - -} // namespace Common::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp index f138b5f137..444ff33615 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp @@ -14,7 +14,7 @@ #include #include #include "dynarmic/mcl/integer_of_size.hpp" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/a32_emit_x64.h" #include "dynarmic/backend/x64/abi.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp index 4b7054b4b2..db6c9dd1fa 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp @@ -14,7 +14,7 @@ #include #include #include "dynarmic/mcl/integer_of_size.hpp" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/a64_emit_x64.h" #include "dynarmic/backend/x64/abi.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index 59ecc974f7..388e3993cd 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -11,7 +11,7 @@ #include #include "common/common_types.h" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/block_of_code.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index f41bea6c83..f59c3bfcab 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -26,7 +26,7 @@ #include "common/assert.h" #include "dynarmic/mcl/bit.hpp" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/a32_jitstate.h" #include "dynarmic/backend/x64/abi.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h index 857b1a4484..4dc367c8eb 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h @@ -15,7 +15,7 @@ #include "dynarmic/mcl/bit.hpp" #include "common/common_types.h" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/callback.h" #include "dynarmic/backend/x64/constant_pool.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/callback.h b/src/dynarmic/src/dynarmic/backend/x64/callback.h index fb1a1a5855..4fb51bdffc 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/callback.h +++ b/src/dynarmic/src/dynarmic/backend/x64/callback.h @@ -12,7 +12,7 @@ #include #include "common/common_types.h" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" namespace Dynarmic::Backend::X64 { diff --git a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h index 79e57fc78c..83688d4307 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h +++ b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h @@ -15,7 +15,7 @@ #include "common/common_types.h" #include -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" namespace Dynarmic::Backend::X64 { diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h index 619945e19a..0f5e1e31f5 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h @@ -20,7 +20,7 @@ #include #include -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/mcl/bit.hpp" #include "dynarmic/backend/exception_handler.h" #include "dynarmic/backend/x64/reg_alloc.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 827600c7c2..d8646f3a86 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -13,7 +13,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "dynarmic/mcl/integer_of_size.hpp" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/block_of_code.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h index 3ac078f1d7..52ea9a74ab 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h @@ -9,7 +9,7 @@ #pragma once #include -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/a32_emit_x64.h" #include "dynarmic/backend/x64/a64_emit_x64.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp index b5ec6ec7cf..7a24f7d062 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp @@ -16,7 +16,7 @@ #include "dynarmic/mcl/bit.hpp" #include "common/common_types.h" #include "dynarmic/mcl/function_info.hpp" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/block_of_code.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index 926653a920..29ccfff9f0 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -15,7 +15,7 @@ #include "common/assert.h" #include "dynarmic/mcl/function_info.hpp" #include "dynarmic/mcl/integer_of_size.hpp" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/block_of_code.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h index d62090d612..430323d679 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h @@ -10,7 +10,7 @@ #include #include "common/assert.h" #include "common/common_types.h" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" namespace Dynarmic::Backend::X64 { diff --git a/src/dynarmic/src/dynarmic/backend/x64/oparg.h b/src/dynarmic/src/dynarmic/backend/x64/oparg.h index 7366c0c7a3..f8cd7f33d1 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/oparg.h +++ b/src/dynarmic/src/dynarmic/backend/x64/oparg.h @@ -9,7 +9,7 @@ #pragma once #include "common/assert.h" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" namespace Dynarmic::Backend::X64 { diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp index 5a828839c1..f55d0d8127 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp @@ -15,7 +15,7 @@ #include "dynarmic/backend/x64/hostloc.h" #include "common/assert.h" #include -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/reg_alloc.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h index 455c6a970a..844fb4a554 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h @@ -14,7 +14,7 @@ #include "boost/container/small_vector.hpp" #include "common/common_types.h" -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include #include #include diff --git a/src/dynarmic/src/dynarmic/backend/x64/xbyak.h b/src/dynarmic/src/dynarmic/backend/x64/xbyak.h deleted file mode 100644 index 38401678e6..0000000000 --- a/src/dynarmic/src/dynarmic/backend/x64/xbyak.h +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -// You must ensure this matches with src/common/x64/xbyak.h on root dir -#include -#include -#define XBYAK_STD_UNORDERED_SET ankerl::unordered_dense::set -#define XBYAK_STD_UNORDERED_MAP ankerl::unordered_dense::map -#define XBYAK_STD_UNORDERED_MULTIMAP boost::unordered_multimap -#include -#include diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp index 1a80ae638a..97cf67073b 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp +++ b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp @@ -8,7 +8,7 @@ #include #include -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/hostloc.h" diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_x64.h b/src/dynarmic/src/dynarmic/common/spin_lock_x64.h index b17d4f67f8..5f6ce044e7 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_x64.h +++ b/src/dynarmic/src/dynarmic/common/spin_lock_x64.h @@ -8,7 +8,7 @@ #pragma once -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" namespace Dynarmic { diff --git a/src/dynarmic/tests/x64_cpu_info.cpp b/src/dynarmic/tests/x64_cpu_info.cpp index a33d8c013f..04ea991675 100644 --- a/src/dynarmic/tests/x64_cpu_info.cpp +++ b/src/dynarmic/tests/x64_cpu_info.cpp @@ -14,7 +14,7 @@ #include #include -#include "dynarmic/backend/x64/xbyak.h" +#include "common/x64/xbyak.h" TEST_CASE("Host CPU supports", "[a64]") { using Cpu = Xbyak::util::Cpu; diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index dbf011860e..831bed2476 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -13,7 +13,267 @@ #include #ifdef ARCHITECTURE_x86_64 + +#include +#include +#include +#include "common/assert.h" + +// xbyak hates human beings +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wshadow" +#endif +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wshadow" +#endif + #include "common/x64/xbyak.h" + +namespace Common::X64 { + +constexpr size_t RegToIndex(const Xbyak::Reg& reg) { + using Kind = Xbyak::Reg::Kind; + ASSERT((reg.getKind() & (Kind::REG | Kind::XMM)) != 0 && "RegSet only support GPRs and XMM registers."); + ASSERT(reg.getIdx() < 16 && "RegSet only supports XXM0-15."); + return size_t(reg.getIdx()) + (reg.getKind() == Kind::REG ? 0 : 16); +} + +constexpr Xbyak::Reg64 IndexToReg64(size_t reg_index) { + ASSERT(reg_index < 16); + return Xbyak::Reg64(int(reg_index)); +} + +constexpr Xbyak::Xmm IndexToXmm(size_t reg_index) { + ASSERT(reg_index >= 16 && reg_index < 32); + return Xbyak::Xmm(int(reg_index - 16)); +} + +constexpr Xbyak::Reg IndexToReg(size_t reg_index) { + if (reg_index < 16) { + return IndexToReg64(reg_index); + } else { + return IndexToXmm(reg_index); + } +} + +constexpr std::bitset<32> BuildRegSet(std::initializer_list regs) { + size_t bits = 0; + for (const Xbyak::Reg& reg : regs) + bits |= size_t{1} << RegToIndex(reg); + return {bits}; +} + +constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF); +constexpr inline std::bitset<32> ABI_ALL_XMMS(0xFFFF0000); + +constexpr inline Xbyak::Reg ABI_JIT_REG = Xbyak::util::rbx; +#ifdef _WIN32 +// Microsoft x64 ABI +constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax; +constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx; +constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx; +constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8; +constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9; + +constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({ + // GPRs + Xbyak::util::rcx, + Xbyak::util::rdx, + Xbyak::util::r8, + Xbyak::util::r9, + Xbyak::util::r10, + Xbyak::util::r11, + // XMMs + Xbyak::util::xmm0, + Xbyak::util::xmm1, + Xbyak::util::xmm2, + Xbyak::util::xmm3, + Xbyak::util::xmm4, + Xbyak::util::xmm5, +}); + +constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({ + // GPRs + Xbyak::util::rbx, + Xbyak::util::rsi, + Xbyak::util::rdi, + Xbyak::util::rbp, + Xbyak::util::r12, + Xbyak::util::r13, + Xbyak::util::r14, + Xbyak::util::r15, + // XMMs + Xbyak::util::xmm6, + Xbyak::util::xmm7, + Xbyak::util::xmm8, + Xbyak::util::xmm9, + Xbyak::util::xmm10, + Xbyak::util::xmm11, + Xbyak::util::xmm12, + Xbyak::util::xmm13, + Xbyak::util::xmm14, + Xbyak::util::xmm15, +}); + +constexpr size_t ABI_SHADOW_SPACE = 0x20; + +#else + +// System V x86-64 ABI +constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax; +constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi; +constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi; +constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx; +constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx; + +constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({ + // GPRs + Xbyak::util::rcx, + Xbyak::util::rdx, + Xbyak::util::rdi, + Xbyak::util::rsi, + Xbyak::util::r8, + Xbyak::util::r9, + Xbyak::util::r10, + Xbyak::util::r11, + // XMMs + Xbyak::util::xmm0, + Xbyak::util::xmm1, + Xbyak::util::xmm2, + Xbyak::util::xmm3, + Xbyak::util::xmm4, + Xbyak::util::xmm5, + Xbyak::util::xmm6, + Xbyak::util::xmm7, + Xbyak::util::xmm8, + Xbyak::util::xmm9, + Xbyak::util::xmm10, + Xbyak::util::xmm11, + Xbyak::util::xmm12, + Xbyak::util::xmm13, + Xbyak::util::xmm14, + Xbyak::util::xmm15, +}); + +constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({ + // GPRs + Xbyak::util::rbx, + Xbyak::util::rbp, + Xbyak::util::r12, + Xbyak::util::r13, + Xbyak::util::r14, + Xbyak::util::r15, +}); + +constexpr size_t ABI_SHADOW_SPACE = 0; +#endif + +struct ABIFrameInfo { + s32 subtraction; + s32 xmm_offset; +}; + +inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size) { + const auto count = (regs & ABI_ALL_GPRS).count(); + rsp_alignment -= count * 8; + size_t subtraction = 0; + const auto xmm_count = (regs & ABI_ALL_XMMS).count(); + if (xmm_count) { + // If we have any XMMs to save, we must align the stack here. + subtraction = rsp_alignment & 0xF; + } + subtraction += 0x10 * xmm_count; + size_t xmm_base_subtraction = subtraction; + subtraction += needed_frame_size; + subtraction += ABI_SHADOW_SPACE; + // Final alignment. + rsp_alignment -= subtraction; + subtraction += rsp_alignment & 0xF; + + return ABIFrameInfo{ + s32(subtraction), + s32(subtraction - xmm_base_subtraction) + }; +} + +inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size = 0) { + auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); + for (size_t i = 0; i < regs.size(); ++i) + if (regs[i] && ABI_ALL_GPRS[i]) + code.push(IndexToReg64(i)); + + if (frame_info.subtraction != 0) + code.sub(code.rsp, frame_info.subtraction); + + for (size_t i = 0; i < regs.size(); ++i) { + if (regs[i] && ABI_ALL_XMMS[i]) { + code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i)); + frame_info.xmm_offset += 0x10; + } + } + + return ABI_SHADOW_SPACE; +} + +inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size = 0) { + auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); + + for (size_t i = 0; i < regs.size(); ++i) { + if (regs[i] && ABI_ALL_XMMS[i]) { + code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]); + frame_info.xmm_offset += 0x10; + } + } + + if (frame_info.subtraction != 0) + code.add(code.rsp, frame_info.subtraction); + + // GPRs need to be popped in reverse order + for (size_t j = 0; j < regs.size(); ++j) { + const size_t i = regs.size() - j - 1; + if (regs[i] && ABI_ALL_GPRS[i]) { + code.pop(IndexToReg64(i)); + } + } +} + +// Constants for use with cmpps/cmpss +enum { + CMP_EQ = 0, + CMP_LT = 1, + CMP_LE = 2, + CMP_UNORD = 3, + CMP_NEQ = 4, + CMP_NLT = 5, + CMP_NLE = 6, + CMP_ORD = 7, +}; + +constexpr bool IsWithin2G(uintptr_t ref, uintptr_t target) { + const u64 distance = target - (ref + 5); + return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL); +} + +inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { + return IsWithin2G(uintptr_t(code.getCurr()), target); +} + +template +inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { + static_assert(std::is_pointer_v, "Argument must be a (function) pointer."); + size_t addr = size_t(f); + if (IsWithin2G(code, addr)) { + code.call(f); + } else { + // ABI_RETURN is a safe temp register to use before a call + code.mov(ABI_RETURN, addr); + code.call(ABI_RETURN); + } +} + +} // namespace Common::X64 #endif #include "common/assert.h"