diff --git a/include/xsimd/config/xsimd_cpu_features_arm.hpp b/include/xsimd/config/xsimd_cpu_features_arm.hpp index d52a8a219..add0162c4 100644 --- a/include/xsimd/config/xsimd_cpu_features_arm.hpp +++ b/include/xsimd/config/xsimd_cpu_features_arm.hpp @@ -13,11 +13,9 @@ #define XSIMD_CPU_FEATURES_ARM_HPP #include "./xsimd_config.hpp" - -#if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL -#include "../utils/bits.hpp" #include "./xsimd_getauxval.hpp" +#if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL // HWCAP_XXX masks to use on getauxval results. // Header does not exists on all architectures and masks are architecture // specific. @@ -36,87 +34,54 @@ namespace xsimd * This is well defined on all architectures. * It will always return false on non-ARM architectures. */ - class arm_cpu_features + class arm_cpu_features : private linux_hwcap_backend_default { public: - arm_cpu_features() noexcept = default; + inline bool neon() const noexcept; + inline bool neon64() const noexcept; + inline bool sve() const noexcept; + inline bool i8mm() const noexcept; + }; + + /******************** + * Implementation * + ********************/ - inline bool neon() const noexcept - { + inline bool arm_cpu_features::neon() const noexcept + { #if XSIMD_TARGET_ARM && !XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL - return hwcap().has_feature(HWCAP_NEON); + return hwcap().has_feature(HWCAP_NEON); #else - return static_cast(XSIMD_WITH_NEON); + return static_cast(XSIMD_WITH_NEON); #endif - } + } - constexpr bool neon64() const noexcept - { - return static_cast(XSIMD_WITH_NEON64); - } + inline bool arm_cpu_features::neon64() const noexcept + { + return static_cast(XSIMD_WITH_NEON64); + } - inline bool sve() const noexcept - { + inline bool arm_cpu_features::sve() const noexcept + { #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL - return hwcap().has_feature(HWCAP_SVE); + return hwcap().has_feature(HWCAP_SVE); #else - return false; + return false; #endif - } - - inline bool i8mm() const noexcept - { + } + inline bool arm_cpu_features::i8mm() const noexcept + { #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL #ifdef HWCAP2_I8MM - return hwcap2().has_feature(HWCAP2_I8MM); + return hwcap2().has_feature(HWCAP2_I8MM); #else - // Possibly missing on older Linux distributions - return hwcap2().has_feature(1 << 13); + // Possibly missing on older Linux distributions + return hwcap2().has_feature(1 << 13); #endif #else - return false; + return false; #endif - } - - private: -#if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL - enum class status - { - hwcap_valid = 0, - hwcap2_valid = 1, - }; - - using status_bitset = utils::uint_bitset; - - mutable status_bitset m_status {}; - - mutable xsimd::linux_auxval m_hwcap {}; - - inline xsimd::linux_auxval const& hwcap() const noexcept - { - if (!m_status.bit_is_set()) - { - m_hwcap = xsimd::linux_auxval::read(AT_HWCAP); - m_status.set_bit(); - } - return m_hwcap; - } - -#if XSIMD_TARGET_ARM64 - mutable xsimd::linux_auxval m_hwcap2 {}; - - inline xsimd::linux_auxval const& hwcap2() const noexcept - { - if (!m_status.bit_is_set()) - { - m_hwcap2 = xsimd::linux_auxval::read(AT_HWCAP2); - m_status.set_bit(); - } - return m_hwcap2; - } -#endif -#endif // XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL - }; + } } #endif diff --git a/include/xsimd/config/xsimd_cpu_features_riscv.hpp b/include/xsimd/config/xsimd_cpu_features_riscv.hpp index 2520a249e..62e900d3b 100644 --- a/include/xsimd/config/xsimd_cpu_features_riscv.hpp +++ b/include/xsimd/config/xsimd_cpu_features_riscv.hpp @@ -13,11 +13,9 @@ #define XSIMD_CPU_FEATURES_RISCV_HPP #include "./xsimd_config.hpp" - -#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL -#include "../utils/bits.hpp" #include "./xsimd_getauxval.hpp" +#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL // HWCAP_XXX masks to use on getauxval results. // Header does not exists on all architectures and masks are architecture // specific. @@ -26,49 +24,29 @@ namespace xsimd { - class riscv_cpu_features + class riscv_cpu_features : private linux_hwcap_backend_default { public: - riscv_cpu_features() noexcept = default; + inline bool rvv() const noexcept; + }; - inline bool rvv() const noexcept - { + /******************** + * Implementation * + ********************/ + + inline bool riscv_cpu_features::rvv() const noexcept + { #if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL #ifdef HWCAP_V - return hwcap().has_feature(HWCAP_V); + return hwcap().has_feature(HWCAP_V); #else - // Possibly missing on older Linux distributions - return hwcap().has_feature(1 << ('V' - 'A')); + // Possibly missing on older Linux distributions + return hwcap().has_feature(1 << ('V' - 'A')); #endif #else - return false; -#endif - } - - private: -#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL - enum class status - { - hwcap_valid = 0, - }; - - using status_bitset = utils::uint_bitset; - - mutable status_bitset m_status {}; - - mutable xsimd::linux_auxval m_hwcap {}; - - inline xsimd::linux_auxval const& hwcap() const noexcept - { - if (!m_status.bit_is_set()) - { - m_hwcap = xsimd::linux_auxval::read(AT_HWCAP); - m_status.set_bit(); - } - return m_hwcap; - } + return false; #endif - }; + } } #endif diff --git a/include/xsimd/config/xsimd_getauxval.hpp b/include/xsimd/config/xsimd_getauxval.hpp index dfd2c3b7d..0c9cff57e 100644 --- a/include/xsimd/config/xsimd_getauxval.hpp +++ b/include/xsimd/config/xsimd_getauxval.hpp @@ -12,6 +12,7 @@ #ifndef XSIMD_GETAUXVAL_HPP #define XSIMD_GETAUXVAL_HPP +#include "../utils/bits.hpp" #include "./xsimd_config.hpp" #if XSIMD_HAVE_LINUX_GETAUXVAL @@ -68,6 +69,49 @@ namespace xsimd } }; + class linux_hwcap_backend + { + public: + inline linux_auxval hwcap() const noexcept; + + inline linux_auxval hwcap2() const noexcept; + + private: + enum class status + { + hwcap_valid = 0, + hwcap2_valid = 1, + }; + + using status_bitset = utils::uint_bitset; + + mutable status_bitset m_status {}; + mutable xsimd::linux_auxval m_hwcap {}; + mutable xsimd::linux_auxval m_hwcap2 {}; + }; + + class linux_hwcap_backend_noop + { + public: + inline linux_auxval hwcap() const noexcept { return {}; } + + inline linux_auxval hwcap2() const noexcept { return {}; } + }; + +#if XSIMD_HAVE_LINUX_GETAUXVAL + using linux_hwcap_backend_default = linux_hwcap_backend; +#else + // Contrary to CPUID that is only used on one architecture, HWCAP are + // available on multiple architectures with different meaning for the + // different bit fields. + // We use the Linux `HWCAP` constants directly to avoid repetition, so + // we could not use a default implementation without already being on + // Linux anyways. + struct linux_hwcap_backend_default + { + }; +#endif + /******************** * Implementation * ********************/ @@ -86,6 +130,30 @@ namespace xsimd } #endif } + + inline linux_auxval linux_hwcap_backend::hwcap() const noexcept + { + if (!m_status.bit_is_set()) + { +#if XSIMD_HAVE_LINUX_GETAUXVAL + m_hwcap = linux_auxval::read(AT_HWCAP); +#endif + m_status.set_bit(); + } + return m_hwcap; + } + + inline linux_auxval linux_hwcap_backend::hwcap2() const noexcept + { + if (!m_status.bit_is_set()) + { +#if XSIMD_HAVE_LINUX_GETAUXVAL + m_hwcap2 = linux_auxval::read(AT_HWCAP2); +#endif + m_status.set_bit(); + } + return m_hwcap2; + } } #endif