Skip to content

Commit 2293695

Browse files
authored
Merge pull request #1301 from AntoinePrv/getauxval-backend
Nicer factoring of getauxval based cpu features
2 parents 47b10f3 + 2db459a commit 2293695

File tree

3 files changed

+115
-104
lines changed

3 files changed

+115
-104
lines changed

include/xsimd/config/xsimd_cpu_features_arm.hpp

Lines changed: 32 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313
#define XSIMD_CPU_FEATURES_ARM_HPP
1414

1515
#include "./xsimd_config.hpp"
16-
17-
#if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL
18-
#include "../utils/bits.hpp"
1916
#include "./xsimd_getauxval.hpp"
2017

18+
#if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL
2119
// HWCAP_XXX masks to use on getauxval results.
2220
// Header does not exists on all architectures and masks are architecture
2321
// specific.
@@ -36,87 +34,54 @@ namespace xsimd
3634
* This is well defined on all architectures.
3735
* It will always return false on non-ARM architectures.
3836
*/
39-
class arm_cpu_features
37+
class arm_cpu_features : private linux_hwcap_backend_default
4038
{
4139
public:
42-
arm_cpu_features() noexcept = default;
40+
inline bool neon() const noexcept;
41+
inline bool neon64() const noexcept;
42+
inline bool sve() const noexcept;
43+
inline bool i8mm() const noexcept;
44+
};
45+
46+
/********************
47+
* Implementation *
48+
********************/
4349

44-
inline bool neon() const noexcept
45-
{
50+
inline bool arm_cpu_features::neon() const noexcept
51+
{
4652
#if XSIMD_TARGET_ARM && !XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
47-
return hwcap().has_feature(HWCAP_NEON);
53+
return hwcap().has_feature(HWCAP_NEON);
4854
#else
49-
return static_cast<bool>(XSIMD_WITH_NEON);
55+
return static_cast<bool>(XSIMD_WITH_NEON);
5056
#endif
51-
}
57+
}
5258

53-
constexpr bool neon64() const noexcept
54-
{
55-
return static_cast<bool>(XSIMD_WITH_NEON64);
56-
}
59+
inline bool arm_cpu_features::neon64() const noexcept
60+
{
61+
return static_cast<bool>(XSIMD_WITH_NEON64);
62+
}
5763

58-
inline bool sve() const noexcept
59-
{
64+
inline bool arm_cpu_features::sve() const noexcept
65+
{
6066
#if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
61-
return hwcap().has_feature(HWCAP_SVE);
67+
return hwcap().has_feature(HWCAP_SVE);
6268
#else
63-
return false;
69+
return false;
6470
#endif
65-
}
66-
67-
inline bool i8mm() const noexcept
68-
{
71+
}
6972

73+
inline bool arm_cpu_features::i8mm() const noexcept
74+
{
7075
#if XSIMD_TARGET_ARM64 && XSIMD_HAVE_LINUX_GETAUXVAL
7176
#ifdef HWCAP2_I8MM
72-
return hwcap2().has_feature(HWCAP2_I8MM);
77+
return hwcap2().has_feature(HWCAP2_I8MM);
7378
#else
74-
// Possibly missing on older Linux distributions
75-
return hwcap2().has_feature(1 << 13);
79+
// Possibly missing on older Linux distributions
80+
return hwcap2().has_feature(1 << 13);
7681
#endif
7782
#else
78-
return false;
83+
return false;
7984
#endif
80-
}
81-
82-
private:
83-
#if XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL
84-
enum class status
85-
{
86-
hwcap_valid = 0,
87-
hwcap2_valid = 1,
88-
};
89-
90-
using status_bitset = utils::uint_bitset<status, std::uint32_t>;
91-
92-
mutable status_bitset m_status {};
93-
94-
mutable xsimd::linux_auxval m_hwcap {};
95-
96-
inline xsimd::linux_auxval const& hwcap() const noexcept
97-
{
98-
if (!m_status.bit_is_set<status::hwcap_valid>())
99-
{
100-
m_hwcap = xsimd::linux_auxval::read(AT_HWCAP);
101-
m_status.set_bit<status::hwcap_valid>();
102-
}
103-
return m_hwcap;
104-
}
105-
106-
#if XSIMD_TARGET_ARM64
107-
mutable xsimd::linux_auxval m_hwcap2 {};
108-
109-
inline xsimd::linux_auxval const& hwcap2() const noexcept
110-
{
111-
if (!m_status.bit_is_set<status::hwcap2_valid>())
112-
{
113-
m_hwcap2 = xsimd::linux_auxval::read(AT_HWCAP2);
114-
m_status.set_bit<status::hwcap2_valid>();
115-
}
116-
return m_hwcap2;
117-
}
118-
#endif
119-
#endif // XSIMD_TARGET_ARM && XSIMD_HAVE_LINUX_GETAUXVAL
120-
};
85+
}
12186
}
12287
#endif

include/xsimd/config/xsimd_cpu_features_riscv.hpp

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313
#define XSIMD_CPU_FEATURES_RISCV_HPP
1414

1515
#include "./xsimd_config.hpp"
16-
17-
#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL
18-
#include "../utils/bits.hpp"
1916
#include "./xsimd_getauxval.hpp"
2017

18+
#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL
2119
// HWCAP_XXX masks to use on getauxval results.
2220
// Header does not exists on all architectures and masks are architecture
2321
// specific.
@@ -26,49 +24,29 @@
2624

2725
namespace xsimd
2826
{
29-
class riscv_cpu_features
27+
class riscv_cpu_features : private linux_hwcap_backend_default
3028
{
3129
public:
32-
riscv_cpu_features() noexcept = default;
30+
inline bool rvv() const noexcept;
31+
};
3332

34-
inline bool rvv() const noexcept
35-
{
33+
/********************
34+
* Implementation *
35+
********************/
36+
37+
inline bool riscv_cpu_features::rvv() const noexcept
38+
{
3639
#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL
3740
#ifdef HWCAP_V
38-
return hwcap().has_feature(HWCAP_V);
41+
return hwcap().has_feature(HWCAP_V);
3942
#else
40-
// Possibly missing on older Linux distributions
41-
return hwcap().has_feature(1 << ('V' - 'A'));
43+
// Possibly missing on older Linux distributions
44+
return hwcap().has_feature(1 << ('V' - 'A'));
4245
#endif
4346
#else
44-
return false;
45-
#endif
46-
}
47-
48-
private:
49-
#if XSIMD_TARGET_RISCV && XSIMD_HAVE_LINUX_GETAUXVAL
50-
enum class status
51-
{
52-
hwcap_valid = 0,
53-
};
54-
55-
using status_bitset = utils::uint_bitset<status, std::uint32_t>;
56-
57-
mutable status_bitset m_status {};
58-
59-
mutable xsimd::linux_auxval m_hwcap {};
60-
61-
inline xsimd::linux_auxval const& hwcap() const noexcept
62-
{
63-
if (!m_status.bit_is_set<status::hwcap_valid>())
64-
{
65-
m_hwcap = xsimd::linux_auxval::read(AT_HWCAP);
66-
m_status.set_bit<status::hwcap_valid>();
67-
}
68-
return m_hwcap;
69-
}
47+
return false;
7048
#endif
71-
};
49+
}
7250
}
7351

7452
#endif

include/xsimd/config/xsimd_getauxval.hpp

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

15+
#include "../utils/bits.hpp"
1516
#include "./xsimd_config.hpp"
1617

1718
#if XSIMD_HAVE_LINUX_GETAUXVAL
@@ -68,6 +69,49 @@ namespace xsimd
6869
}
6970
};
7071

72+
class linux_hwcap_backend
73+
{
74+
public:
75+
inline linux_auxval hwcap() const noexcept;
76+
77+
inline linux_auxval hwcap2() const noexcept;
78+
79+
private:
80+
enum class status
81+
{
82+
hwcap_valid = 0,
83+
hwcap2_valid = 1,
84+
};
85+
86+
using status_bitset = utils::uint_bitset<status, std::uint32_t>;
87+
88+
mutable status_bitset m_status {};
89+
mutable xsimd::linux_auxval m_hwcap {};
90+
mutable xsimd::linux_auxval m_hwcap2 {};
91+
};
92+
93+
class linux_hwcap_backend_noop
94+
{
95+
public:
96+
inline linux_auxval hwcap() const noexcept { return {}; }
97+
98+
inline linux_auxval hwcap2() const noexcept { return {}; }
99+
};
100+
101+
#if XSIMD_HAVE_LINUX_GETAUXVAL
102+
using linux_hwcap_backend_default = linux_hwcap_backend;
103+
#else
104+
// Contrary to CPUID that is only used on one architecture, HWCAP are
105+
// available on multiple architectures with different meaning for the
106+
// different bit fields.
107+
// We use the Linux `HWCAP` constants directly to avoid repetition, so
108+
// we could not use a default implementation without already being on
109+
// Linux anyways.
110+
struct linux_hwcap_backend_default
111+
{
112+
};
113+
#endif
114+
71115
/********************
72116
* Implementation *
73117
********************/
@@ -86,6 +130,30 @@ namespace xsimd
86130
}
87131
#endif
88132
}
133+
134+
inline linux_auxval linux_hwcap_backend::hwcap() const noexcept
135+
{
136+
if (!m_status.bit_is_set<status::hwcap_valid>())
137+
{
138+
#if XSIMD_HAVE_LINUX_GETAUXVAL
139+
m_hwcap = linux_auxval::read(AT_HWCAP);
140+
#endif
141+
m_status.set_bit<status::hwcap_valid>();
142+
}
143+
return m_hwcap;
144+
}
145+
146+
inline linux_auxval linux_hwcap_backend::hwcap2() const noexcept
147+
{
148+
if (!m_status.bit_is_set<status::hwcap2_valid>())
149+
{
150+
#if XSIMD_HAVE_LINUX_GETAUXVAL
151+
m_hwcap2 = linux_auxval::read(AT_HWCAP2);
152+
#endif
153+
m_status.set_bit<status::hwcap2_valid>();
154+
}
155+
return m_hwcap2;
156+
}
89157
}
90158

91159
#endif

0 commit comments

Comments
 (0)