]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/aarch64/cpuinfo.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / aarch64 / cpuinfo.c
CommitLineData
2c200a12 1/* CPU feature detection for AArch64 architecture.
a945c346 2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
2c200a12
AC
3
4 This file is part of GCC.
5
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 This file is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
24
0cfde688
AC
25#include "common/config/aarch64/cpuinfo.h"
26
2c200a12
AC
27#if __has_include(<sys/auxv.h>)
28#include <sys/auxv.h>
29
30#if __has_include(<sys/ifunc.h>)
31#include <sys/ifunc.h>
32#else
33typedef struct __ifunc_arg_t {
34 unsigned long _size;
35 unsigned long _hwcap;
36 unsigned long _hwcap2;
37} __ifunc_arg_t;
38#endif
39
40#if __has_include(<asm/hwcap.h>)
41#include <asm/hwcap.h>
42
2c200a12
AC
43/* Architecture features used in Function Multi Versioning. */
44struct {
45 unsigned long long features;
46 /* As features grows new fields could be added. */
47} __aarch64_cpu_features __attribute__((visibility("hidden"), nocommon));
48
49#ifndef _IFUNC_ARG_HWCAP
50#define _IFUNC_ARG_HWCAP (1ULL << 62)
51#endif
52#ifndef AT_HWCAP
53#define AT_HWCAP 16
54#endif
55#ifndef HWCAP_CPUID
56#define HWCAP_CPUID (1 << 11)
57#endif
58#ifndef HWCAP_FP
59#define HWCAP_FP (1 << 0)
60#endif
61#ifndef HWCAP_ASIMD
62#define HWCAP_ASIMD (1 << 1)
63#endif
64#ifndef HWCAP_AES
65#define HWCAP_AES (1 << 3)
66#endif
67#ifndef HWCAP_PMULL
68#define HWCAP_PMULL (1 << 4)
69#endif
70#ifndef HWCAP_SHA1
71#define HWCAP_SHA1 (1 << 5)
72#endif
73#ifndef HWCAP_SHA2
74#define HWCAP_SHA2 (1 << 6)
75#endif
76#ifndef HWCAP_ATOMICS
77#define HWCAP_ATOMICS (1 << 8)
78#endif
79#ifndef HWCAP_FPHP
80#define HWCAP_FPHP (1 << 9)
81#endif
82#ifndef HWCAP_ASIMDHP
83#define HWCAP_ASIMDHP (1 << 10)
84#endif
85#ifndef HWCAP_ASIMDRDM
86#define HWCAP_ASIMDRDM (1 << 12)
87#endif
88#ifndef HWCAP_JSCVT
89#define HWCAP_JSCVT (1 << 13)
90#endif
91#ifndef HWCAP_FCMA
92#define HWCAP_FCMA (1 << 14)
93#endif
94#ifndef HWCAP_LRCPC
95#define HWCAP_LRCPC (1 << 15)
96#endif
97#ifndef HWCAP_DCPOP
98#define HWCAP_DCPOP (1 << 16)
99#endif
100#ifndef HWCAP_SHA3
101#define HWCAP_SHA3 (1 << 17)
102#endif
103#ifndef HWCAP_SM3
104#define HWCAP_SM3 (1 << 18)
105#endif
106#ifndef HWCAP_SM4
107#define HWCAP_SM4 (1 << 19)
108#endif
109#ifndef HWCAP_ASIMDDP
110#define HWCAP_ASIMDDP (1 << 20)
111#endif
112#ifndef HWCAP_SHA512
113#define HWCAP_SHA512 (1 << 21)
114#endif
115#ifndef HWCAP_SVE
116#define HWCAP_SVE (1 << 22)
117#endif
118#ifndef HWCAP_ASIMDFHM
119#define HWCAP_ASIMDFHM (1 << 23)
120#endif
121#ifndef HWCAP_DIT
122#define HWCAP_DIT (1 << 24)
123#endif
124#ifndef HWCAP_ILRCPC
125#define HWCAP_ILRCPC (1 << 26)
126#endif
127#ifndef HWCAP_FLAGM
128#define HWCAP_FLAGM (1 << 27)
129#endif
130#ifndef HWCAP_SSBS
131#define HWCAP_SSBS (1 << 28)
132#endif
133#ifndef HWCAP_SB
134#define HWCAP_SB (1 << 29)
135#endif
136
137#ifndef HWCAP2_DCPODP
138#define HWCAP2_DCPODP (1 << 0)
139#endif
140#ifndef HWCAP2_SVE2
141#define HWCAP2_SVE2 (1 << 1)
142#endif
143#ifndef HWCAP2_SVEAES
144#define HWCAP2_SVEAES (1 << 2)
145#endif
146#ifndef HWCAP2_SVEPMULL
147#define HWCAP2_SVEPMULL (1 << 3)
148#endif
149#ifndef HWCAP2_SVEBITPERM
150#define HWCAP2_SVEBITPERM (1 << 4)
151#endif
152#ifndef HWCAP2_SVESHA3
153#define HWCAP2_SVESHA3 (1 << 5)
154#endif
155#ifndef HWCAP2_SVESM4
156#define HWCAP2_SVESM4 (1 << 6)
157#endif
158#ifndef HWCAP2_FLAGM2
159#define HWCAP2_FLAGM2 (1 << 7)
160#endif
161#ifndef HWCAP2_FRINT
162#define HWCAP2_FRINT (1 << 8)
163#endif
164#ifndef HWCAP2_SVEI8MM
165#define HWCAP2_SVEI8MM (1 << 9)
166#endif
167#ifndef HWCAP2_SVEF32MM
168#define HWCAP2_SVEF32MM (1 << 10)
169#endif
170#ifndef HWCAP2_SVEF64MM
171#define HWCAP2_SVEF64MM (1 << 11)
172#endif
173#ifndef HWCAP2_SVEBF16
174#define HWCAP2_SVEBF16 (1 << 12)
175#endif
176#ifndef HWCAP2_I8MM
177#define HWCAP2_I8MM (1 << 13)
178#endif
179#ifndef HWCAP2_BF16
180#define HWCAP2_BF16 (1 << 14)
181#endif
182#ifndef HWCAP2_DGH
183#define HWCAP2_DGH (1 << 15)
184#endif
185#ifndef HWCAP2_RNG
186#define HWCAP2_RNG (1 << 16)
187#endif
188#ifndef HWCAP2_BTI
189#define HWCAP2_BTI (1 << 17)
190#endif
191#ifndef HWCAP2_MTE
192#define HWCAP2_MTE (1 << 18)
193#endif
194#ifndef HWCAP2_RPRES
195#define HWCAP2_RPRES (1 << 21)
196#endif
197#ifndef HWCAP2_MTE3
198#define HWCAP2_MTE3 (1 << 22)
199#endif
200#ifndef HWCAP2_SME
201#define HWCAP2_SME (1 << 23)
202#endif
203#ifndef HWCAP2_SME_I16I64
204#define HWCAP2_SME_I16I64 (1 << 24)
205#endif
206#ifndef HWCAP2_SME_F64F64
207#define HWCAP2_SME_F64F64 (1 << 25)
208#endif
209#ifndef HWCAP2_WFXT
210#define HWCAP2_WFXT (1UL << 31)
211#endif
212#ifndef HWCAP2_EBF16
213#define HWCAP2_EBF16 (1UL << 32)
214#endif
215#ifndef HWCAP2_SVE_EBF16
216#define HWCAP2_SVE_EBF16 (1UL << 33)
217#endif
218
219static void
220__init_cpu_features_constructor(unsigned long hwcap,
221 const __ifunc_arg_t *arg) {
222#define setCPUFeature(F) __aarch64_cpu_features.features |= 1ULL << F
223#define getCPUFeature(id, ftr) __asm__("mrs %0, " #id : "=r"(ftr))
224#define extractBits(val, start, number) \
225 (val & ((1ULL << number) - 1ULL) << start) >> start
226 unsigned long hwcap2 = 0;
227 if (hwcap & _IFUNC_ARG_HWCAP)
228 hwcap2 = arg->_hwcap2;
229 if (hwcap & HWCAP_CRC32)
230 setCPUFeature(FEAT_CRC);
231 if (hwcap & HWCAP_PMULL)
232 setCPUFeature(FEAT_PMULL);
233 if (hwcap & HWCAP_FLAGM)
234 setCPUFeature(FEAT_FLAGM);
235 if (hwcap2 & HWCAP2_FLAGM2) {
236 setCPUFeature(FEAT_FLAGM);
237 setCPUFeature(FEAT_FLAGM2);
238 }
239 if (hwcap & HWCAP_SM3 && hwcap & HWCAP_SM4)
240 setCPUFeature(FEAT_SM4);
241 if (hwcap & HWCAP_ASIMDDP)
242 setCPUFeature(FEAT_DOTPROD);
243 if (hwcap & HWCAP_ASIMDFHM)
244 setCPUFeature(FEAT_FP16FML);
245 if (hwcap & HWCAP_FPHP) {
246 setCPUFeature(FEAT_FP16);
247 setCPUFeature(FEAT_FP);
248 }
249 if (hwcap & HWCAP_DIT)
250 setCPUFeature(FEAT_DIT);
251 if (hwcap & HWCAP_ASIMDRDM)
252 setCPUFeature(FEAT_RDM);
253 if (hwcap & HWCAP_ILRCPC)
254 setCPUFeature(FEAT_RCPC2);
255 if (hwcap & HWCAP_AES)
256 setCPUFeature(FEAT_AES);
257 if (hwcap & HWCAP_SHA1)
258 setCPUFeature(FEAT_SHA1);
259 if (hwcap & HWCAP_SHA2)
260 setCPUFeature(FEAT_SHA2);
261 if (hwcap & HWCAP_JSCVT)
262 setCPUFeature(FEAT_JSCVT);
263 if (hwcap & HWCAP_FCMA)
264 setCPUFeature(FEAT_FCMA);
265 if (hwcap & HWCAP_SB)
266 setCPUFeature(FEAT_SB);
267 if (hwcap & HWCAP_SSBS)
268 setCPUFeature(FEAT_SSBS2);
269 if (hwcap2 & HWCAP2_MTE) {
270 setCPUFeature(FEAT_MEMTAG);
271 setCPUFeature(FEAT_MEMTAG2);
272 }
273 if (hwcap2 & HWCAP2_MTE3) {
274 setCPUFeature(FEAT_MEMTAG);
275 setCPUFeature(FEAT_MEMTAG2);
276 setCPUFeature(FEAT_MEMTAG3);
277 }
278 if (hwcap2 & HWCAP2_SVEAES)
279 setCPUFeature(FEAT_SVE_AES);
280 if (hwcap2 & HWCAP2_SVEPMULL) {
281 setCPUFeature(FEAT_SVE_AES);
282 setCPUFeature(FEAT_SVE_PMULL128);
283 }
284 if (hwcap2 & HWCAP2_SVEBITPERM)
285 setCPUFeature(FEAT_SVE_BITPERM);
286 if (hwcap2 & HWCAP2_SVESHA3)
287 setCPUFeature(FEAT_SVE_SHA3);
288 if (hwcap2 & HWCAP2_SVESM4)
289 setCPUFeature(FEAT_SVE_SM4);
290 if (hwcap2 & HWCAP2_DCPODP)
291 setCPUFeature(FEAT_DPB2);
292 if (hwcap & HWCAP_ATOMICS)
293 setCPUFeature(FEAT_LSE);
294 if (hwcap2 & HWCAP2_RNG)
295 setCPUFeature(FEAT_RNG);
296 if (hwcap2 & HWCAP2_I8MM)
297 setCPUFeature(FEAT_I8MM);
298 if (hwcap2 & HWCAP2_EBF16)
299 setCPUFeature(FEAT_EBF16);
300 if (hwcap2 & HWCAP2_SVE_EBF16)
301 setCPUFeature(FEAT_SVE_EBF16);
302 if (hwcap2 & HWCAP2_DGH)
303 setCPUFeature(FEAT_DGH);
304 if (hwcap2 & HWCAP2_FRINT)
305 setCPUFeature(FEAT_FRINTTS);
306 if (hwcap2 & HWCAP2_SVEI8MM)
307 setCPUFeature(FEAT_SVE_I8MM);
308 if (hwcap2 & HWCAP2_SVEF32MM)
309 setCPUFeature(FEAT_SVE_F32MM);
310 if (hwcap2 & HWCAP2_SVEF64MM)
311 setCPUFeature(FEAT_SVE_F64MM);
312 if (hwcap2 & HWCAP2_BTI)
313 setCPUFeature(FEAT_BTI);
314 if (hwcap2 & HWCAP2_RPRES)
315 setCPUFeature(FEAT_RPRES);
316 if (hwcap2 & HWCAP2_WFXT)
317 setCPUFeature(FEAT_WFXT);
318 if (hwcap2 & HWCAP2_SME)
319 setCPUFeature(FEAT_SME);
320 if (hwcap2 & HWCAP2_SME_I16I64)
321 setCPUFeature(FEAT_SME_I64);
322 if (hwcap2 & HWCAP2_SME_F64F64)
323 setCPUFeature(FEAT_SME_F64);
324 if (hwcap & HWCAP_CPUID) {
325 unsigned long ftr;
326 getCPUFeature(ID_AA64PFR1_EL1, ftr);
327 /* ID_AA64PFR1_EL1.MTE >= 0b0001 */
328 if (extractBits(ftr, 8, 4) >= 0x1)
329 setCPUFeature(FEAT_MEMTAG);
330 /* ID_AA64PFR1_EL1.SSBS == 0b0001 */
331 if (extractBits(ftr, 4, 4) == 0x1)
332 setCPUFeature(FEAT_SSBS);
333 /* ID_AA64PFR1_EL1.SME == 0b0010 */
334 if (extractBits(ftr, 24, 4) == 0x2)
335 setCPUFeature(FEAT_SME2);
336 getCPUFeature(ID_AA64PFR0_EL1, ftr);
337 /* ID_AA64PFR0_EL1.FP != 0b1111 */
338 if (extractBits(ftr, 16, 4) != 0xF) {
339 setCPUFeature(FEAT_FP);
340 /* ID_AA64PFR0_EL1.AdvSIMD has the same value as ID_AA64PFR0_EL1.FP */
341 setCPUFeature(FEAT_SIMD);
342 }
343 /* ID_AA64PFR0_EL1.SVE != 0b0000 */
344 if (extractBits(ftr, 32, 4) != 0x0) {
345 /* get ID_AA64ZFR0_EL1, that name supported if sve enabled only */
346 getCPUFeature(S3_0_C0_C4_4, ftr);
347 /* ID_AA64ZFR0_EL1.SVEver == 0b0000 */
348 if (extractBits(ftr, 0, 4) == 0x0)
349 setCPUFeature(FEAT_SVE);
350 /* ID_AA64ZFR0_EL1.SVEver == 0b0001 */
351 if (extractBits(ftr, 0, 4) == 0x1)
352 setCPUFeature(FEAT_SVE2);
353 /* ID_AA64ZFR0_EL1.BF16 != 0b0000 */
354 if (extractBits(ftr, 20, 4) != 0x0)
355 setCPUFeature(FEAT_SVE_BF16);
356 }
357 getCPUFeature(ID_AA64ISAR0_EL1, ftr);
358 /* ID_AA64ISAR0_EL1.SHA3 != 0b0000 */
359 if (extractBits(ftr, 32, 4) != 0x0)
360 setCPUFeature(FEAT_SHA3);
361 getCPUFeature(ID_AA64ISAR1_EL1, ftr);
362 /* ID_AA64ISAR1_EL1.DPB >= 0b0001 */
363 if (extractBits(ftr, 0, 4) >= 0x1)
364 setCPUFeature(FEAT_DPB);
365 /* ID_AA64ISAR1_EL1.LRCPC != 0b0000 */
366 if (extractBits(ftr, 20, 4) != 0x0)
367 setCPUFeature(FEAT_RCPC);
368 /* ID_AA64ISAR1_EL1.LRCPC == 0b0011 */
369 if (extractBits(ftr, 20, 4) == 0x3)
370 setCPUFeature(FEAT_RCPC3);
371 /* ID_AA64ISAR1_EL1.SPECRES == 0b0001 */
372 if (extractBits(ftr, 40, 4) == 0x2)
373 setCPUFeature(FEAT_PREDRES);
374 /* ID_AA64ISAR1_EL1.BF16 != 0b0000 */
375 if (extractBits(ftr, 44, 4) != 0x0)
376 setCPUFeature(FEAT_BF16);
377 /* ID_AA64ISAR1_EL1.LS64 >= 0b0001 */
378 if (extractBits(ftr, 60, 4) >= 0x1)
379 setCPUFeature(FEAT_LS64);
380 /* ID_AA64ISAR1_EL1.LS64 >= 0b0010 */
381 if (extractBits(ftr, 60, 4) >= 0x2)
382 setCPUFeature(FEAT_LS64_V);
383 /* ID_AA64ISAR1_EL1.LS64 >= 0b0011 */
384 if (extractBits(ftr, 60, 4) >= 0x3)
385 setCPUFeature(FEAT_LS64_ACCDATA);
386 } else {
387 /* Set some features in case of no CPUID support. */
388 if (hwcap & (HWCAP_FP | HWCAP_FPHP)) {
389 setCPUFeature(FEAT_FP);
390 /* FP and AdvSIMD fields have the same value. */
391 setCPUFeature(FEAT_SIMD);
392 }
393 if (hwcap & HWCAP_DCPOP || hwcap2 & HWCAP2_DCPODP)
394 setCPUFeature(FEAT_DPB);
395 if (hwcap & HWCAP_LRCPC || hwcap & HWCAP_ILRCPC)
396 setCPUFeature(FEAT_RCPC);
397 if (hwcap2 & HWCAP2_BF16 || hwcap2 & HWCAP2_EBF16)
398 setCPUFeature(FEAT_BF16);
399 if (hwcap2 & HWCAP2_SVEBF16)
400 setCPUFeature(FEAT_SVE_BF16);
401 if (hwcap2 & HWCAP2_SVE2 && hwcap & HWCAP_SVE)
402 setCPUFeature(FEAT_SVE2);
403 if (hwcap & HWCAP_SHA3)
404 setCPUFeature(FEAT_SHA3);
405 }
406 setCPUFeature(FEAT_INIT);
407}
408
409void
410__init_cpu_features_resolver(unsigned long hwcap, const __ifunc_arg_t *arg) {
411 if (__aarch64_cpu_features.features)
412 return;
413 __init_cpu_features_constructor(hwcap, arg);
414}
415
416void __attribute__ ((constructor))
417__init_cpu_features(void) {
418 unsigned long hwcap;
419 unsigned long hwcap2;
420 /* CPU features already initialized. */
421 if (__aarch64_cpu_features.features)
422 return;
423 hwcap = getauxval(AT_HWCAP);
424 hwcap2 = getauxval(AT_HWCAP2);
425 __ifunc_arg_t arg;
426 arg._size = sizeof(__ifunc_arg_t);
427 arg._hwcap = hwcap;
428 arg._hwcap2 = hwcap2;
429 __init_cpu_features_constructor(hwcap | _IFUNC_ARG_HWCAP, &arg);
430#undef extractBits
431#undef getCPUFeature
432#undef setCPUFeature
433}
434#endif /* __has_include(<asm/hwcap.h>) */
435#endif /* __has_include(<sys/auxv.h>) */