KleidiCV Coverage Report


Directory: ./
File: kleidicv/include/kleidicv/dispatch.h
Date: 2025-09-25 14:13:34
Exec Total Coverage
Lines: 8 8 100.0%
Functions: 3 3 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2023 - 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 #ifndef KLEIDICV_DISPATCH_H
6 #define KLEIDICV_DISPATCH_H
7
8 #include "kleidicv/config.h"
9
10 #if KLEIDICV_ENABLE_SME2 || KLEIDICV_ENABLE_SME || KLEIDICV_ENABLE_SVE2
11
12 #include <cstdint>
13 #include <type_traits>
14
15 #ifdef __APPLE__
16
17 #include <sys/sysctl.h>
18
19 namespace KLEIDICV_TARGET_NAMESPACE {
20
21 static bool query_sysctl(const char* attribute_name) {
22 uint64_t attribute_value = 0;
23 size_t max_attribute_size = sizeof(attribute_value);
24 if (sysctlbyname(attribute_name, &attribute_value, &max_attribute_size, NULL,
25 0)) {
26 return false;
27 }
28
29 return attribute_value;
30 }
31
32 #if KLEIDICV_ENABLE_SVE2
33 #define KLEIDICV_SVE2_RESOLVE(sve2_impl) \
34 if (!std::is_null_pointer_v<decltype(sve2_impl)> && \
35 KLEIDICV_TARGET_NAMESPACE::query_sysctl("hw.optional.arm.FEAT_SVE2")) { \
36 return sve2_impl; \
37 }
38 #else
39 #define KLEIDICV_SVE2_RESOLVE(x)
40 #endif // KLEIDICV_ENABLE_SVE2
41
42 #if KLEIDICV_ENABLE_SME
43 #define KLEIDICV_SME_RESOLVE(sme_impl) \
44 if (!std::is_null_pointer_v<decltype(sme_impl)> && \
45 KLEIDICV_TARGET_NAMESPACE::query_sysctl("hw.optional.arm.FEAT_SME")) { \
46 return sme_impl; \
47 }
48 #else
49 #define KLEIDICV_SME_RESOLVE(x)
50 #endif // KLEIDICV_ENABLE_SME
51
52 #if KLEIDICV_ENABLE_SME2
53 #define KLEIDICV_SME2_RESOLVE(sme2_impl) \
54 if (!std::is_null_pointer_v<decltype(sme2_impl)> && \
55 KLEIDICV_TARGET_NAMESPACE::query_sysctl("hw.optional.arm.FEAT_SME2")) { \
56 return sme2_impl; \
57 }
58 #else
59 #define KLEIDICV_SME2_RESOLVE(x)
60 #endif // KLEIDICV_ENABLE_SME2
61
62 } // namespace KLEIDICV_TARGET_NAMESPACE
63
64 #define KLEIDICV_MULTIVERSION_C_API(api_name, neon_impl, sve2_impl, sme_impl, \
65 sme2_impl) \
66 static decltype(neon_impl) api_name##_resolver() { \
67 KLEIDICV_SME2_RESOLVE(sme2_impl); \
68 KLEIDICV_SME_RESOLVE(sme_impl); \
69 KLEIDICV_SVE2_RESOLVE(sve2_impl); \
70 return neon_impl; \
71 } \
72 extern "C" { \
73 decltype(neon_impl) api_name = api_name##_resolver(); \
74 }
75
76 #else // __APPLE__
77
78 #include <sys/auxv.h>
79 namespace KLEIDICV_TARGET_NAMESPACE {
80
81 using HwCapTy = uint64_t;
82
83 struct HwCaps final {
84 HwCapTy hwcap1;
85 HwCapTy hwcap2;
86 };
87
88 456 static inline HwCaps get_hwcaps() {
89 456 return HwCaps{getauxval(AT_HWCAP), getauxval(AT_HWCAP2)};
90 }
91
92 #if KLEIDICV_ENABLE_SVE2
93 327 static inline bool hwcaps_has_sve2(HwCaps hwcaps) {
94 327 return hwcaps.hwcap2 & (1 << 1);
95 }
96
97 #define KLEIDICV_SVE2_RESOLVE(sve2_impl) \
98 if (!std::is_null_pointer_v<decltype(sve2_impl)> && \
99 KLEIDICV_TARGET_NAMESPACE::hwcaps_has_sve2(hwcaps)) { \
100 return sve2_impl; \
101 }
102 #else
103 #define KLEIDICV_SVE2_RESOLVE(x)
104 #endif // KLEIDICV_ENABLE_SVE2
105
106 #if KLEIDICV_ENABLE_SME
107 372 static inline bool hwcaps_has_sme(HwCaps hwcaps) {
108 372 const int kSMEBit = 23;
109 744 return hwcaps.hwcap2 & (1UL << kSMEBit);
110 372 }
111
112 #define KLEIDICV_SME_RESOLVE(sme_impl) \
113 if (!std::is_null_pointer_v<decltype(sme_impl)> && \
114 KLEIDICV_TARGET_NAMESPACE::hwcaps_has_sme(hwcaps)) { \
115 return sme_impl; \
116 }
117 #else
118 #define KLEIDICV_SME_RESOLVE(x)
119 #endif // KLEIDICV_ENABLE_SME
120
121 #if KLEIDICV_ENABLE_SME2
122 static inline bool hwcaps_has_sme2(HwCaps hwcaps) {
123 const int kSME2Bit = 37;
124 return hwcaps.hwcap2 & (1UL << kSME2Bit);
125 }
126
127 #define KLEIDICV_SME2_RESOLVE(sme2_impl) \
128 if (!std::is_null_pointer_v<decltype(sme2_impl)> && \
129 KLEIDICV_TARGET_NAMESPACE::hwcaps_has_sme2(hwcaps)) { \
130 return sme2_impl; \
131 }
132 #else
133 #define KLEIDICV_SME2_RESOLVE(x)
134 #endif // KLEIDICV_ENABLE_SME2
135
136 } // namespace KLEIDICV_TARGET_NAMESPACE
137
138 #define KLEIDICV_MULTIVERSION_C_API(api_name, neon_impl, sve2_impl, sme_impl, \
139 sme2_impl) \
140 static decltype(neon_impl) api_name##_resolver() { \
141 [[maybe_unused]] KLEIDICV_TARGET_NAMESPACE::HwCaps hwcaps = \
142 KLEIDICV_TARGET_NAMESPACE::get_hwcaps(); \
143 KLEIDICV_SME2_RESOLVE(sme2_impl); \
144 KLEIDICV_SME_RESOLVE(sme_impl); \
145 KLEIDICV_SVE2_RESOLVE(sve2_impl); \
146 return neon_impl; \
147 } \
148 extern "C" { \
149 decltype(neon_impl) api_name = api_name##_resolver(); \
150 }
151
152 #endif // __APPLE__
153
154 #else // KLEIDICV_HAVE_SVE2 || KLEIDICV_HAVE_SME || KLEIDICV_HAVE_SME2
155
156 #define KLEIDICV_MULTIVERSION_C_API(api_name, neon_impl, sve2_impl, sme_impl, \
157 sme2_impl) \
158 \
159 extern "C" { \
160 decltype(neon_impl) api_name = neon_impl; \
161 }
162
163 #endif // KLEIDICV_ENABLE_SME2 || KLEIDICV_ENABLE_SME || KLEIDICV_ENABLE_SVE2
164
165 #if KLEIDICV_ALWAYS_ENABLE_SME2
166 #define KLEIDICV_SME2_IMPL_IF(func) func
167 #else
168 #define KLEIDICV_SME2_IMPL_IF(func) nullptr
169 #endif // KLEIDICV_ALWAYS_ENABLE_SME2
170
171 #if KLEIDICV_ALWAYS_ENABLE_SME
172 #define KLEIDICV_SME_IMPL_IF(func) func
173 #else
174 #define KLEIDICV_SME_IMPL_IF(func) nullptr
175 #endif // KLEIDICV_ALWAYS_ENABLE_SME
176
177 #if KLEIDICV_ALWAYS_ENABLE_SVE2
178 #define KLEIDICV_SVE2_IMPL_IF(func) func
179 #else
180 #define KLEIDICV_SVE2_IMPL_IF(func) nullptr
181 #endif // KLEIDICV_ALWAYS_ENABLE_SVE2
182
183 #endif // KLEIDICV_DISPATCH_H
184