PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
simd_config.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
17#ifndef PACS_ENCODING_SIMD_CONFIG_HPP
18#define PACS_ENCODING_SIMD_CONFIG_HPP
19
20#include <cstddef>
21#include <cstdint>
22
23// Platform detection
24#if defined(_MSC_VER)
25 #define PACS_COMPILER_MSVC 1
26#elif defined(__clang__)
27 #define PACS_COMPILER_CLANG 1
28#elif defined(__GNUC__)
29 #define PACS_COMPILER_GCC 1
30#endif
31
32// Architecture detection
33#if defined(__x86_64__) || defined(_M_X64)
34 #define PACS_ARCH_X64 1
35#elif defined(__i386__) || defined(_M_IX86)
36 #define PACS_ARCH_X86 1
37#elif defined(__aarch64__) || defined(_M_ARM64)
38 #define PACS_ARCH_ARM64 1
39#elif defined(__arm__) || defined(_M_ARM)
40 #define PACS_ARCH_ARM32 1
41#endif
42
43// SIMD feature detection (compile-time)
44#if defined(PACS_ARCH_X64) || defined(PACS_ARCH_X86)
45 #if defined(__AVX512F__)
46 #define PACS_SIMD_AVX512 1
47 #endif
48 #if defined(__AVX2__)
49 #define PACS_SIMD_AVX2 1
50 #endif
51 #if defined(__AVX__)
52 #define PACS_SIMD_AVX 1
53 #endif
54 #if defined(__SSE4_1__)
55 #define PACS_SIMD_SSE41 1
56 #endif
57 #if defined(__SSSE3__)
58 #define PACS_SIMD_SSSE3 1
59 #endif
60 #if defined(__SSE2__) || defined(_M_X64)
61 #define PACS_SIMD_SSE2 1
62 #endif
63#elif defined(PACS_ARCH_ARM64) || defined(PACS_ARCH_ARM32)
64 #if defined(__ARM_NEON) || defined(__ARM_NEON__)
65 #define PACS_SIMD_NEON 1
66 #endif
67#endif
68
69// Include appropriate intrinsics headers
70#if defined(PACS_SIMD_AVX512) || defined(PACS_SIMD_AVX2) || \
71 defined(PACS_SIMD_AVX) || defined(PACS_SIMD_SSE41) || \
72 defined(PACS_SIMD_SSSE3) || defined(PACS_SIMD_SSE2)
73 #if defined(PACS_COMPILER_MSVC)
74 #include <intrin.h>
75 #else
76 #include <x86intrin.h>
77 #endif
78#elif defined(PACS_SIMD_NEON)
79 #include <arm_neon.h>
80#endif
81
83
87enum class simd_feature : uint32_t {
88 none = 0,
89 sse2 = 1 << 0,
90 ssse3 = 1 << 1,
91 sse41 = 1 << 2,
92 avx = 1 << 3,
93 avx2 = 1 << 4,
94 avx512f = 1 << 5,
95 neon = 1 << 6
96};
97
101[[nodiscard]] constexpr simd_feature operator|(simd_feature a,
102 simd_feature b) noexcept {
103 return static_cast<simd_feature>(static_cast<uint32_t>(a) |
104 static_cast<uint32_t>(b));
105}
106
110[[nodiscard]] constexpr simd_feature operator&(simd_feature a,
111 simd_feature b) noexcept {
112 return static_cast<simd_feature>(static_cast<uint32_t>(a) &
113 static_cast<uint32_t>(b));
114}
115
119[[nodiscard]] constexpr bool has_feature(simd_feature features,
120 simd_feature check) noexcept {
121 return (features & check) == check;
122}
123
124namespace detail {
125
126#if defined(PACS_ARCH_X64) || defined(PACS_ARCH_X86)
127
131inline void cpuid(int info[4], int function_id) noexcept {
132#if defined(PACS_COMPILER_MSVC)
133 __cpuid(info, function_id);
134#else
135 __asm__ __volatile__(
136 "cpuid"
137 : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
138 : "a"(function_id), "c"(0));
139#endif
140}
141
145inline void cpuid_ex(int info[4], int function_id, int sub_function) noexcept {
146#if defined(PACS_COMPILER_MSVC)
147 __cpuidex(info, function_id, sub_function);
148#else
149 __asm__ __volatile__(
150 "cpuid"
151 : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
152 : "a"(function_id), "c"(sub_function));
153#endif
154}
155
156#endif // x86/x64
157
158} // namespace detail
159
164[[nodiscard]] inline simd_feature detect_features() noexcept {
166
167#if defined(PACS_ARCH_X64) || defined(PACS_ARCH_X86)
168 int info[4] = {0};
169
170 // Check basic CPUID
171 detail::cpuid(info, 0);
172 int max_function = info[0];
173
174 if (max_function >= 1) {
175 detail::cpuid(info, 1);
176
177 // EDX features
178 if (info[3] & (1 << 26)) {
179 features = features | simd_feature::sse2;
180 }
181
182 // ECX features
183 if (info[2] & (1 << 0)) {
184 features = features | simd_feature::ssse3;
185 }
186 if (info[2] & (1 << 19)) {
187 features = features | simd_feature::sse41;
188 }
189 if (info[2] & (1 << 28)) {
190 features = features | simd_feature::avx;
191 }
192 }
193
194 if (max_function >= 7) {
195 detail::cpuid_ex(info, 7, 0);
196
197 // EBX features
198 if (info[1] & (1 << 5)) {
199 features = features | simd_feature::avx2;
200 }
201 if (info[1] & (1 << 16)) {
202 features = features | simd_feature::avx512f;
203 }
204 }
205
206#elif defined(PACS_ARCH_ARM64)
207 // ARM64 always has NEON
208 features = features | simd_feature::neon;
209
210#elif defined(PACS_ARCH_ARM32)
211 // ARM32: Check for NEON via auxiliary vector or runtime detection
212 // For simplicity, assume NEON is available if compiled with NEON support
213#if defined(PACS_SIMD_NEON)
214 features = features | simd_feature::neon;
215#endif
216
217#endif // Architecture
218
219 return features;
220}
221
226[[nodiscard]] inline simd_feature get_features() noexcept {
227 static const simd_feature features = detect_features();
228 return features;
229}
230
234[[nodiscard]] inline bool has_sse2() noexcept {
236}
237
241[[nodiscard]] inline bool has_ssse3() noexcept {
243}
244
248[[nodiscard]] inline bool has_sse41() noexcept {
250}
251
255[[nodiscard]] inline bool has_avx() noexcept {
257}
258
262[[nodiscard]] inline bool has_avx2() noexcept {
264}
265
269[[nodiscard]] inline bool has_avx512f() noexcept {
271}
272
276[[nodiscard]] inline bool has_neon() noexcept {
278}
279
284[[nodiscard]] inline size_t optimal_vector_width() noexcept {
285 if (has_avx512f()) {
286 return 64;
287 }
288 if (has_avx2()) {
289 return 32;
290 }
291 if (has_sse2() || has_neon()) {
292 return 16;
293 }
294 return 0; // No SIMD
295}
296
297} // namespace kcenon::pacs::encoding::simd
298
299#endif // PACS_ENCODING_SIMD_CONFIG_HPP
size_t optimal_vector_width() noexcept
Get optimal vector width in bytes for current CPU.
bool has_neon() noexcept
Check if NEON is available.
bool has_sse2() noexcept
Check if SSE2 is available.
constexpr bool has_feature(simd_feature features, simd_feature check) noexcept
Check if a specific feature is set.
simd_feature detect_features() noexcept
Detect available SIMD features at runtime.
constexpr simd_feature operator&(simd_feature a, simd_feature b) noexcept
Bitwise AND for simd_feature flags.
bool has_avx2() noexcept
Check if AVX2 is available.
bool has_ssse3() noexcept
Check if SSSE3 is available.
simd_feature get_features() noexcept
Get cached SIMD features (singleton pattern)
bool has_avx() noexcept
Check if AVX is available.
bool has_avx512f() noexcept
Check if AVX-512F is available.
constexpr simd_feature operator|(simd_feature a, simd_feature b) noexcept
Bitwise OR for simd_feature flags.
bool has_sse41() noexcept
Check if SSE4.1 is available.
simd_feature
SIMD feature flags for runtime detection.
Definition simd_config.h:87