Vecmat 0.2.3
C math and linear algebra library for 2D/3D graphics, physics, and science.
Loading...
Searching...
No Matches
cpu.c
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025-2026 Igal Alkon
2// SPDX-FileCopyrightText: 2026 ALKONTEK <git@alkontek.com>
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <vecmat.h>
6
7#if defined(__x86_64__) || defined(_M_X64) || defined(__amd64__) || \
8 defined(__i386__) || defined(_M_IX86)
9#define VECMAT_ARCH_X86 1
10#endif
11
12#if defined(__aarch64__) || defined(_M_ARM64)
13#define VECMAT_ARCH_AARCH64 1
14#endif
15
16#if defined(VECMAT_ARCH_X86)
17#if defined(_MSC_VER)
18#include <intrin.h>
19#else
20#include <cpuid.h>
21#endif
22#endif
23
24#if defined(VECMAT_ARCH_AARCH64) && defined(__linux__)
25#include <sys/auxv.h>
26#ifndef HWCAP_SVE
27#define HWCAP_SVE (1u << 22)
28#endif
29#ifndef HWCAP2_SVE2
30#define HWCAP2_SVE2 (1u << 1)
31#endif
32#endif
33
35static int runtime_cached;
36
37#if defined(VECMAT_ARCH_X86)
38#if defined(_MSC_VER)
39static int vm_cpuid(unsigned leaf, unsigned sub,
40 unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
41{
42 int regs[4];
43 __cpuidex(regs, (int)leaf, (int)sub);
44 *eax = (unsigned)regs[0];
45 *ebx = (unsigned)regs[1];
46 *ecx = (unsigned)regs[2];
47 *edx = (unsigned)regs[3];
48 return 1;
49}
50
51static unsigned vm_xgetbv(unsigned idx)
52{
53 return (unsigned)_xgetbv(idx);
54}
55#else
56static int vm_cpuid(const unsigned leaf, const unsigned sub,
57 unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
58{
59 const unsigned max = __get_cpuid_max(leaf & 0x80000000u, 0);
60 if (max < leaf)
61 return 0;
62 return (int)__get_cpuid_count(leaf, sub, eax, ebx, ecx, edx);
63}
64
65static unsigned vm_xgetbv(unsigned idx)
66{
67 unsigned eax, edx;
68 __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(idx));
69 return eax;
70}
71#endif
72
73static int vm_cpu_probe_avx(void)
74{
75 unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
76 if (!vm_cpuid(1, 0, &eax, &ebx, &ecx, &edx))
77 return 0;
78 /* OSXSAVE (27) and AVX (28) */
79 if ((ecx & (1u << 27)) == 0 || (ecx & (1u << 28)) == 0)
80 return 0;
81 return (vm_xgetbv(0) & 0x6u) == 0x6u; /* XMM+YMM state */
82}
83
84static int vm_cpu_probe_avx2(void)
85{
86 unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
87 if (!vm_cpu_probe_avx())
88 return 0;
89 if (!vm_cpuid(7, 0, &eax, &ebx, &ecx, &edx))
90 return 0;
91 return (ebx & (1u << 5)) != 0; /* AVX2 */
92}
93
94static int vm_cpu_probe_avx512f(void)
95{
96 unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
97 if (!vm_cpuid(1, 0, &eax, &ebx, &ecx, &edx))
98 return 0;
99 if ((ecx & (1u << 27)) == 0)
100 return 0;
101 /* XMM+YMM (bits 1-2) and opmask+ZMM_Hi256+Hi16_ZMM (bits 5-7) */
102 if ((vm_xgetbv(0) & 0xe6u) != 0xe6u)
103 return 0;
104 if (!vm_cpuid(7, 0, &eax, &ebx, &ecx, &edx))
105 return 0;
106 return (ebx & (1u << 16)) != 0; /* AVX512F */
107}
108#endif /* VECMAT_ARCH_X86 */
109
110static int vm_cpu_probe_sve(void)
111{
112#if defined(VECMAT_ARCH_AARCH64) && defined(__linux__)
113 return (getauxval(AT_HWCAP) & HWCAP_SVE) != 0;
114#else
115 return 0;
116#endif
117}
118
119static int vm_cpu_probe_sve2(void)
120{
121#if defined(VECMAT_ARCH_AARCH64) && defined(__linux__)
122 if (!vm_cpu_probe_sve())
123 return 0;
124 return (getauxval(AT_HWCAP2) & HWCAP2_SVE2) != 0;
125#else
126 return 0;
127#endif
128}
129
131{
133#if defined(VECMAT_ENABLE_AVX) || defined(__AVX__)
134 f |= VM_CPU_AVX;
135#endif
136#if defined(VECMAT_ENABLE_AVX2) || defined(__AVX2__)
137 f |= VM_CPU_AVX2;
138#endif
139#if defined(VECMAT_ENABLE_AVX512) || defined(__AVX512F__)
140 f |= VM_CPU_AVX512;
141#endif
142#if defined(VECMAT_ENABLE_SVE) || defined(__ARM_FEATURE_SVE)
143 f |= VM_CPU_SVE;
144#endif
145#if defined(VECMAT_ENABLE_SVE2) || defined(__ARM_FEATURE_SVE2)
146 f |= VM_CPU_SVE2;
147#endif
148 return f;
149}
150
152{
153 if (runtime_cached)
154 return runtime_cache;
155
157#if defined(VECMAT_ARCH_X86)
158 if (vm_cpu_probe_avx())
159 f |= VM_CPU_AVX;
160 if (vm_cpu_probe_avx2())
161 f |= VM_CPU_AVX2;
162 if (vm_cpu_probe_avx512f())
163 f |= VM_CPU_AVX512;
164#endif
165 if (vm_cpu_probe_sve())
166 f |= VM_CPU_SVE;
167 if (vm_cpu_probe_sve2())
168 f |= VM_CPU_SVE2;
169
170 runtime_cache = f;
171 runtime_cached = 1;
172 return f;
173}
174
176{
177 const vm_cpu_features_t have =
179
180 if (have & VM_CPU_SVE2)
181 return VM_CPU_SVE2;
182 if (have & VM_CPU_SVE)
183 return VM_CPU_SVE;
184 if (have & VM_CPU_AVX512)
185 return VM_CPU_AVX512;
186 if (have & VM_CPU_AVX2)
187 return VM_CPU_AVX2;
188 if (have & VM_CPU_AVX)
189 return VM_CPU_AVX;
190 return VM_CPU_SCALAR;
191}
192
193const char *vm_cpu_name(const vm_cpu_features_t features)
194{
195 if (features & VM_CPU_SVE2)
196 return "sve2";
197 if (features & VM_CPU_SVE)
198 return "sve";
199 if (features & VM_CPU_AVX512)
200 return "avx512";
201 if (features & VM_CPU_AVX2)
202 return "avx2";
203 if (features & VM_CPU_AVX)
204 return "avx";
205 if (features & VM_CPU_SCALAR)
206 return "scalar";
207 return "none";
208}
209
210#if !defined(VECMAT_RUNTIME_DISPATCH)
211void vm_cpu_init(void)
212{
214}
215#endif
vm_cpu_features_t vm_cpu_compiled_features(void)
Definition cpu.c:130
static int vm_cpu_probe_sve2(void)
Definition cpu.c:119
const char * vm_cpu_name(const vm_cpu_features_t features)
Definition cpu.c:193
static vm_cpu_features_t runtime_cache
Definition cpu.c:34
static int vm_cpu_probe_sve(void)
Definition cpu.c:110
static int runtime_cached
Definition cpu.c:35
vm_cpu_features_t vm_cpu_runtime_features(void)
Definition cpu.c:151
vm_cpu_features_t vm_cpu_selected_features(void)
Definition cpu.c:175
uint32_t vm_cpu_features_t
Definition vecmat.h:452
void vm_cpu_init(void)
Definition dispatch.c:77
@ VM_CPU_AVX
Definition vecmat.h:460
@ VM_CPU_SVE2
Definition vecmat.h:459
@ VM_CPU_AVX2
Definition vecmat.h:456
@ VM_CPU_SVE
Definition vecmat.h:457
@ VM_CPU_AVX512
Definition vecmat.h:458
@ VM_CPU_SCALAR
Definition vecmat.h:455