Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:37:15

0001 /***************************************************************************
0002  * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
0003  * Martin Renou                                                             *
0004  * Copyright (c) QuantStack                                                 *
0005  * Copyright (c) Serge Guelton                                              *
0006  *                                                                          *
0007  * Distributed under the terms of the BSD 3-Clause License.                 *
0008  *                                                                          *
0009  * The full license is in the file LICENSE, distributed with this software. *
0010  ***************************************************************************/
0011 
0012 #ifndef XSIMD_GETAUXVAL_HPP
0013 #define XSIMD_GETAUXVAL_HPP
0014 
0015 #include "../utils/bits.hpp"
0016 #include "./xsimd_config.hpp"
0017 
0018 #if XSIMD_HAVE_LINUX_GETAUXVAL
0019 #include <sys/auxv.h> // getauxval
0020 #endif
0021 
0022 namespace xsimd
0023 {
0024     namespace detail
0025     {
0026         using linux_getauxval_t = unsigned long;
0027 
0028         inline linux_getauxval_t linux_getauxval(linux_getauxval_t type) noexcept;
0029     }
0030 
0031     /*
0032      * Holds the value of a Linux auxiliary vector entry (e.g. AT_HWCAP).
0033      *
0034      * On Linux systems, the kernel exposes some CPU features through the
0035      * auxiliary vector, which can be queried via `getauxval(AT_HWCAP)`.
0036      * Well defined on all platforms, and will return always falsw on
0037      * non-linux platforms.
0038      *
0039      * Usage:
0040      *   auto hwcap = linux_auxval::read(AT_HWCAP);
0041      *   bool neon = hwcap.has_feature(HWCAP_NEON);
0042      *
0043      * @see https://www.kernel.org/doc/Documentation/arm64/elf_hwcaps.txt
0044      */
0045     class linux_auxval
0046     {
0047     private:
0048         using getauxval_t = detail::linux_getauxval_t;
0049 
0050     public:
0051         constexpr linux_auxval() noexcept = default;
0052 
0053         inline static linux_auxval read(getauxval_t type) noexcept
0054         {
0055             return linux_auxval(detail::linux_getauxval(type));
0056         }
0057 
0058         constexpr bool has_feature(getauxval_t feat) const noexcept
0059         {
0060             return (m_auxval & feat) == feat;
0061         }
0062 
0063     private:
0064         getauxval_t m_auxval = {};
0065 
0066         constexpr explicit linux_auxval(getauxval_t v) noexcept
0067             : m_auxval(v)
0068         {
0069         }
0070     };
0071 
0072     class linux_hwcap_backend
0073     {
0074     public:
0075         inline linux_auxval hwcap() const noexcept;
0076 
0077         inline linux_auxval hwcap2() const noexcept;
0078 
0079     private:
0080         enum class status
0081         {
0082             hwcap_valid = 0,
0083             hwcap2_valid = 1,
0084         };
0085 
0086         using status_bitset = utils::uint_bitset<status, std::uint32_t>;
0087 
0088         mutable status_bitset m_status {};
0089         mutable xsimd::linux_auxval m_hwcap {};
0090         mutable xsimd::linux_auxval m_hwcap2 {};
0091     };
0092 
0093     class linux_hwcap_backend_noop
0094     {
0095     public:
0096         inline linux_auxval hwcap() const noexcept { return {}; }
0097 
0098         inline linux_auxval hwcap2() const noexcept { return {}; }
0099     };
0100 
0101 #if XSIMD_HAVE_LINUX_GETAUXVAL
0102     using linux_hwcap_backend_default = linux_hwcap_backend;
0103 #else
0104     // Contrary to CPUID that is only used on one architecture, HWCAP are
0105     // available on multiple architectures with different meaning for the
0106     // different bit fields.
0107     // We use the Linux `HWCAP` constants directly to avoid repetition, so
0108     // we could not use a default implementation without already being on
0109     // Linux anyways.
0110     struct linux_hwcap_backend_default
0111     {
0112     };
0113 #endif
0114 
0115     /********************
0116      *  Implementation  *
0117      ********************/
0118 
0119     namespace detail
0120     {
0121 #if XSIMD_HAVE_LINUX_GETAUXVAL
0122         inline linux_getauxval_t linux_getauxval(linux_getauxval_t type) noexcept
0123         {
0124             return getauxval(type);
0125         }
0126 #else
0127         inline linux_getauxval_t linux_getauxval(linux_getauxval_t) noexcept
0128         {
0129             return {}; // All bits set to 0
0130         }
0131 #endif
0132     }
0133 
0134     inline linux_auxval linux_hwcap_backend::hwcap() const noexcept
0135     {
0136         if (!m_status.bit_is_set<status::hwcap_valid>())
0137         {
0138 #if XSIMD_HAVE_LINUX_GETAUXVAL
0139             m_hwcap = linux_auxval::read(AT_HWCAP);
0140 #endif
0141             m_status.set_bit<status::hwcap_valid>();
0142         }
0143         return m_hwcap;
0144     }
0145 
0146     inline linux_auxval linux_hwcap_backend::hwcap2() const noexcept
0147     {
0148         if (!m_status.bit_is_set<status::hwcap2_valid>())
0149         {
0150 #if XSIMD_HAVE_LINUX_GETAUXVAL
0151             m_hwcap2 = linux_auxval::read(AT_HWCAP2);
0152 #endif
0153             m_status.set_bit<status::hwcap2_valid>();
0154         }
0155         return m_hwcap2;
0156     }
0157 }
0158 
0159 #endif