mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
netlist: further optimize ppmf.h [Couriersud]
Move towards a pure c++ constexpr solution to derive the optimal pointer to member function solution. All the macro madness is centralized to a compile_info struct with static members. For the time being the evaluation result is compared against the previous approach. Going forward this will be dropped as well as the support for MINGW with GCC <= 4.6
This commit is contained in:
parent
d041e74e2c
commit
ec0f62d789
@ -33,6 +33,8 @@
|
||||
///
|
||||
|
||||
#include "pconfig.h"
|
||||
#include "ptypes.h"
|
||||
#include "putil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint> // uintptr_t
|
||||
@ -48,15 +50,18 @@
|
||||
#define PPMF_TYPE_GNUC_PMF_CONV 1
|
||||
#define PPMF_TYPE_INTERNAL 2
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// FIXME: Remove this macro madmess latest after September, 2020
|
||||
// FIXME: Do we still need to support MINGW <= 4.6?
|
||||
|
||||
#if defined(__clang__) && defined(__i386__) && defined(_WIN32)
|
||||
#define PHAS_PMF_INTERNAL 0
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
// does not work in versions over 4.7.x of 32bit MINGW
|
||||
#if defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)))
|
||||
#define PHAS_PMF_INTERNAL 0
|
||||
#elif defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__)
|
||||
#define PHAS_PMF_INTERNAL 1
|
||||
#define MEMBER_ABI _thiscall
|
||||
#elif defined(__clang__) && defined(__i386__) && defined(_WIN32)
|
||||
#define PHAS_PMF_INTERNAL 0
|
||||
#elif defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(__MIPSEL__) || defined(__mips_isa_rev) || defined(__mips64) || defined(__EMSCRIPTEN__)
|
||||
#define PHAS_PMF_INTERNAL 2
|
||||
#else
|
||||
@ -91,22 +96,40 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
|
||||
#if (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV)
|
||||
#pragma GCC diagnostic ignored "-Wpmf-conversions"
|
||||
#endif
|
||||
|
||||
namespace plib {
|
||||
|
||||
struct ppmf_internal
|
||||
{
|
||||
using ci = compile_info;
|
||||
enum { value =
|
||||
(ci::type() == ci_compiler::CLANG && !ci::m64()
|
||||
&& ci::os() == ci_os::WINDOWS) ? 0 :
|
||||
(ci::mingw() && !ci::m64() && ci::version() >= 407) ? 0 :
|
||||
(ci::mingw() && !ci::m64()) ? 1 :
|
||||
((ci::type() == ci_compiler::CLANG || ci::type() == ci_compiler::GCC)
|
||||
&& (ci::arch() == ci_arch::MIPS
|
||||
|| ci::arch() == ci_arch::ARM
|
||||
|| ci::os() == ci_os::EMSCRIPTEN)) ? 2 :
|
||||
(ci::type() == ci_compiler::CLANG || ci::type() == ci_compiler::GCC) ? 1 :
|
||||
(ci::type() == ci_compiler::MSC && ci::m64()) ? 3 :
|
||||
0
|
||||
};
|
||||
};
|
||||
|
||||
// FIXME: on supported platforms we should consider using GNU PMF extensions
|
||||
// if no internal solution exists
|
||||
|
||||
using ppmf_type = std::integral_constant<int, (ppmf_internal::value > 0 ? PPMF_TYPE_INTERNAL : PPMF_TYPE_PMF)>;
|
||||
|
||||
// check against previous implementation
|
||||
static_assert(ppmf_internal::value == PHAS_PMF_INTERNAL, "internal mismatch");
|
||||
static_assert(ppmf_type::value == PPMF_TYPE, "type mismatch");
|
||||
|
||||
///
|
||||
/// \brief Used to derive a pointer to a member function.
|
||||
///
|
||||
@ -137,7 +160,7 @@ namespace plib {
|
||||
{
|
||||
// apply the "this" delta to the object first
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
|
||||
auto *o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
|
||||
generic_class *o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
|
||||
|
||||
// if the low bit of the vtable index is clear, then it is just a raw function pointer
|
||||
if ((m_function & 1) == 0)
|
||||
@ -335,7 +358,8 @@ namespace plib {
|
||||
static_assert(sizeof(m_resolved) >= sizeof(r.first), "size mismatch 1");
|
||||
static_assert(sizeof(m_resolved) >= sizeof(member_abi_function<O>), "size mismatch 2");
|
||||
|
||||
*reinterpret_cast<member_abi_function<O> *>(&m_resolved) = r.first;
|
||||
//*reinterpret_cast<member_abi_function<O> *>(&m_resolved) = r.first;
|
||||
reinterpret_copy(r.first, m_resolved);
|
||||
m_obj = reinterpret_cast<generic_class *>(r.second);
|
||||
}
|
||||
|
||||
@ -357,8 +381,7 @@ namespace plib {
|
||||
};
|
||||
|
||||
template<typename R, typename... Targs>
|
||||
using pmfp = pmfp_base<PPMF_TYPE, PHAS_PMF_INTERNAL, R, Targs...>;
|
||||
|
||||
using pmfp = pmfp_base<ppmf_type::value, ppmf_internal::value, R, Targs...>;
|
||||
|
||||
///
|
||||
/// \brief Class to support delegate late binding
|
||||
@ -423,7 +446,7 @@ namespace plib {
|
||||
|
||||
} // namespace plib
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
@ -40,9 +40,40 @@ namespace plib
|
||||
//============================================================
|
||||
|
||||
/// \brief Dummy 128 bit types for platforms which don't support 128 bit
|
||||
///
|
||||
/// Users should always consult compile_info::has_int128 prior to
|
||||
/// using the UINT128/INT128 data type.
|
||||
///
|
||||
struct UINT128_DUMMY {};
|
||||
struct INT128_DUMMY {};
|
||||
|
||||
enum class ci_compiler
|
||||
{
|
||||
UNKNOWN,
|
||||
CLANG,
|
||||
GCC,
|
||||
MSC
|
||||
};
|
||||
|
||||
enum class ci_os
|
||||
{
|
||||
UNKNOWN,
|
||||
LINUX,
|
||||
FREEBSD,
|
||||
OPENBSD,
|
||||
WINDOWS,
|
||||
MACOSX,
|
||||
EMSCRIPTEN
|
||||
};
|
||||
|
||||
enum class ci_arch
|
||||
{
|
||||
UNKNOWN,
|
||||
X86,
|
||||
ARM,
|
||||
MIPS
|
||||
};
|
||||
|
||||
struct compile_info
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@ -69,7 +100,60 @@ namespace plib
|
||||
static constexpr int128_type int128_max() { return int128_type(); }
|
||||
static constexpr uint128_type uint128_max() { return uint128_type(); }
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
using type = std::integral_constant<ci_compiler, ci_compiler::CLANG>;
|
||||
using version = std::integral_constant<int, (__clang_major__) * 100 + (__clang_minor__)>;
|
||||
#elif defined(__GNUC__)
|
||||
using type = std::integral_constant<ci_compiler, ci_compiler::GCC>;
|
||||
using version = std::integral_constant<int, (__GNUC__) * 100 + (__GNUC_MINOR__)>;
|
||||
#elif defined(_MSC_VER)
|
||||
using type = std::integral_constant<ci_compiler, ci_compiler::MSC>;
|
||||
using version = std::integral_constant<int, _MSC_VER>;
|
||||
#else
|
||||
using type = std::integral_constant<ci_compiler, ci_compiler::UNKNOWN>;
|
||||
using version = std::integral_constant<int, 0>;
|
||||
#endif
|
||||
#ifdef __unix__
|
||||
using is_unix = std::integral_constant<bool, true>;
|
||||
#else
|
||||
using is_unix = std::integral_constant<bool, false>;
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
using os = std::integral_constant<ci_os, ci_os::LINUX>;
|
||||
#elif defined(__FreeBSD__)
|
||||
using os = std::integral_constant<ci_os, ci_os::FREEBSD>;
|
||||
#elif defined(__OpenBSD__)
|
||||
using os = std::integral_constant<ci_os, ci_os::OPENBSD>;
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
using os = std::integral_constant<ci_os, ci_os::EMSCRIPTEN>;
|
||||
#elif defined(_WIN32)
|
||||
using os = std::integral_constant<ci_os, ci_os::WINDOWS>;
|
||||
#elif defined(__APPLE__)
|
||||
using os = std::integral_constant<ci_os, ci_os::MACOSX>;
|
||||
#else
|
||||
using os = std::integral_constant<ci_os, ci_os::UNKNOWN>;
|
||||
#endif
|
||||
#if defined(__x86_64__) || defined (_M_X64) || defined(__aarch64__) || defined(__mips64) || defined(_M_AMD64) || defined(_M_ARM64)
|
||||
using m64 = std::integral_constant<bool, true>;
|
||||
#else
|
||||
using m64 = std::integral_constant<bool, false>;
|
||||
#endif
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
using arch = std::integral_constant<ci_arch, ci_arch::X86>;
|
||||
#elif defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(_M_ARM)
|
||||
using arch = std::integral_constant<ci_arch, ci_arch::ARM>;
|
||||
#elif defined(__MIPSEL__) || defined(__mips_isa_rev) || defined(__mips64)
|
||||
using arch = std::integral_constant<ci_arch, ci_arch::MIPS>;
|
||||
#else
|
||||
using arch = std::integral_constant<ci_arch, ci_arch::UNKNOWN>;
|
||||
#endif
|
||||
#if defined(__MINGW32__)
|
||||
using mingw = std::integral_constant<bool, true>;
|
||||
#else
|
||||
using mingw = std::integral_constant<bool, false>;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace plib
|
||||
|
||||
using INT128 = plib::compile_info::int128_type;
|
||||
|
@ -249,6 +249,24 @@ namespace plib
|
||||
list_t m_collection;
|
||||
};
|
||||
|
||||
/// \brief copy type S to type D byte by byte
|
||||
///
|
||||
/// The purpose of this copy function is to suppress compiler warnings.
|
||||
/// Use at your own risk. This is dangerous.
|
||||
///
|
||||
/// \param s Source object
|
||||
/// \param d Destination object
|
||||
/// \tparam S Type of source object
|
||||
/// \tparam D Type of destination object
|
||||
template <typename S, typename D>
|
||||
void reinterpret_copy(S &s, D &d)
|
||||
{
|
||||
static_assert(sizeof(D) >= sizeof(S), "size mismatch");
|
||||
auto *dp = reinterpret_cast<std::uint8_t *>(&d);
|
||||
const auto *sp = reinterpret_cast<std::uint8_t *>(&s);
|
||||
std::copy(sp, sp + sizeof(S), dp);
|
||||
}
|
||||
|
||||
namespace util
|
||||
{
|
||||
pstring basename(const pstring &filename, const pstring &suffix = "");
|
||||
|
Loading…
Reference in New Issue
Block a user