2016-12-12 09:23:08 +00:00
|
|
|
// Copyright 2016 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2023-01-06 15:28:02 +00:00
|
|
|
#include "common/arch.h"
|
|
|
|
#if CITRA_ARCH(x86_64)
|
|
|
|
|
2016-12-12 09:23:08 +00:00
|
|
|
#include <type_traits>
|
2022-06-12 11:26:05 +00:00
|
|
|
#include <xbyak/xbyak.h>
|
2016-12-12 09:23:08 +00:00
|
|
|
#include "common/x64/xbyak_abi.h"
|
|
|
|
|
2018-08-14 22:27:27 +00:00
|
|
|
namespace Common::X64 {
|
2016-12-12 09:23:08 +00:00
|
|
|
|
|
|
|
// 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,
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
|
|
|
|
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<uintptr_t>(code.getCurr()), target);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
|
2018-08-07 17:31:57 +00:00
|
|
|
static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
|
2018-09-06 20:03:28 +00:00
|
|
|
std::size_t addr = reinterpret_cast<std::size_t>(f);
|
2016-12-12 09:23:08 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-14 22:27:27 +00:00
|
|
|
} // namespace Common::X64
|
2023-01-06 15:28:02 +00:00
|
|
|
|
|
|
|
#endif // CITRA_ARCH(x86_64)
|