diff options
-rw-r--r-- | src/lib/netlist/plib/ppmf.h | 59 | ||||
-rw-r--r-- | src/lib/netlist/plib/ptypes.h | 84 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.h | 18 |
3 files changed, 143 insertions, 18 deletions
diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h index f83e4620861..919897df37f 100644 --- a/src/lib/netlist/plib/ppmf.h +++ b/src/lib/netlist/plib/ppmf.h @@ -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 diff --git a/src/lib/netlist/plib/ptypes.h b/src/lib/netlist/plib/ptypes.h index c40735a0f48..ef3dd724388 100644 --- a/src/lib/netlist/plib/ptypes.h +++ b/src/lib/netlist/plib/ptypes.h @@ -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; diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 20ea01e890e..8ceec3d7151 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -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 = ""); |