Skip to content

Commit 2b80376

Browse files
committed
Simplify linux_auxval
1 parent e1d374f commit 2b80376

File tree

2 files changed

+49
-86
lines changed

2 files changed

+49
-86
lines changed

include/xsimd/config/xsimd_cpu_features_arm.hpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,20 @@
1414

1515
#include "./xsimd_config.hpp"
1616

17-
#if XSIMD_WITH_LINUX_GETAUXVAL
17+
#if XSIMD_TARGET_ARM && XSIMD_WITH_LINUX_GETAUXVAL
18+
#include "../utils/bits.hpp"
1819
#include "./xsimd_getauxval.hpp"
20+
21+
// HWCAP_XXX masks to use on getauxval results.
22+
// Header does not exists on all architectures and masks are architecture
23+
// specific.
24+
#include <asm/hwcap.h>
25+
26+
// Port possibly missing mask. Should only be defined on Arm64.
27+
#if XSIMD_TARGET_ARM64 && !defined(HWCAP2_I8MM)
28+
#define HWCAP2_I8MM (1 << 13)
1929
#endif
30+
#endif // XSIMD_TARGET_ARM && XSIMD_WITH_LINUX_GETAUXVAL
2031

2132
namespace xsimd
2233
{
@@ -27,8 +38,8 @@ namespace xsimd
2738
* On Linux, runtime detection uses getauxval to query the auxiliary vector.
2839
* On other platforms, only compile-time information is used.
2940
*
30-
* This is well defined on all architectures. It will always return false on
31-
* non-ARM architectures.
41+
* This is well defined on all architectures.
42+
* It will always return false on non-ARM architectures.
3243
*/
3344
class arm_cpu_features
3445
{
@@ -38,7 +49,7 @@ namespace xsimd
3849
inline bool neon() const noexcept
3950
{
4051
#if XSIMD_TARGET_ARM && !XSIMD_TARGET_ARM64 && XSIMD_WITH_LINUX_GETAUXVAL
41-
return hwcap().all_bits_set<linux_hwcap::aux::neon>();
52+
return hwcap().has_feature(HWCAP_NEON);
4253
#else
4354
return static_cast<bool>(XSIMD_WITH_NEON);
4455
#endif
@@ -52,7 +63,7 @@ namespace xsimd
5263
inline bool sve() const noexcept
5364
{
5465
#if XSIMD_TARGET_ARM64 && XSIMD_WITH_LINUX_GETAUXVAL
55-
return hwcap().all_bits_set<linux_hwcap::aux::sve>();
66+
return hwcap().has_feature(HWCAP_SVE);
5667
#else
5768
return false;
5869
#endif
@@ -61,7 +72,7 @@ namespace xsimd
6172
inline bool i8mm() const noexcept
6273
{
6374
#if XSIMD_TARGET_ARM64 && XSIMD_WITH_LINUX_GETAUXVAL
64-
return hwcap2().all_bits_set<linux_hwcap2::aux::i8mm>();
75+
return hwcap2().has_feature(HWCAP2_I8MM);
6576
#else
6677
return false;
6778
#endif
@@ -79,26 +90,26 @@ namespace xsimd
7990

8091
mutable status_bitset m_status {};
8192

82-
mutable xsimd::linux_hwcap m_hwcap {};
93+
mutable xsimd::linux_auxval m_hwcap {};
8394

84-
inline xsimd::linux_hwcap const& hwcap() const noexcept
95+
inline xsimd::linux_auxval const& hwcap() const noexcept
8596
{
8697
if (!m_status.bit_is_set<status::hwcap_valid>())
8798
{
88-
m_hwcap = xsimd::linux_hwcap::read();
99+
m_hwcap = xsimd::linux_auxval::read(AT_HWCAP);
89100
m_status.set_bit<status::hwcap_valid>();
90101
}
91102
return m_hwcap;
92103
}
93104

94105
#if XSIMD_TARGET_ARM64
95-
mutable xsimd::linux_hwcap2 m_hwcap2 {};
106+
mutable xsimd::linux_auxval m_hwcap2 {};
96107

97-
inline xsimd::linux_hwcap2 const& hwcap2() const noexcept
108+
inline xsimd::linux_auxval const& hwcap2() const noexcept
98109
{
99110
if (!m_status.bit_is_set<status::hwcap2_valid>())
100111
{
101-
m_hwcap2 = xsimd::linux_hwcap2::read();
112+
m_hwcap2 = xsimd::linux_auxval::read(AT_HWCAP2);
102113
m_status.set_bit<status::hwcap2_valid>();
103114
}
104115
return m_hwcap2;

include/xsimd/config/xsimd_getauxval.hpp

Lines changed: 26 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#ifndef XSIMD_GETAUXVAL_HPP
1313
#define XSIMD_GETAUXVAL_HPP
1414

15-
#include "../utils/bits.hpp"
1615
#include "./xsimd_config.hpp"
1716

1817
#if XSIMD_WITH_LINUX_GETAUXVAL
@@ -26,96 +25,49 @@ namespace xsimd
2625
using linux_getauxval_t = unsigned long;
2726

2827
inline linux_getauxval_t linux_getauxval(linux_getauxval_t type) noexcept;
29-
30-
/**
31-
* Base class for getauxval querying.
32-
*/
33-
template <linux_getauxval_t type, typename A>
34-
class linux_auxval : private utils::uint_bitset<A, linux_getauxval_t>
35-
{
36-
using bitset_t = utils::uint_bitset<A, linux_getauxval_t>;
37-
using bitset_t::bitset_t;
38-
39-
public:
40-
using aux = A;
41-
42-
inline static linux_auxval read()
43-
{
44-
return linux_auxval(linux_getauxval(type));
45-
}
46-
47-
/** Create a value which returns false to everything. */
48-
constexpr linux_auxval() noexcept = default;
49-
50-
using bitset_t::all_bits_set;
51-
};
52-
53-
template <typename Traits>
54-
using make_auxiliary_val_t = linux_auxval<Traits::type, typename Traits::aux>;
5528
}
5629

5730
/*
58-
* Hardware Capabilities Register (HWCAP) for Linux.
31+
* Holds the value of a Linux auxiliary vector entry (e.g. AT_HWCAP).
5932
*
6033
* On Linux systems, the kernel exposes some CPU features through the
6134
* auxiliary vector, which can be queried via `getauxval(AT_HWCAP)`.
62-
* This utility parses such bit values.
35+
* Well defined on all platforms, and will return always falsw on
36+
* non-linux platforms.
37+
*
38+
* Usage:
39+
* auto hwcap = linux_auxval::read(AT_HWCAP);
40+
* bool neon = hwcap.has_feature(HWCAP_NEON);
6341
*
6442
* @see https://www.kernel.org/doc/Documentation/arm64/elf_hwcaps.txt
6543
*/
66-
struct linux_hwcap_traits
44+
class linux_auxval
6745
{
68-
#if XSIMD_WITH_LINUX_GETAUXVAL
69-
static constexpr detail::linux_getauxval_t type = AT_HWCAP;
70-
#else
71-
static constexpr detail::linux_getauxval_t type = 0;
72-
#endif
46+
private:
47+
using getauxval_t = detail::linux_getauxval_t;
7348

74-
enum class aux
49+
public:
50+
constexpr linux_auxval() noexcept = default;
51+
52+
inline static linux_auxval read(getauxval_t type) noexcept
7553
{
76-
#if XSIMD_WITH_LINUX_GETAUXVAL
77-
#if XSIMD_TARGET_ARM64
78-
/** Scalable Vector Extension. */
79-
sve = 22,
80-
#elif XSIMD_TARGET_ARM
81-
/** Neon vector extension. */
82-
neon = 12,
83-
#endif
84-
#endif
85-
};
86-
};
54+
return linux_auxval(detail::linux_getauxval(type));
55+
}
8756

88-
using linux_hwcap = detail::make_auxiliary_val_t<linux_hwcap_traits>;
57+
constexpr bool has_feature(getauxval_t feat) const noexcept
58+
{
59+
return (m_auxval & feat) == feat;
60+
}
8961

90-
/*
91-
* Extended Hardware Capabilities Register (HWCAP2) for Linux.
92-
*
93-
* On Linux systems, the kernel exposes some CPU additional features through the
94-
* auxiliary vector, which can be queried via `getauxval(AT_HWCAP2)`.
95-
*
96-
* @see https://www.kernel.org/doc/Documentation/arm64/elf_hwcaps.txt
97-
*/
98-
struct linux_hwcap2_traits
99-
{
100-
#if XSIMD_WITH_LINUX_GETAUXVAL
101-
static constexpr detail::linux_getauxval_t type = AT_HWCAP2;
102-
#else
103-
static constexpr detail::linux_getauxval_t type = 0;
104-
#endif
62+
private:
63+
getauxval_t m_auxval = {};
10564

106-
enum class aux
65+
constexpr explicit linux_auxval(getauxval_t v) noexcept
66+
: m_auxval(v)
10767
{
108-
#if XSIMD_WITH_LINUX_GETAUXVAL
109-
#if XSIMD_TARGET_ARM64
110-
/** 8 bits integer matrix multiplication. */
111-
i8mm = 13,
112-
#endif
113-
#endif
114-
};
68+
}
11569
};
11670

117-
using linux_hwcap2 = detail::make_auxiliary_val_t<linux_hwcap2_traits>;
118-
11971
/********************
12072
* Implementation *
12173
********************/
@@ -128,7 +80,7 @@ namespace xsimd
12880
return getauxval(type);
12981
}
13082
#else
131-
inline linux_getauxval_t linux_getauxval(linux_getauxval_t type) noexcept
83+
inline linux_getauxval_t linux_getauxval(linux_getauxval_t) noexcept
13284
{
13385
return {}; // All bits set to 0
13486
}

0 commit comments

Comments
 (0)