summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/lib/netlist/plib/ppmf.h59
-rw-r--r--src/lib/netlist/plib/ptypes.h84
-rw-r--r--src/lib/netlist/plib/putil.h18
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 = "");