-
Notifications
You must be signed in to change notification settings - Fork 299
Refactor arm detection #1272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Refactor arm detection #1272
Changes from all commits
af94d18
53c5fd5
db88312
32d6114
74ca895
e82d290
9e154af
4dfe53e
cd38ea8
e1d374f
2b80376
8826d25
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| /*************************************************************************** | ||
| * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * | ||
| * Martin Renou * | ||
| * Copyright (c) QuantStack * | ||
| * Copyright (c) Serge Guelton * | ||
| * * | ||
| * Distributed under the terms of the BSD 3-Clause License. * | ||
| * * | ||
| * The full license is in the file LICENSE, distributed with this software. * | ||
| ***************************************************************************/ | ||
|
|
||
| #ifndef XSIMD_CPU_FEATURES_ARM_HPP | ||
| #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" | ||
|
|
||
| // HWCAP_XXX masks to use on getauxval results. | ||
| // Header does not exists on all architectures and masks are architecture | ||
| // specific. | ||
| #include <asm/hwcap.h> | ||
|
|
||
| // Port possibly missing mask. Should only be defined on Arm64. | ||
| #if XSIMD_TARGET_ARM64 && !defined(HWCAP2_I8MM) | ||
| #define HWCAP2_I8MM (1 << 13) | ||
| #endif | ||
| #endif // XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL | ||
|
|
||
| namespace xsimd | ||
| { | ||
| /** | ||
| * An opinionated CPU feature detection utility for ARM. | ||
| * | ||
| * Combines compile-time knowledge with runtime detection when available. | ||
| * On Linux, runtime detection uses getauxval to query the auxiliary vector. | ||
| * On other platforms, only compile-time information is used. | ||
| * | ||
| * This is well defined on all architectures. | ||
| * It will always return false on non-ARM architectures. | ||
| */ | ||
| class arm_cpu_features | ||
| { | ||
| public: | ||
| arm_cpu_features() noexcept = default; | ||
|
|
||
| inline bool neon() const noexcept | ||
| { | ||
| #if XSIMD_TARGET_ARM && !XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL | ||
| return hwcap().has_feature(HWCAP_NEON); | ||
| #else | ||
| return static_cast<bool>(XSIMD_WITH_NEON); | ||
| #endif | ||
| } | ||
|
|
||
| constexpr bool neon64() const noexcept | ||
| { | ||
| return static_cast<bool>(XSIMD_WITH_NEON64); | ||
| } | ||
|
|
||
| inline bool sve() const noexcept | ||
| { | ||
| #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL | ||
| return hwcap().has_feature(HWCAP_SVE); | ||
| #else | ||
| return false; | ||
| #endif | ||
| } | ||
|
|
||
| inline bool i8mm() const noexcept | ||
| { | ||
| #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL | ||
| return hwcap2().has_feature(HWCAP2_I8MM); | ||
| #else | ||
| 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<status, std::uint32_t>; | ||
|
|
||
| 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<status::hwcap_valid>()) | ||
| { | ||
| m_hwcap = xsimd::linux_auxval::read(AT_HWCAP); | ||
| m_status.set_bit<status::hwcap_valid>(); | ||
| } | ||
| 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<status::hwcap2_valid>()) | ||
| { | ||
| m_hwcap2 = xsimd::linux_auxval::read(AT_HWCAP2); | ||
| m_status.set_bit<status::hwcap2_valid>(); | ||
| } | ||
| return m_hwcap2; | ||
| } | ||
| #endif | ||
| #endif // XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL | ||
| }; | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| /*************************************************************************** | ||
| * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * | ||
| * Martin Renou * | ||
| * Copyright (c) QuantStack * | ||
| * Copyright (c) Serge Guelton * | ||
| * * | ||
| * Distributed under the terms of the BSD 3-Clause License. * | ||
| * * | ||
| * The full license is in the file LICENSE, distributed with this software. * | ||
| ***************************************************************************/ | ||
|
|
||
| #ifndef XSIMD_GETAUXVAL_HPP | ||
| #define XSIMD_GETAUXVAL_HPP | ||
|
|
||
| #include "./xsimd_config.hpp" | ||
|
|
||
| #if XSIMD_HAVE_LINUX_GETAUXVAL | ||
| #include <sys/auxv.h> // getauxval | ||
| #endif | ||
|
|
||
| namespace xsimd | ||
| { | ||
| namespace detail | ||
| { | ||
| using linux_getauxval_t = unsigned long; | ||
|
|
||
| inline linux_getauxval_t linux_getauxval(linux_getauxval_t type) noexcept; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you need to forward declare this here and implement it in the bottom.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is used on line 54 (middle of the file). |
||
| } | ||
|
|
||
| /* | ||
| * Holds the value of a Linux auxiliary vector entry (e.g. AT_HWCAP). | ||
| * | ||
| * On Linux systems, the kernel exposes some CPU features through the | ||
| * auxiliary vector, which can be queried via `getauxval(AT_HWCAP)`. | ||
| * Well defined on all platforms, and will return always falsw on | ||
| * non-linux platforms. | ||
| * | ||
| * Usage: | ||
| * auto hwcap = linux_auxval::read(AT_HWCAP); | ||
| * bool neon = hwcap.has_feature(HWCAP_NEON); | ||
| * | ||
| * @see https://www.kernel.org/doc/Documentation/arm64/elf_hwcaps.txt | ||
| */ | ||
| class linux_auxval | ||
| { | ||
| private: | ||
| using getauxval_t = detail::linux_getauxval_t; | ||
|
|
||
| public: | ||
| constexpr linux_auxval() noexcept = default; | ||
|
|
||
| inline static linux_auxval read(getauxval_t type) noexcept | ||
| { | ||
| return linux_auxval(detail::linux_getauxval(type)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the extra functional cast should not be needed.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ha no this is an (explicit) constructor call |
||
| } | ||
|
|
||
| constexpr bool has_feature(getauxval_t feat) const noexcept | ||
| { | ||
| return (m_auxval & feat) == feat; | ||
| } | ||
|
|
||
| private: | ||
| getauxval_t m_auxval = {}; | ||
|
|
||
| constexpr explicit linux_auxval(getauxval_t v) noexcept | ||
| : m_auxval(v) | ||
| { | ||
| } | ||
| }; | ||
|
|
||
| /******************** | ||
| * Implementation * | ||
| ********************/ | ||
|
|
||
| namespace detail | ||
| { | ||
| #if XSIMD_HAVE_LINUX_GETAUXVAL | ||
| inline linux_getauxval_t linux_getauxval(linux_getauxval_t type) noexcept | ||
| { | ||
| return getauxval(type); | ||
| } | ||
| #else | ||
| inline linux_getauxval_t linux_getauxval(linux_getauxval_t) noexcept | ||
| { | ||
| return {}; // All bits set to 0 | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you add this
__ARM_ARCHcheck?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that the following
__ARM_ARCH >= 7was unsound if__ARM_ARCHwas not defined.