Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions include/xsimd/config/xsimd_cpu_features_arm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#ifndef XSIMD_CPU_FEATURES_ARM_HPP
#define XSIMD_CPU_FEATURES_ARM_HPP

#include <cstddef>
#include <cstdint>

#include "./xsimd_config.hpp"
#include "./xsimd_getauxval.hpp"

Expand All @@ -24,6 +27,24 @@

namespace xsimd
{

namespace detail
{
using arm_reg64_t = std::uint64_t;

/**
* Return the SVE vector length in bytes for the current thread.
*
* SVE vector length can be restricted
* Contrary to `svcntb` this does not require to be compiles with SVE, which
* should not be done in a dynamic dispatch jump function.
*
* Safety: It is the user responsibility to first make sure that SVE is
* available.
*/
inline arm_reg64_t arm_rdvl_unsafe();
}

/**
* An opinionated CPU feature detection utility for ARM.
*
Expand All @@ -40,13 +61,28 @@ namespace xsimd
inline bool neon() const noexcept;
inline bool neon64() const noexcept;
inline bool sve() const noexcept;
inline std::size_t sve_size_bytes() const noexcept;
inline bool i8mm() const noexcept;
};

/********************
* Implementation *
********************/

namespace detail
{
#if XSIMD_TARGET_ARM64 && (defined(__GNUC__) || defined(__clang__))
__attribute__((target("arch=armv8-a+sve"))) inline arm_reg64_t arm_rdvl_unsafe()
{
arm_reg64_t vl;
__asm__ volatile("rdvl %0, #1" : "=r"(vl));
return vl;
}
#else
inline arm_reg64_t arm_rdvl_unsafe() { return 0; }
#endif
}

inline bool arm_cpu_features::neon() const noexcept
{
#if XSIMD_TARGET_ARM && !XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
Expand All @@ -70,6 +106,15 @@ namespace xsimd
#endif
}

inline std::size_t arm_cpu_features::sve_size_bytes() const noexcept
{
if (sve())
{
return detail::arm_rdvl_unsafe();
}
return 0;
}

inline bool arm_cpu_features::i8mm() const noexcept
{
#if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
Expand Down
43 changes: 43 additions & 0 deletions include/xsimd/config/xsimd_cpu_features_riscv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#ifndef XSIMD_CPU_FEATURES_RISCV_HPP
#define XSIMD_CPU_FEATURES_RISCV_HPP

#include <cstddef>
#include <cstdint>

#include "./xsimd_config.hpp"
#include "./xsimd_getauxval.hpp"

Expand All @@ -24,16 +27,47 @@

namespace xsimd
{
namespace detail
{
using riscv_reg64_t = std::uint64_t;

/**
* Return the RVV vector length in bytes.
*
* This does not require to be compiles with SVE, which should not
* be done in a dynamic dispatch jump function.
*
* Safety: It is the user responsibility to first make sure that RVV is
* available.
*/
inline riscv_reg64_t riscv_csrr_unsafe();
}

class riscv_cpu_features : private linux_hwcap_backend_default
{
public:
inline bool rvv() const noexcept;
inline std::size_t rvv_size_bytes() const noexcept;
};

/********************
* Implementation *
********************/

namespace detail
{
#if XSIMD_TARGET_RISCV && (defined(__GNUC__) || defined(__clang__))
__attribute__((target("arch=+v"))) inline riscv_reg64_t riscv_csrr_unsafe()
{
riscv_reg64_t vlenb;
__asm__ volatile("csrr %0, vlenb" : "=r"(vlenb));
return vlenb;
}
#else
inline riscv_reg64_t riscv_csrr_unsafe() { return 0; }
#endif
}

inline bool riscv_cpu_features::rvv() const noexcept
{
#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL
Expand All @@ -47,6 +81,15 @@ namespace xsimd
return false;
#endif
}

inline std::size_t riscv_cpu_features::rvv_size_bytes() const noexcept
{
if (rvv())
{
return detail::riscv_csrr_unsafe();
}
return 0;
}
}

#endif
20 changes: 12 additions & 8 deletions include/xsimd/config/xsimd_cpuid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ namespace xsimd
ARCH_FIELD(neon)
ARCH_FIELD(neon64)
ARCH_FIELD_EX(i8mm<::xsimd::neon64>, i8mm_neon64)
ARCH_FIELD_EX(detail::sve<512>, sve)
ARCH_FIELD_EX_REUSE(detail::sve<256>, sve)
ARCH_FIELD_EX_REUSE(detail::sve<128>, sve)
ARCH_FIELD_EX(detail::rvv<512>, rvv)
ARCH_FIELD_EX_REUSE(detail::rvv<256>, rvv)
ARCH_FIELD_EX_REUSE(detail::rvv<128>, rvv)
ARCH_FIELD_EX(detail::sve<512>, sve512)
ARCH_FIELD_EX(detail::sve<256>, sve256)
ARCH_FIELD_EX(detail::sve<128>, sve128)
ARCH_FIELD_EX(detail::rvv<512>, rvv512)
ARCH_FIELD_EX(detail::rvv<256>, rvv256)
ARCH_FIELD_EX(detail::rvv<128>, rvv128)
ARCH_FIELD(wasm)
ARCH_FIELD(vsx)

Expand All @@ -87,15 +87,19 @@ namespace xsimd
// Safe on all platforms, it will be all false if non risc-v.
const auto riscv_cpu = xsimd::riscv_cpu_features();

rvv = riscv_cpu.rvv();
rvv128 = riscv_cpu.rvv() && (riscv_cpu.rvv_size_bytes() >= (128 / 8));
rvv256 = riscv_cpu.rvv() && (riscv_cpu.rvv_size_bytes() >= (256 / 8));
rvv512 = riscv_cpu.rvv() && (riscv_cpu.rvv_size_bytes() >= (512 / 8));

// Safe on all platforms, it will be all false if non arm.
const auto arm_cpu = xsimd::arm_cpu_features();

neon = arm_cpu.neon();
neon64 = arm_cpu.neon64();
i8mm_neon64 = arm_cpu.neon64() && arm_cpu.i8mm();
sve = arm_cpu.sve();
sve128 = arm_cpu.sve() && (arm_cpu.sve_size_bytes() >= (128 / 8));
sve256 = arm_cpu.sve() && (arm_cpu.sve_size_bytes() >= (256 / 8));
sve512 = arm_cpu.sve() && (arm_cpu.sve_size_bytes() >= (512 / 8));

// Safe on all platforms, it will be all false if non x86.
const auto x86_cpu = xsimd::x86_cpu_features();
Expand Down
8 changes: 8 additions & 0 deletions test/test_cpu_features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ TEST_CASE("[cpu_features] arm implication chains")

CHECK_IMPLICATION(cpu.neon64(), cpu.neon());
CHECK_IMPLICATION(cpu.sve(), cpu.neon64());
CHECK_IMPLICATION(cpu.sve(), cpu.sve_size_bytes() >= (128 / 8));
CHECK_IMPLICATION(cpu.i8mm(), cpu.neon64());
}

Expand All @@ -155,6 +156,13 @@ TEST_CASE("[cpu_features] arm features from environment")
CHECK_ENV_FEATURE("XSIMD_TEST_CPU_ASSUME_I8MM", cpu.i8mm());
}

TEST_CASE("[cpu_features] risc-v implication chains")
{
xsimd::riscv_cpu_features cpu;

CHECK_IMPLICATION(cpu.rvv(), cpu.rvv_size_bytes() >= (128 / 8));
}

TEST_CASE("[cpu_features] risc-v features from environment")
{
xsimd::riscv_cpu_features cpu;
Expand Down
Loading