From e949e9c29de82ee7c32692e7b65da05dd22bdc9d Mon Sep 17 00:00:00 2001 From: couriersud Date: Sat, 13 Jun 2020 15:49:35 +0200 Subject: netlist: Performance improvement and refactoring. [Couriersud] Kidniki now achieves up to 910% when run with static solvers and with nltool. That is significant better than the 860% we have seen previously. This increase is driven by using a global memory pool in the solver code. In addition the following refactoring and code maintenance work is included. Please excuse the large commit, some of this took interfered with other work and the detail development steps were ugly. - gsl support: This commit adds pgsl.h which implements a very limited number of the functionality of the gsl header described in the c++ core guidelines. - clang-tidy fixes - A significant refactoring of palloc.h. Aligned hints were removed, they added complexity without a significant performance gain. Vector operations should better be done on special spans/views. The code has been tested on linux with g++-7, g++-9, clang-11. On Windows mingw-10 and VS2019, OSX clang-11. --- scripts/src/netlist.lua | 1 + src/devices/machine/netlist.cpp | 9 +- src/lib/netlist/analog/nld_mosfet.cpp | 4 +- src/lib/netlist/analog/nld_opamps.cpp | 2 +- src/lib/netlist/analog/nlid_twoterm.h | 8 +- src/lib/netlist/build/makefile | 31 +- src/lib/netlist/devices/nlid_proxy.cpp | 13 +- src/lib/netlist/devices/nlid_system.h | 2 +- src/lib/netlist/devices/nlid_truthtable.cpp | 10 +- src/lib/netlist/nl_base.cpp | 24 +- src/lib/netlist/nl_base.h | 29 +- src/lib/netlist/nl_config.h | 6 + src/lib/netlist/nl_factory.cpp | 2 +- src/lib/netlist/nl_factory.h | 6 +- src/lib/netlist/nl_parser.cpp | 6 +- src/lib/netlist/nl_setup.cpp | 34 +- src/lib/netlist/nl_setup.h | 4 +- src/lib/netlist/nltypes.h | 4 +- src/lib/netlist/plib/gmres.h | 26 +- src/lib/netlist/plib/mat_cr.h | 12 +- src/lib/netlist/plib/palloc.h | 424 ++++++++++++++----------- src/lib/netlist/plib/parray.h | 39 +-- src/lib/netlist/plib/pchrono.h | 7 +- src/lib/netlist/plib/pconfig.h | 17 +- src/lib/netlist/plib/pdynlib.h | 1 + src/lib/netlist/plib/penum.h | 4 +- src/lib/netlist/plib/pexception.cpp | 2 +- src/lib/netlist/plib/pfmtlog.cpp | 4 +- src/lib/netlist/plib/pfmtlog.h | 6 +- src/lib/netlist/plib/pfunction.cpp | 50 +-- src/lib/netlist/plib/pgsl.h | 105 ++++++ src/lib/netlist/plib/plists.h | 8 + src/lib/netlist/plib/pmain.cpp | 8 +- src/lib/netlist/plib/pmath.h | 4 +- src/lib/netlist/plib/pmatrix2d.h | 93 ++++-- src/lib/netlist/plib/pmempool.h | 65 ++-- src/lib/netlist/plib/poptions.cpp | 17 +- src/lib/netlist/plib/poptions.h | 2 +- src/lib/netlist/plib/ppmf.h | 33 +- src/lib/netlist/plib/ppreprocessor.cpp | 6 +- src/lib/netlist/plib/ppreprocessor.h | 4 +- src/lib/netlist/plib/prandom.h | 11 +- src/lib/netlist/plib/pstonum.h | 13 +- src/lib/netlist/plib/pstream.h | 8 +- src/lib/netlist/plib/pstring.cpp | 6 +- src/lib/netlist/plib/pstrutil.h | 7 +- src/lib/netlist/plib/ptimed_queue.h | 2 +- src/lib/netlist/plib/ptypes.h | 6 +- src/lib/netlist/plib/putil.cpp | 20 +- src/lib/netlist/plib/putil.h | 10 +- src/lib/netlist/prg/nltool.cpp | 30 +- src/lib/netlist/prg/nlwav.cpp | 12 +- src/lib/netlist/solver/nld_matrix_solver.cpp | 22 +- src/lib/netlist/solver/nld_matrix_solver.h | 322 ++----------------- src/lib/netlist/solver/nld_matrix_solver_ext.h | 288 +++++++++++++++++ src/lib/netlist/solver/nld_ms_direct.h | 4 +- src/lib/netlist/solver/nld_ms_direct1.h | 1 + src/lib/netlist/solver/nld_ms_direct2.h | 1 + src/lib/netlist/solver/nld_ms_gcr.h | 15 +- src/lib/netlist/solver/nld_ms_gmres.h | 1 + src/lib/netlist/solver/nld_ms_sm.h | 1 + src/lib/netlist/solver/nld_ms_sor.h | 19 +- src/lib/netlist/solver/nld_ms_sor_mat.h | 3 +- src/lib/netlist/solver/nld_ms_w.h | 3 +- src/lib/netlist/solver/nld_solver.cpp | 31 +- src/lib/netlist/solver/nld_solver.h | 2 +- src/lib/netlist/tools/nl_convert.cpp | 15 +- 67 files changed, 1126 insertions(+), 859 deletions(-) create mode 100644 src/lib/netlist/plib/pgsl.h mode change 100644 => 100755 src/lib/netlist/plib/pmatrix2d.h create mode 100644 src/lib/netlist/solver/nld_matrix_solver_ext.h diff --git a/scripts/src/netlist.lua b/scripts/src/netlist.lua index b260e8e3dec..a2a309d4a18 100644 --- a/scripts/src/netlist.lua +++ b/scripts/src/netlist.lua @@ -53,6 +53,7 @@ project "netlist" MAME_DIR .. "src/lib/netlist/plib/pconfig.h", MAME_DIR .. "src/lib/netlist/plib/palloc.h", MAME_DIR .. "src/lib/netlist/plib/pchrono.h", + MAME_DIR .. "src/lib/netlist/plib/pgsl.h", MAME_DIR .. "src/lib/netlist/plib/penum.h", MAME_DIR .. "src/lib/netlist/plib/pexception.cpp", MAME_DIR .. "src/lib/netlist/plib/pexception.h", diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp index a47d453762d..1dd17acd8b1 100644 --- a/src/devices/machine/netlist.cpp +++ b/src/devices/machine/netlist.cpp @@ -127,7 +127,7 @@ protected: netlist::host_arena::unique_ptr static_solver_lib() const noexcept override { //return plib::make_unique(nullptr); - return netlist::host_arena::make_unique(nl_static_solver_syms); + return plib::make_unique(nl_static_solver_syms); } private: @@ -169,7 +169,7 @@ protected: netlist::host_arena::unique_ptr static_solver_lib() const noexcept override { - return netlist::host_arena::make_unique(nullptr); + return plib::make_unique(nullptr); } private: @@ -181,7 +181,7 @@ class netlist_mame_device::netlist_mame_t : public netlist::netlist_state_t public: netlist_mame_t(netlist_mame_device &parent, const pstring &name) - : netlist::netlist_state_t(name, netlist::host_arena::make_unique(parent)) + : netlist::netlist_state_t(name, plib::make_unique(parent)) , m_parent(parent) { } @@ -978,7 +978,8 @@ netlist::host_arena::unique_ptr netlist_mame_device::b { try { - auto lnetlist = netlist::host_arena::make_unique("netlist", netlist::host_arena::make_unique()); + auto lnetlist = plib::make_unique("netlist", + plib::make_unique()); // enable validation mode lnetlist->set_extended_validation(true); common_dev_start(lnetlist.get()); diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp index b285f099adb..846ba8f3ba1 100644 --- a/src/lib/netlist/analog/nld_mosfet.cpp +++ b/src/lib/netlist/analog/nld_mosfet.cpp @@ -415,8 +415,8 @@ namespace analog else { // linear - const auto Sqr1(static_cast(plib::pow(Vdsat - Vds, 2))); - const auto Sqr2(static_cast(plib::pow(nlconst::two() * Vdsat - Vds, 2))); + const auto Sqr1(plib::narrow_cast(plib::pow(Vdsat - Vds, 2))); + const auto Sqr2(plib::narrow_cast(plib::pow(nlconst::two() * Vdsat - Vds, 2))); Cgb = 0; Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2) * nlconst::two_thirds(); Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2) * nlconst::two_thirds(); diff --git a/src/lib/netlist/analog/nld_opamps.cpp b/src/lib/netlist/analog/nld_opamps.cpp index 1890ba85826..7b5db6b2fb6 100644 --- a/src/lib/netlist/analog/nld_opamps.cpp +++ b/src/lib/netlist/analog/nld_opamps.cpp @@ -115,7 +115,7 @@ namespace netlist , m_VL(*this, "VL") , m_VREF(*this, "VREF") { - m_type = static_cast(m_modacc.m_TYPE); + m_type = plib::narrow_cast(m_modacc.m_TYPE); if (m_type < 1 || m_type > 3) { log().fatal(MF_OPAMP_UNKNOWN_TYPE(m_type)); diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h index 87411ee8109..de2a69a23f7 100644 --- a/src/lib/netlist/analog/nlid_twoterm.h +++ b/src/lib/netlist/analog/nlid_twoterm.h @@ -561,11 +561,11 @@ namespace analog { register_subalias("P", P()); register_subalias("N", N()); - if (m_func() != "") + if (!m_func().empty()) m_compiled->compile(m_func(), std::vector({{pstring("T")}})); } - NETLIB_IS_TIMESTEP(m_func() != "") + NETLIB_IS_TIMESTEP(!m_func().empty()) NETLIB_TIMESTEPI() { @@ -609,11 +609,11 @@ namespace analog { register_subalias("P", P()); register_subalias("N", N()); - if (m_func() != "") + if (!m_func().empty()) m_compiled->compile(m_func(), std::vector({{pstring("T")}})); } - NETLIB_IS_TIMESTEP(m_func() != "") + NETLIB_IS_TIMESTEP(!m_func().empty()) NETLIB_TIMESTEPI() { m_t += step; diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile index 5f5352d0c69..1d442953fb6 100644 --- a/src/lib/netlist/build/makefile +++ b/src/lib/netlist/build/makefile @@ -25,11 +25,13 @@ VSBUILD = $(SRC)/buildVS DOC = $(SRC)/documentation TIDY_FLAGSX = -checks=*,-google*,-hicpp*,readability*,-fuchsia*,cert-*,-android-*, -TIDY_FLAGSX += -llvm-header-guard,-cppcoreguidelines-pro-type-reinterpret-cast, +TIDY_FLAGSX += -llvm-header-guard, +# TIDY_FLAGSX += -cppcoreguidelines-pro-type-reinterpret-cast, TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-pointer-arithmetic, #TIDY_FLAGSX += -cppcoreguidelines-owning-memory, TIDY_FLAGSX += -modernize-use-default-member-init,-cppcoreguidelines-pro-bounds-constant-array-index, -TIDY_FLAGSX += -modernize-pass-by-value,-cppcoreguidelines-pro-type-static-cast-downcast, +TIDY_FLAGSX += -modernize-pass-by-value, +#TIDY_FLAGSX += -cppcoreguidelines-pro-type-static-cast-downcast, TIDY_FLAGSX += -cppcoreguidelines-avoid-magic-numbers, TIDY_FLAGSX += -cppcoreguidelines-macro-usage, TIDY_FLAGSX += -cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes, @@ -37,7 +39,7 @@ TIDY_FLAGSX += -bugprone-macro-parentheses, #TIDY_FLAGSX += -misc-macro-parentheses, TIDY_FLAGSX += -bugprone-too-small-loop-variable, TIDY_FLAGSX += -modernize-use-trailing-return-type, -TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-array-to-pointer-decay, +#TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-array-to-pointer-decay, TIDY_FLAGSX += -readability-magic-numbers,-readability-braces-around-statements, TIDY_FLAGSX += -readability-implicit-bool-conversion, TIDY_FLAGSX += -readability-named-parameter,-readability-function-size, @@ -85,7 +87,7 @@ CC = g++ LD = @g++ MD = @mkdir RM = @rm -CLANG_TIDY = clang-tidy-10 +CLANG_TIDY = clang-tidy-11 DEPENDCC=$(CC) @@ -132,6 +134,8 @@ POBJS := \ PMAIN := $(POBJ)/pmain.o NLOBJS := \ + $(NLOBJ)/solver/nld_solver.o \ + $(NLOBJ)/solver/nld_matrix_solver.o \ $(NLOBJ)/nl_base.o \ $(NLOBJ)/nl_parser.o \ $(NLOBJ)/nl_setup.o \ @@ -142,8 +146,6 @@ NLOBJS := \ $(NLOBJ)/analog/nld_switches.o \ $(NLOBJ)/analog/nlid_twoterm.o \ $(NLOBJ)/analog/nld_opamps.o \ - $(NLOBJ)/solver/nld_solver.o \ - $(NLOBJ)/solver/nld_matrix_solver.o \ $(NLOBJ)/tools/nl_convert.o \ $(NLOBJ)/generated/static_solvers.o \ $(NLOBJ)/devices/nld_2102A.o \ @@ -287,27 +289,32 @@ native: $(MAKE) CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra " gcc9: - $(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -fext-numeric-literals -Wall -pedantic -Wpedantic -Wsign-compare -Wextra" EXTRALIBS="-lquadmath" + $(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -Wall -pedantic -Wpedantic -fext-numeric-literals -Wsign-compare -Wextra" EXTRALIBS="-lquadmath" clang: #$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native -msse4.2 -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field -Wno-padded -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors" $(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native \ -mllvm -inline-threshold=2000 \ + -Wunknown-warning-option \ -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field \ -Werror -Wno-padded -Wno-weak-vtables -Wno-weak-template-vtables -Wno-unused-template \ - -Wno-missing-variable-declarations -Wno-float-equal -Wconversion \ + -Wmissing-variable-declarations -Wno-float-equal -Wconversion \ -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral \ - -Wno-exit-time-destructors -Winconsistent-missing-destructor-override" + -Wno-exit-time-destructors -Winconsistent-missing-destructor-override \ + -Wno-return-std-move-in-c++11 -Wno-unreachable-code" clang-libc: + #clang-11 currently broken #$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native -msse4.2 -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field -Wno-padded -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors" - $(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang-libc CEXTRAFLAGS="-march=native \ + $(MAKE) CC=clang++-10 LD=clang++-10 OBJ=obj/clang-libc CEXTRAFLAGS="-march=native \ -stdlib=libc++ -mllvm -inline-threshold=2000 \ + -Wunknown-warning-option \ -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field \ -Werror -Wno-padded -Wno-weak-vtables -Wno-weak-template-vtables -Wno-unused-template \ - -Wno-missing-variable-declarations -Wno-float-equal -Wconversion \ + -Wmissing-variable-declarations -Wno-float-equal -Wconversion \ -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral \ - -Wno-exit-time-destructors -Winconsistent-missing-destructor-override" \ + -Wno-exit-time-destructors -Winconsistent-missing-destructor-override \ + -Wno-return-std-move-in-c++11 -Wno-unreachable-code" LDEXTRAFLAGS=-stdlib=libc++ clang-5: diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp index d804988c6fd..585637fb5f9 100644 --- a/src/lib/netlist/devices/nlid_proxy.cpp +++ b/src/lib/netlist/devices/nlid_proxy.cpp @@ -9,6 +9,8 @@ #include "nl_errstr.h" #include "solver/nld_solver.h" +#include + namespace netlist { namespace devices @@ -18,6 +20,8 @@ namespace netlist // nld_base_proxy // ----------------------------------------------------------------------------- + static const std::array, 3> power_syms = {{ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}}; + nld_base_proxy::nld_base_proxy(netlist_state_t &anetlist, const pstring &name, const logic_t *inout_proxied) : device_t(anetlist, name, inout_proxied->logic_family()) @@ -29,16 +33,15 @@ namespace netlist throw nl_exception(MF_NULLPTR_FAMILY_NP("nld_base_proxy")); } - const std::vector> power_syms = { {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}; bool f = false; for (const auto & pwr_sym : power_syms) { pstring devname = inout_proxied->device().name(); - auto *tp_ct(anetlist.setup().find_terminal(devname + "." + pwr_sym.first, + auto *tp_ct(anetlist.setup().find_terminal(devname + "." + pstring(pwr_sym.first), /*detail::terminal_type::INPUT,*/ false)); - auto *tp_cn(anetlist.setup().find_terminal(devname + "." + pwr_sym.second, + auto *tp_cn(anetlist.setup().find_terminal(devname + "." + pstring(pwr_sym.second), /*detail::terminal_type::INPUT,*/ false)); if ((tp_ct != nullptr) && (tp_cn != nullptr)) { @@ -47,8 +50,8 @@ namespace netlist if (!tp_cn->is_analog()) throw nl_exception(plib::pfmt("Not an analog terminal: {1}")(tp_cn->name())); - auto *tp_t = static_cast(tp_ct); - auto *tn_t = static_cast(tp_cn); + auto *tp_t = dynamic_cast(tp_ct); + auto *tn_t = dynamic_cast(tp_cn); if (f && (tp_t != nullptr && tn_t != nullptr)) log().warning(MI_MULTIPLE_POWER_TERMINALS_ON_DEVICE(inout_proxied->device().name(), m_tp->name(), m_tn->name(), diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index fc1bfefd84b..31a31c62d88 100644 --- a/src/lib/netlist/devices/nlid_system.h +++ b/src/lib/netlist/devices/nlid_system.h @@ -93,7 +93,7 @@ namespace devices , m_compiled(*this, "m_compiled") , m_funcparam({nlconst::zero()}) { - if (m_func() != "") + if (!m_func().empty()) m_compiled->compile(m_func(), std::vector({{pstring("T")}})); connect(m_feedback, m_Q); } diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp index 1718f53560d..a1bcc26d035 100644 --- a/src/lib/netlist/devices/nlid_truthtable.cpp +++ b/src/lib/netlist/devices/nlid_truthtable.cpp @@ -440,7 +440,7 @@ namespace devices if (!m_ttbl) { - m_ttbl = pool.make_unique::truthtable_t>(); + m_ttbl = plib::make_unique::truthtable_t>(pool); truthtable_parser desc_s(m_NO, m_NI, packed_int(m_ttbl->m_out_state.data(), sizeof(m_ttbl->m_out_state[0]) * 8), m_ttbl->m_timing_index.data(), m_ttbl->m_timing_nt.data()); @@ -448,7 +448,7 @@ namespace devices desc_s.parse(m_desc); } - return pool.make_unique(anetlist, name, m_family_name, *m_ttbl, m_desc); + return plib::make_unique(pool, anetlist, name, m_family_name, *m_ttbl, m_desc); } private: device_arena::unique_ptr::truthtable_t> m_ttbl; @@ -578,7 +578,7 @@ void truthtable_parser::parse(const std::vector &truthtable) for (int j=0; j < 16; j++) m_timing_nt[j] = netlist_time::zero(); - while (!(ttline == "")) + while (!ttline.empty()) { std::vector io(plib::psplit(ttline,"|")); // checks @@ -670,7 +670,7 @@ namespace factory #define ENTRYY(n, m, s) case (n * 100 + m): \ { using xtype = devices::netlist_factory_truthtable_t; \ auto cs=s; \ - ret = host_arena::make_unique(desc.name, std::move(cs)); } \ + ret = plib::make_unique(desc.name, std::move(cs)); } \ break #define ENTRY(n, s) ENTRYY(n, 1, s); ENTRYY(n, 2, s); ENTRYY(n, 3, s); \ @@ -700,7 +700,7 @@ namespace factory nl_assert_always(false, msg.c_str()); } ret->m_desc = desc.desc; - ret->m_family_name = (desc.family != "" ? desc.family : pstring(config::DEFAULT_LOGIC_FAMILY())); + ret->m_family_name = (!desc.family.empty() ? desc.family : pstring(config::DEFAULT_LOGIC_FAMILY())); return ret; } diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 42104458f7a..a9ac57f620d 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -27,7 +27,7 @@ namespace netlist host_arena::unique_ptr callbacks_t:: static_solver_lib() const { - return host_arena::make_unique(nullptr); + return plib::make_unique(nullptr); } // ---------------------------------------------------------------------------------------- @@ -129,9 +129,9 @@ namespace netlist m_lib = m_callbacks->static_solver_lib(); - m_setup = host_arena::make_unique(*this); + m_setup = plib::make_unique(*this); // create the run interface - m_netlist = m_pool.make_unique(*this, name); + m_netlist = plib::make_unique(m_pool, *this, name); // Make sure save states are invalidated when a new version is deployed @@ -313,7 +313,7 @@ namespace netlist case 0: { std::vector d; - std::vector t; + std::vector t; log().verbose("Using default startup strategy"); for (auto &n : m_nets) for (auto & term : n->core_terms()) @@ -402,7 +402,7 @@ namespace netlist } log().verbose("Total calls : {1:12} {2:12} {3:12}", total_count, - total_time, total_time / static_cast((total_count > 0) ? total_count : 1)); + total_time, total_time / gsl::narrow((total_count > 0) ? total_count : 1)); log().verbose("Total loop {1:15}", si.m_stat_mainloop()); log().verbose("Total time {1:15}", total_time); @@ -424,8 +424,8 @@ namespace netlist } plib::pperftime_t::type total_overhead = overhead() - * static_cast::type>(total_count) - / static_cast::type>(200000); + * gsl::narrow::type>(total_count) + / gsl::narrow::type>(200000); log().verbose("Queue Pushes {1:15}", si.m_queue.m_prof_call()); log().verbose("Queue Moves {1:15}", si.m_queue.m_prof_sortmove()); @@ -436,7 +436,7 @@ namespace netlist log().verbose("Take the next lines with a grain of salt. They depend on the measurement implementation."); log().verbose("Total overhead {1:15}", total_overhead); plib::pperftime_t::type overhead_per_pop = (si.m_stat_mainloop()-2*total_overhead - (total_time - total_overhead)) - / static_cast::type>(si.m_queue.m_prof_call()); + / gsl::narrow::type>(si.m_queue.m_prof_call()); log().verbose("Overhead per pop {1:11}", overhead_per_pop ); log().verbose(""); } @@ -450,7 +450,7 @@ namespace netlist if (stats->m_stat_inc_active() > 3 * stats->m_stat_total_time.count() && stats->m_stat_inc_active() > trigger) log().verbose("HINT({}, NO_DEACTIVATE) // {} {} {}", ep->name(), - static_cast(stats->m_stat_inc_active()) / static_cast(stats->m_stat_total_time.count()), + gsl::narrow(stats->m_stat_inc_active()) / gsl::narrow(stats->m_stat_total_time.count()), stats->m_stat_inc_active(), stats->m_stat_total_time.count()); } log().verbose(""); @@ -856,14 +856,14 @@ namespace netlist pstring param_t::get_initial(const core_device_t *dev, bool *found) const { pstring res = dev->state().setup().get_initial_param_val(this->name(), ""); - *found = (res != ""); + *found = (!res.empty()); return res; } param_str_t::param_str_t(core_device_t &device, const pstring &name, const pstring &val) : param_t(device, name) { - m_param = host_arena::make_unique(val); + m_param = plib::make_unique(val); *m_param = device.state().setup().get_initial_param_val(this->name(),val); } @@ -871,7 +871,7 @@ namespace netlist : param_t(name) { // deviceless parameter, no registration, owner is responsible - m_param = host_arena::make_unique(val); + m_param = plib::make_unique(val); *m_param = state.setup().get_initial_param_val(this->name(),val); } diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 7597989d71b..97e3f404a36 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -708,9 +708,8 @@ namespace netlist #endif void set_delegate(const nldelegate &delegate) noexcept { m_delegate = delegate; } - nldelegate &delegate() noexcept { return m_delegate; } const nldelegate &delegate() const noexcept { return m_delegate; } - inline void run_delegate() noexcept { m_delegate(); } + inline void run_delegate() noexcept { return m_delegate(); } private: nldelegate m_delegate; net_t * m_net; @@ -997,7 +996,7 @@ namespace netlist { public: - using list_t = std::vector; + using list_t = plib::aligned_vector; analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *railterminal = nullptr); @@ -1209,7 +1208,7 @@ namespace netlist pstring valstr() const override { - return plib::pfmt("{}").e(static_cast(m_param)); + return plib::pfmt("{}").e(gsl::narrow(m_param)); } private: @@ -1309,7 +1308,7 @@ namespace netlist public: template ::value>> value_base_t(P ¶m, const pstring &name) - : m_value(static_cast(param.value(name))) + : m_value(gsl::narrow(param.value(name))) { } template ::value, int> = 0> @@ -1513,7 +1512,8 @@ namespace netlist ~device_t() noexcept override = default; - nldelegate default_delegate() { return nldelegate(&device_t::update, this); } + //nldelegate default_delegate() { return nldelegate(&device_t::update, this); } + nldelegate default_delegate() { return { &device_t::update, this }; } protected: NETLIB_UPDATEI() { } @@ -1757,7 +1757,7 @@ namespace netlist template device_arena::unique_ptr make_pool_object(Args&&... args) { - return m_pool.make_unique(std::forward(args)...); + return plib::make_unique(m_pool, std::forward(args)...); } // memory pool - still needed in some places device_arena &pool() noexcept { return m_pool; } @@ -2302,6 +2302,7 @@ namespace netlist inline void detail::net_t::remove_from_active_list(core_terminal_t &term) noexcept { + gsl_Expects(!m_list_active.empty()); m_list_active.remove(&term); if (m_list_active.empty()) railterminal().device().do_dec_active(); @@ -2309,24 +2310,24 @@ namespace netlist inline const analog_net_t & analog_t::net() const noexcept { - return static_cast(core_terminal_t::net()); + return plib::downcast(core_terminal_t::net()); } inline analog_net_t & analog_t::net() noexcept { - return static_cast(core_terminal_t::net()); + return plib::downcast(core_terminal_t::net()); } inline nl_fptype terminal_t::operator ()() const noexcept { return net().Q_Analog(); } inline logic_net_t & logic_t::net() noexcept { - return static_cast(core_terminal_t::net()); + return plib::downcast(core_terminal_t::net()); } inline const logic_net_t & logic_t::net() const noexcept { - return static_cast(core_terminal_t::net()); + return plib::downcast(core_terminal_t::net()); } inline netlist_sig_t logic_input_t::operator()() const noexcept @@ -2516,7 +2517,7 @@ namespace netlist if (plib::is_integral::value) if (plib::abs(valx - plib::trunc(valx)) > nlconst::magic(1e-6)) throw nl_exception(MF_INVALID_NUMBER_CONVERSION_1_2(device.name() + "." + name, p)); - m_param = static_cast(valx); + m_param = plib::narrow_cast(valx); } device.state().save(*this, m_param, this->name(), "m_param"); @@ -2599,7 +2600,7 @@ namespace netlist state_container::state_container(O &owner, const pstring &name, const state_container::value_type & value) { - owner.state().save(owner, *static_cast(this), owner.name(), name); + owner.state().save(owner, static_cast(*this), owner.name(), name); for (std::size_t i=0; i < this->size(); i++) (*this)[i] = value; } @@ -2610,7 +2611,7 @@ namespace netlist std::size_t n, const state_container::value_type & value) : C(n, value) { - owner.state().save(owner, *static_cast(this), owner.name(), name); + owner.state().save(owner, static_cast(*this), owner.name(), name); } extern template struct state_var; diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index 8740b5ddbd9..81e0c860aa9 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -200,6 +200,12 @@ namespace netlist /// using MAX_QUEUE_SIZE = std::integral_constant; // NOLINT + using use_float_matrix = std::integral_constant; + using use_long_double_matrix = std::integral_constant; + using use_float128_matrix = std::integral_constant; + + using use_mempool = std::integral_constant; + /// \brief Floating point types used /// /// nl_fptype is the floating point type used throughout the diff --git a/src/lib/netlist/nl_factory.cpp b/src/lib/netlist/nl_factory.cpp index 8ef9799101a..519c4ea029c 100644 --- a/src/lib/netlist/nl_factory.cpp +++ b/src/lib/netlist/nl_factory.cpp @@ -76,7 +76,7 @@ namespace factory { device_arena::unique_ptr library_element_t::make_device(device_arena &pool, netlist_state_t &anetlist, const pstring &name) { - return pool.make_unique(anetlist, name); + return plib::make_unique(pool, anetlist, name); } diff --git a/src/lib/netlist/nl_factory.h b/src/lib/netlist/nl_factory.h index 4c9a47cc749..5b3ee4bb3a6 100644 --- a/src/lib/netlist/nl_factory.h +++ b/src/lib/netlist/nl_factory.h @@ -129,7 +129,7 @@ namespace factory { netlist_state_t &anetlist, const pstring &name, std::tuple& args, std::index_sequence) { - return pool.make_unique(anetlist, name, std::forward(std::get(args))...); + return plib::make_unique(pool, anetlist, name, std::forward(std::get(args))...); } dev_uptr make_device(device_arena &pool, @@ -149,7 +149,7 @@ namespace factory { static uptr create(const pstring &name, properties &&props, Args&&... args) { - return host_arena::make_unique>(name, + return plib::make_unique, host_arena>(name, std::move(props), std::forward(args)...); } private: @@ -194,7 +194,7 @@ namespace factory { template element_t::uptr constructor_t(const pstring &name, properties &&props) { - return host_arena::make_unique>(name, std::move(props)); + return plib::make_unique, host_arena>(name, std::move(props)); } // ----------------------------------------------------------------------------- diff --git a/src/lib/netlist/nl_parser.cpp b/src/lib/netlist/nl_parser.cpp index 8e76538632a..e34683d5261 100644 --- a/src/lib/netlist/nl_parser.cpp +++ b/src/lib/netlist/nl_parser.cpp @@ -83,7 +83,7 @@ bool parser_t::parse(const pstring &nlname) require_token(m_tok_paren_left); token_t name = get_token(); require_token(m_tok_paren_right); - if (name.str() == nlname || nlname == "") + if (name.str() == nlname || nlname.empty()) { parse_netlist(name.str()); return true; @@ -164,8 +164,8 @@ void parser_t::net_truthtable_start(const pstring &nlname) netlist::tt_desc desc; desc.name = name; - desc.ni = static_cast(ni); - desc.no = static_cast(no); + desc.ni = gsl::narrow(ni); + desc.no = gsl::narrow(no); desc.family = ""; while (true) diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp index 1b63b002492..b6c466be6e7 100644 --- a/src/lib/netlist/nl_setup.cpp +++ b/src/lib/netlist/nl_setup.cpp @@ -200,7 +200,7 @@ namespace netlist || plib::abs(value) > nlconst::magic(1e9)) register_param(param, plib::pfmt("{1:.9}").e(value)); else - register_param(param, plib::pfmt("{1}")(static_cast(value))); + register_param(param, plib::pfmt("{1}")(gsl::narrow(value))); } void nlparse_t::register_param(const pstring ¶m, const pstring &value) @@ -248,7 +248,7 @@ namespace netlist void nlparse_t::register_lib_entry(const pstring &name, factory::properties &&props) { - m_factory.add(host_arena::make_unique(name, std::move(props))); + m_factory.add(plib::make_unique(name, std::move(props))); } void nlparse_t::register_frontier(const pstring &attach, const pstring &r_IN, @@ -508,7 +508,7 @@ pstring setup_t::resolve_alias(const pstring &name) const ret = temp; auto p = m_abstract.m_alias.find(ret); temp = (p != m_abstract.m_alias.end() ? p->second : ""); - } while (temp != "" && temp != ret); + } while (!temp.empty() && temp != ret); log().debug("{1}==>{2}\n", name, ret); return ret; @@ -532,7 +532,7 @@ pstring setup_t::de_alias(const pstring &alias) const break; } } - } while (temp != "" && temp != ret); + } while (!temp.empty() && temp != ret); log().debug("{1}==>{2}\n", alias, ret); return ret; @@ -650,7 +650,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &o { nl_assert(out.is_logic()); - const auto &out_cast = static_cast(out); + const auto &out_cast = dynamic_cast(out); auto iter_proxy(m_proxies.find(&out)); if (iter_proxy != m_proxies.end()) @@ -878,7 +878,7 @@ void setup_t::connect_terminals(detail::core_terminal_t &t1,detail::core_termina { log().debug("adding analog net ...\n"); // FIXME: Nets should have a unique name - auto anet = nlstate().pool().make_owned(m_nlstate,"net." + t1.name()); + auto anet = plib::make_owned(nlstate().pool(), m_nlstate,"net." + t1.name()); auto *anetp = anet.get(); m_nlstate.register_net(std::move(anet)); t1.set_net(anetp); @@ -1043,7 +1043,7 @@ void setup_t::resolve_inputs() detail::core_terminal_t *t1 = find_terminal(t1s); detail::core_terminal_t *t2 = find_terminal(t2s); if (connect(*t1, *t2)) - m_abstract.m_links.erase(m_abstract.m_links.begin() + static_cast(i)); + m_abstract.m_links.erase(m_abstract.m_links.begin() + plib::narrow_cast(i)); else i++; } @@ -1104,16 +1104,16 @@ void setup_t::resolve_inputs() detail::core_terminal_t *term = i.second; if (term->is_tristate_output()) { - const auto *tri(static_cast(term)); + const auto &tri(dynamic_cast(*term)); // check if we are connected to a proxy - const auto iter_proxy(m_proxies.find(tri)); + const auto iter_proxy(m_proxies.find(&tri)); - if (iter_proxy == m_proxies.end() && !tri->is_force_logic()) + if (iter_proxy == m_proxies.end() && !tri.is_force_logic()) { log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name())); err = true; } - else if (iter_proxy != m_proxies.end() && tri->is_force_logic()) + else if (iter_proxy != m_proxies.end() && tri.is_force_logic()) { log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name())); err = true; @@ -1256,7 +1256,7 @@ nl_fptype models_t::model_t::value(const pstring &entity) const pstring tmp = value_str(entity); nl_fptype factor = nlconst::one(); - auto p = std::next(tmp.begin(), static_cast(tmp.size() - 1)); + auto p = std::next(tmp.begin(), plib::narrow_cast(tmp.size() - 1)); switch (*p) { case 'M': factor = nlconst::magic(1e6); break; // NOLINT @@ -1390,7 +1390,7 @@ const logic_family_desc_t *setup_t::family_from_model(const pstring &model) if (it != m_nlstate.family_cache().end()) return it->second.get(); - auto ret = host_arena::make_unique(ft); + auto ret = plib::make_unique(ft); ret->m_low_thresh_PCNT = modv.m_IVL(); ret->m_high_thresh_PCNT = modv.m_IVH(); @@ -1434,7 +1434,7 @@ void setup_t::prepare_to_run() { pstring envlog = plib::util::environment("NL_LOGS", ""); - if (envlog != "") + if (!envlog.empty()) { std::vector loglist(plib::psplit(envlog, ":")); m_parser.register_dynamic_log_devices(loglist); @@ -1444,7 +1444,7 @@ void setup_t::prepare_to_run() for (auto & e : m_abstract.m_defparams) { - auto param(host_arena::make_unique(nlstate(), e.first, e.second)); + auto param(plib::make_unique(nlstate(), e.first, e.second)); register_param_t(*param); m_defparam_lifetime.push_back(std::move(param)); } @@ -1597,7 +1597,7 @@ source_string_t::stream_ptr source_string_t::stream(const pstring &name) plib::unused_var(name); auto ret(std::make_unique(m_str)); ret->imbue(std::locale::classic()); - return std::move(ret); // FIXME: for c++11 clang builds + return ret; } source_mem_t::stream_ptr source_mem_t::stream(const pstring &name) @@ -1605,7 +1605,7 @@ source_mem_t::stream_ptr source_mem_t::stream(const pstring &name) plib::unused_var(name); auto ret(std::make_unique(m_str, std::ios_base::binary)); ret->imbue(std::locale::classic()); - return std::move(ret); // FIXME: for c++11 clang builds + return ret; } source_file_t::stream_ptr source_file_t::stream(const pstring &name) diff --git a/src/lib/netlist/nl_setup.h b/src/lib/netlist/nl_setup.h index 9e6714007f0..6d99f1ca183 100644 --- a/src/lib/netlist/nl_setup.h +++ b/src/lib/netlist/nl_setup.h @@ -307,10 +307,10 @@ namespace netlist void register_param(const pstring ¶m, nl_fptype value); template - std::enable_if_t::value || plib::is_integral::value> + std::enable_if_t::value> register_param_val(const pstring ¶m, T value) { - register_param(param, static_cast(value)); + register_param(param, plib::narrow_cast(value)); } void register_lib_entry(const pstring &name, factory::properties &&props); diff --git a/src/lib/netlist/nltypes.h b/src/lib/netlist/nltypes.h index 17912a41d13..98bfbb49a92 100644 --- a/src/lib/netlist/nltypes.h +++ b/src/lib/netlist/nltypes.h @@ -78,9 +78,9 @@ namespace netlist /// \note This is not the right location yet. /// - using device_arena = std::conditional, - plib::aligned_arena>::type; + plib::aligned_arena>; using host_arena = plib::aligned_arena; /// \brief Interface definition for netlist callbacks into calling code diff --git a/src/lib/netlist/plib/gmres.h b/src/lib/netlist/plib/gmres.h index c8ea1cad2f8..df0fc787c52 100644 --- a/src/lib/netlist/plib/gmres.h +++ b/src/lib/netlist/plib/gmres.h @@ -38,9 +38,9 @@ namespace plib mat_precondition_ILU(std::size_t size, std::size_t ilu_scale = 4 , std::size_t bw = plib::pmatrix_cr_t::FILL_INFINITY) - : m_mat(static_cast(size)) - , m_LU(static_cast(size)) - , m_ILU_scale(static_cast(ilu_scale)) + : m_mat(narrow_cast(size)) + , m_LU(narrow_cast(size)) + , m_ILU_scale(narrow_cast(ilu_scale)) , m_band_width(bw) { } @@ -103,7 +103,7 @@ namespace plib if (m_mat.col_idx[k] == i && k < m_mat.row_idx[j+1]) nzcol[i].push_back(k); } - nzcol[i].push_back(static_cast(-1)); + nzcol[i].push_back(narrow_cast(-1)); } } @@ -139,7 +139,7 @@ namespace plib const auto &nz = nzcol[i]; std::size_t j; - while ((j = nz[nzcolp++])!=static_cast(-1)) // NOLINT(bugprone-infinite-loop) + while ((j = nz[nzcolp++])!=narrow_cast(-1)) // NOLINT(bugprone-infinite-loop) { v += m_mat.A[j] * m_mat.A[j]; } @@ -209,14 +209,12 @@ namespace plib // FIXME: hardcoding RESTART to 20 becomes an issue on very large // systems. - template + template struct gmres_t { public: using float_type = FT; - // FIXME: dirty hack to make this compile - static constexpr const std::size_t storage_N = plib::sizeabs::ABS(); explicit gmres_t(std::size_t size) : residual(size) @@ -236,7 +234,7 @@ namespace plib g1 = s * g0_last + c * g1; } - std::size_t size() const { return (SIZE<=0) ? m_size : static_cast(SIZE); } + std::size_t size() const { return (SIZE<=0) ? m_size : narrow_cast(SIZE); } template bool do_k(OPS &ops, VT &x, std::size_t &itr_used, FT rho_delta, bool dummy) @@ -360,7 +358,7 @@ namespace plib rho_delta = accuracy * rho_to_accuracy; } else - rho_delta = accuracy * plib::sqrt(static_cast(n)); + rho_delta = accuracy * plib::sqrt(narrow_cast(n)); // // Using @@ -407,8 +405,6 @@ namespace plib private: - //typedef typename plib::mat_cr_t::index_type mattype; - plib::parray residual; plib::parray Ax; @@ -423,8 +419,6 @@ namespace plib std::size_t m_size; bool m_use_more_precise_stop_condition; - - }; @@ -454,7 +448,7 @@ namespace plib { } - std::size_t size() const { return (SIZE<=0) ? m_size : static_cast(SIZE); } + std::size_t size() const { return (SIZE<=0) ? m_size : narrow_cast(SIZE); } template std::size_t solve(OPS &ops, VT &x0, const VRHS & rhs, const std::size_t iter_max, float_type accuracy) @@ -478,7 +472,7 @@ namespace plib ops.calc_rhs(Ax, x); vec_sub(size(), rhs, Ax, residual); - FT rho_delta = accuracy * std::sqrt(static_cast(size())); + FT rho_delta = accuracy * std::sqrt(narrow_cast(size())); rho_delta = 1e-9; diff --git a/src/lib/netlist/plib/mat_cr.h b/src/lib/netlist/plib/mat_cr.h index 061e186d37f..2da661d39d7 100644 --- a/src/lib/netlist/plib/mat_cr.h +++ b/src/lib/netlist/plib/mat_cr.h @@ -73,7 +73,7 @@ namespace plib ~pmatrix_cr_t() = default; - constexpr std::size_t size() const noexcept { return (N>0) ? static_cast(N) : m_size; } + constexpr std::size_t size() const noexcept { return (N>0) ? narrow_cast(N) : m_size; } void clear() noexcept { @@ -132,9 +132,9 @@ namespace plib row_idx[k] = nz; for (std::size_t j=0; j < size(); j++) - if (f[k][j] <= max_fill && plib::abs(static_cast(k)-static_cast(j)) <= static_cast(band_width)) + if (f[k][j] <= max_fill && plib::abs(narrow_cast(k)-narrow_cast(j)) <= narrow_cast(band_width)) { - col_idx[nz] = static_cast(j); + col_idx[nz] = narrow_cast(j); if (j == k) diag[k] = nz; nz++; @@ -150,7 +150,7 @@ namespace plib { for (std::size_t j=k + 1; j < size(); j++) if (f[j][k] < FILL_INFINITY) - nzbd[k].push_back(static_cast(j)); + nzbd[k].push_back(narrow_cast(j)); nzbd[k].push_back(0); // end of sequence } @@ -343,7 +343,7 @@ namespace plib { for (std::size_t i = 0; i < m_ge_par.size(); i++) if (plib::container::contains( m_ge_par[i], k)) - return static_cast(i); + return narrow_cast(i); return -1; } @@ -525,7 +525,7 @@ namespace plib } } if (found) - ilu_rows[p++] = static_cast(i); + ilu_rows[p++] = narrow_cast(i); } ilu_rows[p] = 0; // end of array this->build_from_fill_mat(fill, ilup); //, m_band_width); // ILU(2) diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index 045461c8418..b3ebcbc52e5 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -9,6 +9,7 @@ /// #include "pconfig.h" +#include "pgsl.h" #include "pmath.h" #include "pstring.h" #include "ptypes.h" @@ -26,28 +27,52 @@ namespace plib { + //============================================================ + // aligned types + //============================================================ + +#if 0 +#if (PUSE_ALIGNED_HINTS) + template + using aligned_type __attribute__((aligned(A))) = T; +#else + template + using aligned_type = T; +#endif + + template + using aligned_pointer = aligned_type *; + + template + using const_aligned_pointer = const aligned_type *; + + template + using aligned_reference = aligned_type &; + + template + using const_aligned_reference = const aligned_type &; +#endif //============================================================ // Standard arena_deleter //============================================================ - template - struct arena_deleter + template + struct arena_deleter_base { - }; template - struct arena_deleter> + struct arena_deleter_base { using arena_storage_type = P; - constexpr arena_deleter(arena_storage_type *a = nullptr) noexcept + constexpr arena_deleter_base(arena_storage_type *a = nullptr) noexcept : m_a(a) { } template::value>> - arena_deleter(const arena_deleter &rhs) noexcept + arena_deleter_base(const arena_deleter_base &rhs) noexcept : m_a(rhs.m_a) { } void operator()(T *p) noexcept @@ -61,18 +86,18 @@ namespace plib { }; template - struct arena_deleter> + struct arena_deleter_base { using arena_storage_type = P; - constexpr arena_deleter(arena_storage_type *a = nullptr) noexcept + constexpr arena_deleter_base(arena_storage_type *a = nullptr) noexcept { plib::unused_var(a); } template::value>::type> - arena_deleter(const arena_deleter &rhs) noexcept + arena_deleter_base(const arena_deleter_base &rhs) noexcept { plib::unused_var(rhs); } @@ -85,6 +110,13 @@ namespace plib { } }; + template + struct arena_deleter : public arena_deleter_base + { + using base_type = arena_deleter_base; + using base_type::base_type; + }; + //============================================================ // owned_ptr: smart pointer with ownership information //============================================================ @@ -209,7 +241,8 @@ namespace plib { { public: using value_type = T; - static constexpr const std::size_t align_size = ALIGN; + using pointer = T *; + static /*constexpr*/ const std::size_t align_size = ALIGN; using arena_type = ARENA; static_assert(align_size >= alignof(T) && (align_size % alignof(T)) == 0, @@ -237,14 +270,14 @@ namespace plib { using other = arena_allocator; }; - T* allocate(std::size_t n) + pointer allocate(std::size_t n) { return reinterpret_cast(m_a.allocate(ALIGN, sizeof(T) * n)); //NOLINT } - void deallocate(T* p, std::size_t n) noexcept + void deallocate(pointer p, std::size_t n) noexcept { - m_a.deallocate(p, n); + m_a.deallocate(p, sizeof(T) * n); } template @@ -296,171 +329,88 @@ namespace plib { // The previous code compiled with gcc and clang on all platforms and // compilers apart from MSVC. - template + template + struct arena_base; + + template struct arena_core { static constexpr const bool has_static_deallocator = HSD; + static constexpr const bool has_static_allocator = HSA; using size_type = std::size_t; template using allocator_type = arena_allocator; + template + using deleter_type = arena_deleter; + + template + using unique_ptr = std::unique_ptr>; + + template + using owned_ptr = plib::owned_ptr>; + static inline P &instance() noexcept { static P s_arena; return s_arena; } - size_type cur_alloc() const noexcept { return m_stat_cur_alloc(); } // NOLINT(readability-convert-member-functions-to-static) - size_type max_alloc() const noexcept { return m_stat_max_alloc(); } // NOLINT(readability-convert-member-functions-to-static) - protected: - static size_t &m_stat_cur_alloc() noexcept { static size_t val = 0; return val; } - static size_t &m_stat_max_alloc() noexcept { static size_t val = 0; return val; } - - }; - - template - struct arena_hsd : public arena_core - { - template - inline void free(T *ptr) noexcept - { - ptr->~T(); - static_cast

(this)->deallocate(ptr, sizeof(T)); - } - }; + friend struct arena_base; + private: + size_t m_stat_cur_alloc = 0; + size_t m_stat_max_alloc = 0; - template - struct arena_hsd : public arena_core - { - template - static inline void free(T *ptr) noexcept - { - ptr->~T(); - P::deallocate(ptr, sizeof(T)); - } }; - template - struct arena_base : public arena_hsd + struct arena_base : public arena_core { - template - using deleter_type = arena_deleter; + using base_type = arena_core; + using size_type = typename base_type::size_type; - template - using unique_ptr = std::unique_ptr>; - - template - using owned_ptr = plib::owned_ptr>; + static size_type cur_alloc() noexcept { return base_type::instance().m_stat_cur_alloc; } + static size_type max_alloc() noexcept { return base_type::instance().m_stat_max_alloc; } - template - inline unique_ptr make_unique(Args&&... args) + static inline void inc_alloc_stat(size_type size) { - auto *mem = static_cast

(this)->allocate(alignof(T), sizeof(T)); - try - { - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - auto *mema = new (mem) T(std::forward(args)...); - return unique_ptr(mema, deleter_type()); - } - catch (...) - { - static_cast

(this)->deallocate(mem, sizeof(T)); - throw; - } + auto &i = base_type::instance(); + i.m_stat_cur_alloc += size; + if (i.m_stat_max_alloc - inline owned_ptr make_owned(Args&&... args) + static inline void dec_alloc_stat(size_type size) { - auto *mem = static_cast

(this)->allocate(alignof(T), sizeof(T)); - try - { - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - auto *mema = new (mem) T(std::forward(args)...); - return owned_ptr(mema, true, deleter_type()); - } - catch (...) - { - static_cast

(this)->deallocate(mem, sizeof(T)); - throw; - } + base_type::instance().m_stat_cur_alloc -= size; } - - template - inline T * alloc(Args&&... args) - { - auto *p = static_cast

(this)->allocate(alignof(T), sizeof(T)); - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - return new(p) T(std::forward(args)...); - } - }; - template - struct arena_base : public arena_hsd + template + struct arena_base : public arena_core { - template - using deleter_type = arena_deleter; + using size_type = typename arena_core::size_type; - template - using unique_ptr = std::unique_ptr>; - - template - using owned_ptr = plib::owned_ptr>; + size_type cur_alloc() const noexcept { return this->m_stat_cur_alloc; } + size_type max_alloc() const noexcept { return this->m_stat_max_alloc; } - template - static inline unique_ptr make_unique(Args&&... args) + inline void inc_alloc_stat(size_type size) { - auto *mem = P::allocate(alignof(T), sizeof(T)); - try - { - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - auto *mema = new (mem) T(std::forward(args)...); - return unique_ptr(mema, deleter_type()); - } - catch (...) - { - P::deallocate(mem, sizeof(T)); - throw; - } + this->m_stat_cur_alloc += size; + if (this->m_stat_max_alloc < this->m_stat_cur_alloc) + this->m_stat_max_alloc = this->m_stat_cur_alloc; } - - template - static inline owned_ptr make_owned(Args&&... args) + inline void dec_alloc_stat(size_type size) { - auto *mem = P::allocate(alignof(T), sizeof(T)); - try - { - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - auto *mema = new (mem) T(std::forward(args)...); - return owned_ptr(mema, true, deleter_type()); - } - catch (...) - { - P::deallocate(mem, sizeof(T)); - throw; - } - } - - template - static inline T * alloc(Args&&... args) - { - auto *p = P::allocate(alignof(T), sizeof(T)); - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - return new(p) T(std::forward(args)...); + this->m_stat_cur_alloc -= size; } }; - struct aligned_arena : public arena_base { - static inline void *allocate( size_t alignment, size_t size ) + static inline gsl::owner allocate( size_t alignment, size_t size ) { - m_stat_cur_alloc() += size; - if (m_stat_max_alloc() < m_stat_cur_alloc()) - m_stat_max_alloc() = m_stat_cur_alloc(); + inc_alloc_stat(size); #if (PUSE_ALIGNED_ALLOCATION) #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) @@ -472,7 +422,7 @@ namespace plib { } return p; #else - return aligned_alloc(alignment, size); + return static_cast>(aligned_alloc(alignment, size)); #endif #else unused_var(alignment); @@ -480,10 +430,10 @@ namespace plib { #endif } - static inline void deallocate( void *ptr, size_t size ) noexcept + static inline void deallocate(gsl::owner ptr, size_t size ) noexcept { //unused_var(size); - m_stat_cur_alloc() -= size; + dec_alloc_stat(size); #if (PUSE_ALIGNED_ALLOCATION) // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) ::free(ptr); @@ -504,14 +454,14 @@ namespace plib { { static inline void *allocate( size_t alignment, size_t size ) { - m_stat_cur_alloc() += size; + inc_alloc_stat(size); unused_var(alignment); return ::operator new(size); } static inline void deallocate( void *ptr, size_t size ) noexcept { - m_stat_cur_alloc() -= size; + dec_alloc_stat(size); ::operator delete(ptr); } @@ -522,31 +472,116 @@ namespace plib { } }; - template - constexpr T *assume_aligned_ptr(T *p) noexcept + namespace detail { - static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)"); - static_assert(is_pow2(ALIGN), "Alignment must be a power of 2"); + template + static inline T * alloc(Args&&... args) + { + auto *mem = ARENA::allocate(alignof(T), sizeof(T)); + try + { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + return new (mem) T(std::forward(args)...); + } + catch (...) + { + ARENA::deallocate(mem, sizeof(T)); + throw; + } + } -#if (PUSE_ALIGNED_HINTS) - return reinterpret_cast(__builtin_assume_aligned(p, ALIGN)); -#else - return p; -#endif + template + static inline void free(T *ptr) noexcept + { + ptr->~T(); + ARENA::deallocate(ptr, sizeof(T)); + } + + template + static inline T * alloc(ARENA &arena, Args&&... args) + { + auto *mem = arena.allocate(alignof(T), sizeof(T)); + try + { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + return new (mem) T(std::forward(args)...); + } + catch (...) + { + arena.deallocate(mem, sizeof(T)); + throw; + } + } + + template + static inline void free(ARENA &arena, T *ptr) noexcept + { + ptr->~T(); + arena.deallocate(ptr, sizeof(T)); + } + } // namespace detail + + + + template + static inline + std::enable_if_t> + make_unique(Args&&... args) + { + using up_type = typename ARENA::template unique_ptr; + using deleter_type = typename ARENA::template deleter_type; + auto *mem = detail::alloc(std::forward(args)...); + return up_type(mem, deleter_type()); } - template - constexpr const T *assume_aligned_ptr(const T *p) noexcept + template + static inline + std::enable_if_t> + make_unique(Args&&... args) { - static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)"); - static_assert(is_pow2(ALIGN), "Alignment must be a power of 2"); -#if (PUSE_ALIGNED_HINTS) - return reinterpret_cast(__builtin_assume_aligned(p, ALIGN)); -#else - return p; -#endif + return make_unique(ARENA::instance(), std::forward(args)...); } + template + static inline + typename ARENA::template unique_ptr + make_unique(ARENA &arena, Args&&... args) + { + using up_type = typename ARENA::template unique_ptr; + using deleter_type = typename ARENA::template deleter_type; + auto *mem = detail::alloc(arena, std::forward(args)...); + return up_type(mem, deleter_type(&arena)); + } + + template + static inline + std::enable_if_t> + make_owned(Args&&... args) + { + using op_type = typename ARENA::template owned_ptr; + using deleter_type = typename ARENA::template deleter_type; + auto *mem = detail::alloc(std::forward(args)...); + return op_type(mem, true, deleter_type()); + } + + template + static inline + std::enable_if_t> + make_owned(Args&&... args) + { + return make_owned(ARENA::instance(), std::forward(args)...); + } + + template + static inline typename ARENA::template owned_ptr make_owned(ARENA &arena, Args&&... args) + { + using op_type = typename ARENA::template owned_ptr; + using deleter_type = typename ARENA::template deleter_type; + auto *mem = detail::alloc(arena, std::forward(args)...); + return op_type(mem, true, deleter_type(&arena)); + } + + template using aligned_allocator = aligned_arena::allocator_type; @@ -557,56 +592,71 @@ namespace plib { PDEFINE_HAS_MEMBER(has_align, align_size); - template - struct align_traits + template + struct align_traits_base { + static_assert(!has_align::value, "no align"); static constexpr const std::size_t align_size = alignof(std::max_align_t); static constexpr const std::size_t value_size = sizeof(typename T::value_type); static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size; }; template - struct align_traits::value, void>> + struct align_traits_base { + static_assert(has_align::value, "no align"); static constexpr const std::size_t align_size = T::align_size; static constexpr const std::size_t value_size = sizeof(typename T::value_type); static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size; }; - //============================================================ - // Aligned vector - //============================================================ + template + struct align_traits : public align_traits_base::value> + {}; - // FIXME: needs a separate file - template > - class aligned_vector : public std::vector + template + class paged_arena : public arena_base, true, true> { public: - using base = std::vector; - - using reference = typename base::reference; - using const_reference = typename base::const_reference; - using pointer = typename base::pointer; - using const_pointer = typename base::const_pointer; - using size_type = typename base::size_type; + paged_arena() + { + } - using base::base; + PCOPYASSIGNMOVE(paged_arena, delete) - base & as_base() noexcept { return *this; } - const base & as_base() const noexcept { return *this; } + ~paged_arena() = default; - constexpr reference operator[](size_type i) noexcept + static void *allocate(size_t align, size_t size) { - return assume_aligned_ptr(&(base::operator[](0)))[i]; + plib::unused_var(align); + //size = ((size + PAGESIZE - 1) / PAGESIZE) * PAGESIZE; + return arena().allocate(PAGESIZE, size); } - constexpr const_reference operator[](size_type i) const noexcept + static void deallocate(void *ptr, size_t size) noexcept { - return assume_aligned_ptr(&(base::operator[](0)))[i]; + //size = ((size + PAGESIZE - 1) / PAGESIZE) * PAGESIZE; + arena().deallocate(ptr, size); } - pointer data() noexcept { return assume_aligned_ptr(base::data()); } - const_pointer data() const noexcept { return assume_aligned_ptr(base::data()); } + bool operator ==(const paged_arena &rhs) const noexcept { return this == &rhs; } + + static BASEARENA &arena() noexcept { static BASEARENA m_arena; return m_arena; } + private: + }; + + //============================================================ + // Aligned vector + //============================================================ + + // FIXME: needs a separate file + template >//aligned_arena> + class aligned_vector : public std::vector> + { + public: + using base = std::vector>; + + using base::base; }; diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h index 0d89a56195c..2c2b0fc4270 100644 --- a/src/lib/netlist/plib/parray.h +++ b/src/lib/netlist/plib/parray.h @@ -21,19 +21,20 @@ namespace plib { - template + template struct sizeabs { - static constexpr std::size_t ABS() noexcept { return (SIZE < 0) ? static_cast(0 - SIZE) : static_cast(SIZE); } + static constexpr std::size_t ABS() noexcept { return (SIZE < 0) ? narrow_cast(0 - SIZE) : narrow_cast(SIZE); } using container = typename std::array ; }; - template - struct sizeabs + template + struct sizeabs { static constexpr std::size_t ABS() noexcept { return 0; } + using allocator_type = typename ARENA::template allocator_type; //using container = typename std::vector>; - using container = typename std::vector>; + using container = typename std::vector; }; /// \brief Array with preallocated or dynamic allocation. @@ -51,17 +52,20 @@ namespace plib { /// I consider > 10% performance difference to be a use case. /// - template + template struct parray { public: - static constexpr std::size_t SIZEABS() noexcept { return sizeabs::ABS(); } + static constexpr std::size_t SIZEABS() noexcept { return sizeabs::ABS(); } - using base_type = typename sizeabs::container; + using base_type = typename sizeabs::container; using size_type = typename base_type::size_type; - using reference = typename base_type::reference; - using const_reference = typename base_type::const_reference; - using value_type = typename base_type::value_type; + using value_type = FT; + using reference = FT &; + using const_reference = const FT &; + + using pointer = FT *; + using const_pointer = const FT *; template parray(size_type size, std::enable_if_t<(X==0), int> = 0) @@ -70,7 +74,7 @@ namespace plib { } template - parray(size_type size, FT val, std::enable_if_t<(X==0), int> = 0) + parray(size_type size, const FT &val, std::enable_if_t<(X==0), int> = 0) : m_a(size, val), m_size(size) { } @@ -85,7 +89,7 @@ namespace plib { } template - parray(size_type size, FT val, std::enable_if_t<(X != 0), int> = 0) noexcept(false) + parray(size_type size, const FT &val, std::enable_if_t<(X != 0), int> = 0) noexcept(false) : m_size(size) { if ((SIZE < 0 && size > SIZEABS()) @@ -131,20 +135,19 @@ namespace plib { constexpr reference operator[](size_type i) noexcept { - return assume_aligned_ptr(&m_a[0])[i]; + return data()[i]; } constexpr const_reference operator[](size_type i) const noexcept { - return assume_aligned_ptr(&m_a[0])[i]; + return data()[i]; } - FT * data() noexcept { return assume_aligned_ptr(m_a.data()); } - const FT * data() const noexcept { return assume_aligned_ptr(m_a.data()); } + pointer data() noexcept { return m_a.data(); } + const_pointer data() const noexcept { return m_a.data(); } private: PALIGNAS_VECTOROPT() base_type m_a; - PALIGNAS_CACHELINE() size_type m_size; }; diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h index feee8a30c3e..4a5e77d9ca2 100644 --- a/src/lib/netlist/plib/pchrono.h +++ b/src/lib/netlist/plib/pchrono.h @@ -9,6 +9,7 @@ /// #include "pconfig.h" +#include "pgsl.h" #include "ptypes.h" #include @@ -212,8 +213,8 @@ namespace plib { ctype count() const noexcept { return m_count; } template - S as_seconds() const noexcept { return static_cast(total()) - / static_cast(T::per_second()); } + S as_seconds() const noexcept { return narrow_cast(total()) + / narrow_cast(T::per_second()); } guard_t guard() noexcept { return guard_t(*this); } private: @@ -244,7 +245,7 @@ namespace plib { constexpr type total() const noexcept { return 0; } constexpr ctype count() const noexcept { return 0; } template - S as_seconds() const noexcept { return static_cast(0.0); } + S as_seconds() const noexcept { return narrow_cast(0); } constexpr static bool enabled = false; guard_t guard() { return guard_t(); } }; diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h index b719139d73f..984ed944acb 100644 --- a/src/lib/netlist/plib/pconfig.h +++ b/src/lib/netlist/plib/pconfig.h @@ -72,10 +72,11 @@ #define PALIGNAS_CACHELINE() PALIGNAS(PALIGN_CACHELINE) #define PALIGNAS_VECTOROPT() PALIGNAS(PALIGN_VECTOROPT) -// FIXME: Breaks mame build on windows due to -Wattribute +// FIXME: Breaks mame build on windows mingw due to -Wattribute // also triggers -Wattribute on ARM +// This is fixed on mingw version 10 // FIXME: no error on cross-compile - need further checks -#if defined(__GNUC__) && (defined(_WIN32) || defined(__arm__) || defined(__ARMEL__)) +#if defined(__GNUC__) && ((defined(_WIN32) && __GNUC__ < 10) || defined(__arm__) || defined(__ARMEL__)) #define PALIGNAS(x) #else #define PALIGNAS(x) alignas(x) @@ -83,7 +84,7 @@ /// \brief nvcc build flag. /// -/// Set this to 1 if you are building with NVIDIA nvcc +/// Set this to 101 if you are building with NVIDIA nvcc 10.1 /// #ifndef NVCCBUILD #define NVCCBUILD (0) @@ -166,5 +167,15 @@ typedef __float128 FLOAT128; #endif #endif +#if (PUSE_FLOAT128) +#if defined(__has_include) +#if !__has_include() +//#pragma message "disabling PUSE_FLOAT128 due to missing quadmath.h" +#undef PUSE_FLOAT128 +#define PUSE_FLOAT128 (0) +#endif +#endif +#endif + #endif // PCONFIG_H_ diff --git a/src/lib/netlist/plib/pdynlib.h b/src/lib/netlist/plib/pdynlib.h index ffb3ae03b99..6fe91953529 100644 --- a/src/lib/netlist/plib/pdynlib.h +++ b/src/lib/netlist/plib/pdynlib.h @@ -31,6 +31,7 @@ namespace plib { template T getsym(const pstring &name) const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast(getsym_p(name)); } diff --git a/src/lib/netlist/plib/penum.h b/src/lib/netlist/plib/penum.h index 2765e262773..f965411d546 100644 --- a/src/lib/netlist/plib/penum.h +++ b/src/lib/netlist/plib/penum.h @@ -24,7 +24,7 @@ namespace plib // Implementation in putil.cpp. // Putting the code here leads to a performance decrease. static int from_string_int(const pstring &str, const pstring &x); - static pstring nthstr(int n, const pstring &str); + static pstring nthstr(std::size_t n, const pstring &str); }; } // namespace plib @@ -43,7 +43,7 @@ namespace plib constexpr bool operator==(const ename &rhs) const noexcept {return m_v == rhs.m_v;} \ constexpr bool operator==(const E &rhs) const noexcept {return m_v == rhs;} \ pstring name() const { \ - return nthstr(static_cast(m_v), strings()); \ + return nthstr(m_v, strings()); \ } \ private: E m_v; \ static pstring strings() {\ diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp index d332f989321..56ef7f93efb 100644 --- a/src/lib/netlist/plib/pexception.cpp +++ b/src/lib/netlist/plib/pexception.cpp @@ -5,8 +5,8 @@ #include "pfmtlog.h" #include -#include #include +#include #if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__) #define HAS_FEENABLE_EXCEPT (1) diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp index d776e0133da..ddb9b5dd2e5 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -92,7 +92,7 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec) // a.b format here ... char32_t pend(0); int width(0); - if (fmt != "" && pstring("duxofge").find(static_cast(cfmt_spec)) != pstring::npos) + if (!fmt.empty() && pstring("duxofge").find(static_cast(cfmt_spec)) != pstring::npos) { pend = static_cast(fmt.at(fmt.size() - 1)); if (pstring("duxofge").find(static_cast(pend)) == pstring::npos) @@ -113,7 +113,7 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec) strm << std::setprecision(pstonum_ne_def(fmt.substr(pdot + 1), 6)); width = pstonum_ne_def(left(fmt,pdot), 0); } - else if (fmt != "") + else if (!fmt.empty()) width = pstonum_ne_def(fmt, 0); auto aw(plib::abs(width)); diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index 793c59bf954..ac2a5e9a747 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -55,7 +55,7 @@ namespace plib { static char32_t fmt_spec() { return 'f'; } static inline void streamify(std::ostream &s, const FLOAT128 &v) { - s << static_cast(v); + s << narrow_cast(v); } }; #endif @@ -322,7 +322,7 @@ namespace plib { if (build_enabled && enabled && m_enabled) { pfmt pf(fmt); - static_cast(this)->vdowrite(xlog(pf, std::forward(args)...)); + dynamic_cast(*this).vdowrite(xlog(pf, std::forward(args)...)); } } @@ -332,7 +332,7 @@ namespace plib { if (build_enabled && m_enabled) { pfmt pf(fmt); - static_cast(this)->vdowrite(xlog(pf, std::forward(args)...)); + static_cast(*this).vdowrite(xlog(pf, std::forward(args)...)); } } diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index c5e011dfbb9..3a360c7a33f 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -25,26 +25,26 @@ namespace plib { { static std::map units_si_stat = { - //{ "Y", static_cast(1e24) }, // NOLINT: Yotta - //{ "Z", static_cast(1e21) }, // NOLINT: Zetta - //{ "E", static_cast(1e18) }, // NOLINT: Exa - { "P", static_cast(1e15) }, // NOLINT: Peta - { "T", static_cast(1e12) }, // NOLINT: Tera - { "G", static_cast( 1e9) }, // NOLINT: Giga - { "M", static_cast( 1e6) }, // NOLINT: Mega - { "k", static_cast( 1e3) }, // NOLINT: Kilo - { "h", static_cast( 1e2) }, // NOLINT: Hekto - //{ "da", static_cast(1e1) }, // NOLINT: Deka - { "d", static_cast(1e-1) }, // NOLINT: Dezi - { "c", static_cast(1e-2) }, // NOLINT: Zenti - { "m", static_cast(1e-3) }, // NOLINT: Milli - { "μ", static_cast(1e-6) }, // NOLINT: Mikro - { "n", static_cast(1e-9) }, // NOLINT: Nano - { "p", static_cast(1e-12) }, // NOLINT: Piko - { "f", static_cast(1e-15) }, // NOLINT: Femto - { "a", static_cast(1e-18) }, // NOLINT: Atto - { "z", static_cast(1e-21) }, // NOLINT: Zepto - { "y", static_cast(1e-24) }, // NOLINT: Yokto + //{ "Y", narrow_cast(1e24) }, // NOLINT: Yotta + //{ "Z", narrow_cast(1e21) }, // NOLINT: Zetta + //{ "E", narrow_cast(1e18) }, // NOLINT: Exa + { "P", narrow_cast(1e15) }, // NOLINT: Peta + { "T", narrow_cast(1e12) }, // NOLINT: Tera + { "G", narrow_cast( 1e9) }, // NOLINT: Giga + { "M", narrow_cast( 1e6) }, // NOLINT: Mega + { "k", narrow_cast( 1e3) }, // NOLINT: Kilo + { "h", narrow_cast( 1e2) }, // NOLINT: Hekto + //{ "da", narrow_cast(1e1) }, // NOLINT: Deka + { "d", narrow_cast(1e-1) }, // NOLINT: Dezi + { "c", narrow_cast(1e-2) }, // NOLINT: Zenti + { "m", narrow_cast(1e-3) }, // NOLINT: Milli + { "μ", narrow_cast(1e-6) }, // NOLINT: Mikro + { "n", narrow_cast(1e-9) }, // NOLINT: Nano + { "p", narrow_cast(1e-12) }, // NOLINT: Piko + { "f", narrow_cast(1e-15) }, // NOLINT: Femto + { "a", narrow_cast(1e-18) }, // NOLINT: Atto + { "z", narrow_cast(1e-21) }, // NOLINT: Zepto + { "y", narrow_cast(1e-24) }, // NOLINT: Yokto }; return units_si_stat; } @@ -105,7 +105,7 @@ namespace plib { if (inputs[i] == cmd) { rc.m_cmd = PUSH_INPUT; - rc.m_param = static_cast(i); + rc.m_param = narrow_cast(i); stk += 1; break; } @@ -128,7 +128,7 @@ namespace plib { } if (stk < 1) throw pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr)); - if (stk >= static_cast(MAX_STACK)) + if (stk >= narrow_cast(MAX_STACK)) throw pexception(plib::pfmt("pfunction: stack overflow on token <{1}> in <{2}>")(cmd)(expr)); m_precompiled.push_back(rc); } @@ -286,7 +286,7 @@ namespace plib { lfsr >>= 1; if (lsb) lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10 - return static_cast(lfsr) / static_cast(0xffffU); // NOLINT + return narrow_cast(lfsr) / narrow_cast(0xffffU); // NOLINT } template @@ -297,7 +297,7 @@ namespace plib { lfsr >>= 1; if (lsb) lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10 - return static_cast(lfsr); + return narrow_cast(lfsr); } #define ST1 stack[ptr] @@ -333,7 +333,7 @@ namespace plib { stack[ptr++] = lfsr_random(m_lfsr); break; case PUSH_INPUT: - stack[ptr++] = values[static_cast(rc.m_param)]; + stack[ptr++] = values[narrow_cast(rc.m_param)]; break; case PUSH_CONST: stack[ptr++] = rc.m_param; diff --git a/src/lib/netlist/plib/pgsl.h b/src/lib/netlist/plib/pgsl.h new file mode 100644 index 00000000000..ab7798071a5 --- /dev/null +++ b/src/lib/netlist/plib/pgsl.h @@ -0,0 +1,105 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +#ifndef PGSL_H_ +#define PGSL_H_ + +/// +/// \file pgsl.h +/// +/// This core guidelines gsl implementation currently provides only enough +/// functionality to syntactically support a very limited number of the +/// gsl specification. +/// +/// Going forward this approach may be extended. +/// + +#include "pconfig.h" +#include "pexception.h" +#include "ptypes.h" + +#include +#include +#include + +#if defined(__has_builtin) // clang and gcc 10 + #if __has_builtin(__builtin_unreachable) + #define gsl_Expects(e) ((e) ? static_cast(0) : __builtin_unreachable()) + #endif +#elif defined(__GNUC__) && !(defined( __CUDACC__ ) && defined( __CUDA_ARCH__ )) + #define gsl_Expects(e) ((e) ? static_cast(0) : __builtin_unreachable()) +#elif defined(_MSC_VER) + #define gsl_Expects(e) __assume(e) +#else + #define gsl_Expects(e) ((e) ? static_cast(0) : static_cast(0)) +#endif + +#undef gsl_Expects +#define gsl_Expects(e) do {} while (0) +#define gsl_Ensures(e) gsl_Expects(e) + +namespace plib { + namespace pgsl { + + struct narrowing_error : public std::exception {}; + + template + using owner = T; + + template + using not_null = T; + + /// \brief perform a narrowing cast without checks + /// + template + inline constexpr T narrow_cast(O && v) noexcept + { + static_assert(plib::is_arithmetic::value && std::is_convertible, T>::value, "narrow cast expects conversion between arithmetic types"); + return static_cast(std::forward(v)); + } + + /// \brief perform a narrowing cast terminating if loss of precision + /// + /// The c++ core guidelines require the narrow function to raise an error + /// This will make narrow noexcept(false). This has shown to have a + /// measurable impact on performance and thus we deviate we deviate from + /// the standard here. + /// + template + inline T narrow(O && v) noexcept + { + static_assert(plib::is_arithmetic::value && std::is_convertible, T>::value, "narrow cast expects conversion between arithmetic types"); + + const auto val = static_cast(std::forward(v)); + if( v == static_cast>(val)) + { + return val; + } + + plib::terminate("narrowing_error"); + // throw narrowing_error(); + } + + } // namespace pgsl + + /// \brief downcast from base tpye to derived type + /// + /// The cpp core guidelines require a very careful use of static cast + /// for downcast operations. This template is used to identify these uses + /// and later for debug builds use dynamic_cast. + /// + template + inline constexpr D downcast(B && b) noexcept + { + static_assert(std::is_pointer::value || std::is_reference::value, "downcast only supports pointers or reference for derived"); + static_assert(std::is_pointer::value || std::is_reference::value, "downcast only supports pointers or reference for base"); + return static_cast(std::forward(b)); + } + + using pgsl::narrow_cast; +} // namespace plib + +//FIXME: This is the place to use more complete implementations +namespace gsl = plib::pgsl; + +#endif // PGSL_H_ diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h index f5151b95011..4e3ddace57e 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -62,11 +62,13 @@ namespace plib { reference operator[](size_type index) noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast(m_buf[index]); } constexpr const_reference operator[](size_type index) const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast(m_buf[index]); } @@ -78,13 +80,19 @@ namespace plib { new (&m_buf[index]) C(std::forward(args)...); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) iterator begin() const noexcept { return reinterpret_cast(&m_buf[0]); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) iterator end() const noexcept { return reinterpret_cast(&m_buf[N]); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) iterator begin() noexcept { return reinterpret_cast(&m_buf[0]); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) iterator end() noexcept { return reinterpret_cast(&m_buf[N]); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) const_iterator cbegin() const noexcept { return reinterpret_cast(&m_buf[0]); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) const_iterator cend() const noexcept { return reinterpret_cast(&m_buf[N]); } protected: diff --git a/src/lib/netlist/plib/pmain.cpp b/src/lib/netlist/plib/pmain.cpp index 1e4791adea8..fb428a179fa 100644 --- a/src/lib/netlist/plib/pmain.cpp +++ b/src/lib/netlist/plib/pmain.cpp @@ -29,8 +29,8 @@ namespace plib { int app::main_utfX(int argc, char *argv[]) { std::vector arg; - for (std::size_t i = 0; i < static_cast(argc); i++) - arg.push_back(putf8string(argv[i])); + for (std::size_t i = 0; i < narrow_cast(argc); i++) + arg.emplace_back(putf8string(argv[i])); return main_utfX(arg); } @@ -38,8 +38,8 @@ namespace plib { int app::main_utfX(int argc, wchar_t *argv[]) { std::vector arg; - for (std::size_t i = 0; i < static_cast(argc); i++) - arg.push_back(putf8string(pwstring(argv[i]))); + for (std::size_t i = 0; i < narrow_cast(argc); i++) + arg.emplace_back(putf8string(pwstring(argv[i]))); return main_utfX(arg); } diff --git a/src/lib/netlist/plib/pmath.h b/src/lib/netlist/plib/pmath.h index 652cff059d2..e70c8f7fd55 100644 --- a/src/lib/netlist/plib/pmath.h +++ b/src/lib/netlist/plib/pmath.h @@ -15,9 +15,7 @@ #include #include -#if (PUSE_FLOAT128) -#include -#endif +// quadmath.h included by ptypes.h namespace plib { diff --git a/src/lib/netlist/plib/pmatrix2d.h b/src/lib/netlist/plib/pmatrix2d.h old mode 100644 new mode 100755 index 33e3169c64a..b9a2ebee116 --- a/src/lib/netlist/plib/pmatrix2d.h +++ b/src/lib/netlist/plib/pmatrix2d.h @@ -17,70 +17,102 @@ namespace plib { - template> + template class pmatrix2d { public: using size_type = std::size_t; + using arena_type = A; + using allocator_type = typename A::template allocator_type; + + static constexpr const size_type align_size = align_traits::align_size; + static constexpr const size_type stride_size = align_traits::stride_size; + using value_type = T; - using allocator_type = A; + using reference = T &; + using const_reference = const T &; + + using pointer = T *; + using const_pointer = const T *; - static constexpr const size_type align_size = align_traits::align_size; - static constexpr const size_type stride_size = align_traits::stride_size; pmatrix2d() noexcept - : m_N(0), m_M(0), m_stride(8), m_v() + : m_N(0), m_M(0), m_stride(8), m_v(nullptr) { } pmatrix2d(size_type N, size_type M) : m_N(N), m_M(M), m_v() { + gsl_Expects(N>0); + gsl_Expects(M>0); m_stride = ((M + stride_size-1) / stride_size) * stride_size; - m_v.resize(N * m_stride); + m_v = m_a.allocate(N * m_stride); + for (std::size_t i = 0; i < N * m_stride; i++) + ::new(&m_v[i]) T(); + } + + ~pmatrix2d() + { + if (m_v != nullptr) + { + for (std::size_t i = 0; i < m_N * m_stride; i++) + (&m_v[i])->~T(); + m_a.deallocate(m_v, m_N * m_stride); + } } void resize(size_type N, size_type M) { + gsl_Expects(N>0); + gsl_Expects(M>0); + if (m_v != nullptr) + { + for (std::size_t i = 0; i < N * m_stride; i++) + (&m_v[i])->~T(); + m_a.deallocate(m_v, N * m_stride); + } m_N = N; m_M = M; m_stride = ((M + stride_size-1) / stride_size) * stride_size; - m_v.resize(N * m_stride); + m_v = m_a.allocate(N * m_stride); + for (std::size_t i = 0; i < N * m_stride; i++) + ::new(&m_v[i]) T(); } - constexpr T * operator[] (size_type row) noexcept + constexpr pointer operator[] (size_type row) noexcept { - return assume_aligned_ptr(&m_v[m_stride * row]); + return &m_v[m_stride * row]; } - constexpr const T * operator[] (size_type row) const noexcept + constexpr const_pointer operator[] (size_type row) const noexcept { - return assume_aligned_ptr(&m_v[m_stride * row]); + return &m_v[m_stride * row]; } - T & operator()(size_type r, size_type c) noexcept + reference operator()(size_type r, size_type c) noexcept { return (*this)[r][c]; } - const T & operator()(size_type r, size_type c) const noexcept + const_reference operator()(size_type r, size_type c) const noexcept { return (*this)[r][c]; } // for compatibility with vrl variant - void set(size_type r, size_type c, const T &v) noexcept + void set(size_type r, size_type c, const value_type &v) noexcept { (*this)[r][c] = v; } - T * data() noexcept + pointer data() noexcept { - return m_v.data(); + return m_v; } - const T * data() const noexcept + const_pointer data() const noexcept { - return m_v.data(); + return m_v; } size_type didx(size_type r, size_type c) const noexcept @@ -93,20 +125,23 @@ namespace plib size_type m_M; size_type m_stride; - std::vector m_v; + T * __restrict m_v; + + allocator_type m_a; }; // variable row length matrix - template> + template class pmatrix2d_vrl { public: using size_type = std::size_t; using value_type = T; - using allocator_type = A; + using arena_type = A; + using allocator_type = typename A::template allocator_type; - static constexpr const size_type align_size = align_traits::align_size; - static constexpr const size_type stride_size = align_traits::stride_size; + static constexpr const size_type align_size = align_traits::align_size; + static constexpr const size_type stride_size = align_traits::stride_size; pmatrix2d_vrl() noexcept : m_N(0), m_M(0), m_v() { @@ -139,24 +174,24 @@ namespace plib return &(m_v[m_row[row]]); } -#if 0 + //FIXME: no check! T & operator()(size_type r, size_type c) noexcept { return (*this)[r][c]; } -#else + void set(size_type r, size_type c, const T &v) noexcept { if (c + m_row[r] >= m_row[r + 1]) { - m_v.insert(m_v.begin() + m_row[r+1], v); + m_v.insert(m_v.begin() + narrow_cast(m_row[r+1]), v); for (size_type i = r + 1; i <= m_N; i++) m_row[i] = m_row[i] + 1; } else (*this)[r][c] = v; } -#endif + //FIXME: no check! const T & operator()(size_type r, size_type c) const noexcept { @@ -184,8 +219,8 @@ namespace plib size_type m_N; size_type m_M; - std::vector m_row; - std::vector m_v; + std::vector> m_row; + std::vector m_v; }; diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h index 441595d9e58..ece0f117a8d 100644 --- a/src/lib/netlist/plib/pmempool.h +++ b/src/lib/netlist/plib/pmempool.h @@ -40,31 +40,26 @@ namespace plib { mempool_arena(size_t min_alloc = (1<<21), size_t min_align = PALIGN_CACHELINE) : m_min_alloc(min_alloc) , m_min_align(min_align) + , m_block_align(1024) , m_blocks(base_allocator_type(m_arena)) { - icount()++; } PCOPYASSIGNMOVE(mempool_arena, delete) ~mempool_arena() { - for (auto & b : m_blocks) { if (b->m_num_alloc != 0) { - plib::perrlogger("Found {} info blocks\n", sinfo().size()); + plib::perrlogger("Found {} info blocks\n", m_info.size()); plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc); } - m_arena.free(b); - //::operator delete(b->m_data); - } - if (icount()-- == 1) - { - if (!sinfo().empty()) - plib::perrlogger("Still found {} info blocks after last mempool deleted\n", sinfo().size()); + detail::free(m_arena, b); } + if (!m_info.empty()) + plib::perrlogger("Still found {} info blocks after mempool deleted\n", m_info.size()); } void *allocate(size_t align, size_t size) @@ -92,21 +87,18 @@ namespace plib { void *ret = reinterpret_cast(b->m_data + b->m_cur); auto capacity(rs); ret = std::align(align, size, ret, capacity); - sinfo().insert({ ret, info(b, b->m_cur)}); + m_info.insert({ ret, info(b, b->m_cur)}); rs -= (capacity - size); b->m_cur += rs; - base_type::m_stat_cur_alloc() += size; - if (base_type::m_stat_max_alloc() < base_type::m_stat_cur_alloc()) - base_type::m_stat_max_alloc() = base_type::m_stat_cur_alloc(); + this->inc_alloc_stat(size); return ret; } - /*static */ void deallocate(void *ptr, size_t size) noexcept + void deallocate(void *ptr, size_t size) noexcept { - - auto it = sinfo().find(ptr); - if (it == sinfo().end()) + auto it = m_info.find(ptr); + if (it == m_info.end()) plib::terminate("mempool::free - pointer not found"); block *b = it->second.m_block; if (b->m_num_alloc == 0) @@ -115,7 +107,7 @@ namespace plib { { mempool_arena &mp = b->m_mempool; b->m_num_alloc--; - mp.m_stat_cur_alloc() -= size; + mp.dec_alloc_stat(size); if (b->m_num_alloc == 0) { auto itb = std::find(mp.m_blocks.begin(), mp.m_blocks.end(), b); @@ -123,14 +115,15 @@ namespace plib { plib::terminate("mempool::free - block not found"); mp.m_blocks.erase(itb); - m_arena.free(b); + detail::free(mp.base_arena(), b); } - sinfo().erase(it); + m_info.erase(it); } } bool operator ==(const mempool_arena &rhs) const noexcept { return this == &rhs; } + BASEARENA &base_arena() noexcept { return m_arena; } private: struct block { @@ -142,17 +135,19 @@ namespace plib { { min_bytes = std::max(mp.m_min_alloc, min_bytes); m_free = min_bytes; - size_type alloc_bytes = (min_bytes + mp.m_min_align); // - 1); // & ~(mp.m_min_align - 1); + m_bytes_allocated = (min_bytes + mp.m_block_align); // - 1); // & ~(mp.m_min_align - 1); // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - m_data_allocated = new std::uint8_t[alloc_bytes]; + //m_data_allocated = new std::uint8_t[alloc_bytes]; + m_data_allocated = static_cast(mp.base_arena().allocate(mp.m_block_align, m_bytes_allocated)); void *r = m_data_allocated; - std::align(mp.m_min_align, min_bytes, r, alloc_bytes); + std::align(mp.m_block_align, min_bytes, r, m_bytes_allocated); m_data = reinterpret_cast(r); } ~block() { //::operator delete(m_data_allocated); - delete [] m_data_allocated; + //delete [] m_data_allocated; + m_mempool.base_arena().deallocate(m_data_allocated, m_bytes_allocated); } block(const block &) = delete; @@ -163,6 +158,7 @@ namespace plib { size_type m_num_alloc; size_type m_free; size_type m_cur; + size_type m_bytes_allocated; std::uint8_t *m_data; std::uint8_t *m_data_allocated; mempool_arena &m_mempool; @@ -180,27 +176,20 @@ namespace plib { block * new_block(size_type min_bytes) { - auto *b = m_arena.template alloc(*this, min_bytes); + auto *b = detail::alloc(m_arena, *this, min_bytes); m_blocks.push_back(b); return b; } - static std::unordered_map &sinfo() - { - static std::unordered_map spinfo; - return spinfo; - } - - static std::size_t &icount() - { - static std::size_t count = 0; - return count; - } - size_t m_min_alloc; size_t m_min_align; + size_t m_block_align; BASEARENA m_arena; + using base_allocator_typex = typename BASEARENA::template allocator_type>; + std::unordered_map, std::equal_to, + base_allocator_typex> m_info; +// std::unordered_map m_info; std::vector> m_blocks; }; diff --git a/src/lib/netlist/plib/poptions.cpp b/src/lib/netlist/plib/poptions.cpp index 690feb38c61..c22076f6d0c 100644 --- a/src/lib/netlist/plib/poptions.cpp +++ b/src/lib/netlist/plib/poptions.cpp @@ -68,7 +68,7 @@ namespace plib { auto *o = dynamic_cast