Back to home page

EIC code displayed by LXR

 
 

    


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

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_CPU_FEATURES_ARM_HPP
0013 #define XSIMD_CPU_FEATURES_ARM_HPP
0014 
0015 #include "./xsimd_config.hpp"
0016 #include "./xsimd_getauxval.hpp"
0017 
0018 #include <cstddef>
0019 #include <cstdint>
0020 
0021 #if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL
0022 // HWCAP_XXX masks to use on getauxval results.
0023 // Header does not exists on all architectures and masks are architecture
0024 // specific.
0025 #include <asm/hwcap.h>
0026 #endif // XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL
0027 
0028 namespace xsimd
0029 {
0030 
0031     namespace detail
0032     {
0033         using arm_reg64_t = std::uint64_t;
0034 
0035         /**
0036          * Return the SVE vector length in bytes for the current thread.
0037          *
0038          * SVE vector length can be restricted
0039          * Contrary to `svcntb` this does not require to be compiles with SVE, which
0040          * should not be done in a dynamic dispatch jump function.
0041          *
0042          * Safety: It is the user responsibility to first make sure that SVE is
0043          * available.
0044          */
0045         inline arm_reg64_t arm_rdvl_unsafe();
0046     }
0047 
0048     /**
0049      * An opinionated CPU feature detection utility for ARM.
0050      *
0051      * Combines compile-time knowledge with runtime detection when available.
0052      * On Linux, runtime detection uses getauxval to query the auxiliary vector.
0053      * On other platforms, only compile-time information is used.
0054      *
0055      * This is well defined on all architectures.
0056      * It will always return false on non-ARM architectures.
0057      */
0058     class arm_cpu_features : private linux_hwcap_backend_default
0059     {
0060     public:
0061         inline bool neon() const noexcept;
0062         inline bool neon64() const noexcept;
0063         inline bool sve() const noexcept;
0064         inline std::size_t sve_size_bytes() const noexcept;
0065         inline bool i8mm() const noexcept;
0066     };
0067 
0068     /********************
0069      *  Implementation  *
0070      ********************/
0071 
0072     namespace detail
0073     {
0074 #if XSIMD_TARGET_ARM64 && (defined(__GNUC__) || defined(__clang__))
0075         __attribute__((target("arch=armv8-a+sve"))) inline arm_reg64_t arm_rdvl_unsafe()
0076         {
0077             arm_reg64_t vl;
0078             __asm__ volatile("rdvl %0, #1" : "=r"(vl));
0079             return vl;
0080         }
0081 #else
0082         inline arm_reg64_t arm_rdvl_unsafe() { return 0; }
0083 #endif
0084     }
0085 
0086     inline bool arm_cpu_features::neon() const noexcept
0087     {
0088 #if XSIMD_TARGET_ARM && !XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
0089         return hwcap().has_feature(HWCAP_NEON);
0090 #else
0091         return static_cast<bool>(XSIMD_WITH_NEON);
0092 #endif
0093     }
0094 
0095     inline bool arm_cpu_features::neon64() const noexcept
0096     {
0097         return static_cast<bool>(XSIMD_WITH_NEON64);
0098     }
0099 
0100     inline bool arm_cpu_features::sve() const noexcept
0101     {
0102 #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
0103         return hwcap().has_feature(HWCAP_SVE);
0104 #else
0105         return false;
0106 #endif
0107     }
0108 
0109     inline std::size_t arm_cpu_features::sve_size_bytes() const noexcept
0110     {
0111         if (sve())
0112         {
0113             return detail::arm_rdvl_unsafe();
0114         }
0115         return 0;
0116     }
0117 
0118     inline bool arm_cpu_features::i8mm() const noexcept
0119     {
0120 #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
0121 #ifdef HWCAP2_I8MM
0122         return hwcap2().has_feature(HWCAP2_I8MM);
0123 #else
0124         // Possibly missing on older Linux distributions
0125         return hwcap2().has_feature(1 << 13);
0126 #endif
0127 #else
0128         return false;
0129 #endif
0130     }
0131 }
0132 #endif