From e634c90e776f0728ccf2b58ec303eb38652947a5 Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Thu, 9 Apr 2026 10:24:39 +0200 Subject: [PATCH] Add riscv_cpu_features --- .github/workflows/cross-rvv.yml | 5 ++ .github/workflows/cross-sve.yml | 1 + .github/workflows/linux.yml | 1 + .github/workflows/macos.yml | 1 + include/xsimd/config/xsimd_config.hpp | 11 +++ .../xsimd/config/xsimd_cpu_features_arm.hpp | 11 +-- .../xsimd/config/xsimd_cpu_features_riscv.hpp | 74 +++++++++++++++++++ include/xsimd/config/xsimd_cpuid.hpp | 17 +---- test/test_cpu_features.cpp | 7 ++ 9 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 include/xsimd/config/xsimd_cpu_features_riscv.hpp diff --git a/.github/workflows/cross-rvv.yml b/.github/workflows/cross-rvv.yml index 878dada5e..cbe19c7c4 100644 --- a/.github/workflows/cross-rvv.yml +++ b/.github/workflows/cross-rvv.yml @@ -56,6 +56,11 @@ jobs: -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/.github/toolchains/${{ matrix.sys.compiler }}-riscv64-linux-gnu.cmake - name: Build run: cmake --build _build + - name: Set CPU feature test expectations + run: | + echo "XSIMD_TEST_CPU_ASSUME_SSE4_2=0" >> "$GITHUB_ENV" + echo "XSIMD_TEST_CPU_ASSUME_SVE=0" >> "$GITHUB_ENV" + echo "XSIMD_TEST_CPU_ASSUME_RVV=1" >> "$GITHUB_ENV" - name: Testing xsimd run: > QEMU_CPU="rv64,zba=true,zbb=true,zbs=true,v=true,vlen=${{ matrix.vector_bits }},elen=64,vext_spec=v1.0" diff --git a/.github/workflows/cross-sve.yml b/.github/workflows/cross-sve.yml index 3362cd7b2..8a2ffe102 100644 --- a/.github/workflows/cross-sve.yml +++ b/.github/workflows/cross-sve.yml @@ -43,6 +43,7 @@ jobs: - name: Set CPU feature test expectations run: | echo "XSIMD_TEST_CPU_ASSUME_SSE4_2=0" >> "$GITHUB_ENV" + echo "XSIMD_TEST_CPU_ASSUME_RVV=0" >> "$GITHUB_ENV" echo "XSIMD_TEST_CPU_ASSUME_NEON64=1" >> "$GITHUB_ENV" echo "XSIMD_TEST_CPU_ASSUME_SVE=1" >> "$GITHUB_ENV" echo "XSIMD_TEST_CPU_ASSUME_MANUFACTURER=unknown" >> "$GITHUB_ENV" diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index bb43bb19f..4585ae3b9 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -122,6 +122,7 @@ jobs: run: | # Set CPU feature test expectations, 0 is explicit absence of the feature export XSIMD_TEST_CPU_ASSUME_NEON64="0" + export XSIMD_TEST_CPU_ASSUME_RVV="0" cd _build/test if echo '${{ matrix.sys.flags }}' | grep -q 'avx512' ; then # Running with emulation, must have AVX512, lower tier are checked by implications in tests diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index af0a59ac7..14132f5db 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -24,6 +24,7 @@ jobs: run: cmake --build _build --target xbenchmark --verbose - name: Set CPU feature test expectations run: | + echo "XSIMD_TEST_CPU_ASSUME_RVV=0" >> "$GITHUB_ENV" if echo '${{ matrix.os }}' | grep -q intel; then echo "XSIMD_TEST_CPU_ASSUME_NEON64=0" >> "$GITHUB_ENV" echo "XSIMD_TEST_CPU_ASSUME_SSE4_2=1" >> "$GITHUB_ENV" diff --git a/include/xsimd/config/xsimd_config.hpp b/include/xsimd/config/xsimd_config.hpp index 1aa7e3a22..662e550ff 100644 --- a/include/xsimd/config/xsimd_config.hpp +++ b/include/xsimd/config/xsimd_config.hpp @@ -464,6 +464,17 @@ #define XSIMD_SVE_BITS 0 #endif +/** + * @ingroup xsimd_config_macro + * + * Set to 1 if the target is the RISC-V architecture family. + */ +#ifdef __riscv +#define XSIMD_TARGET_RISCV 1 +#else +#define XSIMD_TARGET_RISCV 0 +#endif + /** * @ingroup xsimd_config_macro * diff --git a/include/xsimd/config/xsimd_cpu_features_arm.hpp b/include/xsimd/config/xsimd_cpu_features_arm.hpp index 63086ccdc..d52a8a219 100644 --- a/include/xsimd/config/xsimd_cpu_features_arm.hpp +++ b/include/xsimd/config/xsimd_cpu_features_arm.hpp @@ -22,11 +22,6 @@ // Header does not exists on all architectures and masks are architecture // specific. #include - -// 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 @@ -71,8 +66,14 @@ namespace xsimd inline bool i8mm() const noexcept { + #if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL +#ifdef HWCAP2_I8MM return hwcap2().has_feature(HWCAP2_I8MM); +#else + // Possibly missing on older Linux distributions + return hwcap2().has_feature(1 << 13); +#endif #else return false; #endif diff --git a/include/xsimd/config/xsimd_cpu_features_riscv.hpp b/include/xsimd/config/xsimd_cpu_features_riscv.hpp new file mode 100644 index 000000000..2520a249e --- /dev/null +++ b/include/xsimd/config/xsimd_cpu_features_riscv.hpp @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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_RISCV_HPP +#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" + +// HWCAP_XXX masks to use on getauxval results. +// Header does not exists on all architectures and masks are architecture +// specific. +#include +#endif // XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL + +namespace xsimd +{ + class riscv_cpu_features + { + public: + riscv_cpu_features() noexcept = default; + + inline bool rvv() const noexcept + { +#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL +#ifdef HWCAP_V + return hwcap().has_feature(HWCAP_V); +#else + // 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; + } +#endif + }; +} + +#endif diff --git a/include/xsimd/config/xsimd_cpuid.hpp b/include/xsimd/config/xsimd_cpuid.hpp index 4be659709..5ac798437 100644 --- a/include/xsimd/config/xsimd_cpuid.hpp +++ b/include/xsimd/config/xsimd_cpuid.hpp @@ -14,14 +14,10 @@ #include "../types/xsimd_all_registers.hpp" #include "./xsimd_cpu_features_arm.hpp" +#include "./xsimd_cpu_features_riscv.hpp" #include "./xsimd_cpu_features_x86.hpp" #include "./xsimd_inline.hpp" -#if XSIMD_HAVE_LINUX_GETAUXVAL && defined(__riscv_vector) -#include -#include -#endif - namespace xsimd { namespace detail @@ -88,15 +84,10 @@ namespace xsimd vsx = 1; #endif -#if XSIMD_HAVE_LINUX_GETAUXVAL -#if defined(__riscv_vector) && defined(__riscv_v_fixed_vlen) && __riscv_v_fixed_vlen > 0 + // Safe on all platforms, it will be all false if non risc-v. + const auto riscv_cpu = xsimd::riscv_cpu_features(); -#ifndef HWCAP_V -#define HWCAP_V (1 << ('V' - 'A')) -#endif - rvv = bool(getauxval(AT_HWCAP) & HWCAP_V); -#endif -#endif + rvv = riscv_cpu.rvv(); // Safe on all platforms, it will be all false if non arm. const auto arm_cpu = xsimd::arm_cpu_features(); diff --git a/test/test_cpu_features.cpp b/test/test_cpu_features.cpp index d16de56dc..9461210f5 100644 --- a/test/test_cpu_features.cpp +++ b/test/test_cpu_features.cpp @@ -154,3 +154,10 @@ TEST_CASE("[cpu_features] arm features from environment") CHECK_ENV_FEATURE("XSIMD_TEST_CPU_ASSUME_SVE", cpu.sve()); CHECK_ENV_FEATURE("XSIMD_TEST_CPU_ASSUME_I8MM", cpu.i8mm()); } + +TEST_CASE("[cpu_features] risc-v features from environment") +{ + xsimd::riscv_cpu_features cpu; + + CHECK_ENV_FEATURE("XSIMD_TEST_CPU_ASSUME_RVV", cpu.rvv()); +}