1 /* x86 CPU feature tuning.
2 This file is part of the GNU C Library.
3 Copyright (C) 2017-2023 Free Software Foundation, Inc.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
20 # define TUNABLE_NAMESPACE cpu
23 # include <unistd.h> /* Get STDOUT_FILENO for _dl_printf. */
24 # include <elf/dl-tunables.h>
26 # include <cpu-features.h>
27 # include <ldsodefs.h>
29 /* We can't use IFUNC memcmp nor strlen in init_cpu_features from libc.a
30 since IFUNC must be set up by init_cpu_features. */
31 # if defined USE_MULTIARCH && !defined SHARED
33 /* DEFAULT_MEMCMP by sysdeps/x86_64/memcmp-isa-default-impl.h. */
34 # include <sysdeps/x86_64/memcmp-isa-default-impl.h>
36 # define DEFAULT_MEMCMP __memcmp_ia32
38 extern __typeof (memcmp
) DEFAULT_MEMCMP
;
40 # define DEFAULT_MEMCMP memcmp
43 # define CHECK_GLIBC_IFUNC_CPU_OFF(f, cpu_features, name, len) \
44 _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \
45 if (!DEFAULT_MEMCMP (f, #name, len)) \
47 CPU_FEATURE_UNSET (cpu_features, name) \
51 /* Disable a preferred feature NAME. We don't enable a preferred feature
52 which isn't available. */
53 # define CHECK_GLIBC_IFUNC_PREFERRED_OFF(f, cpu_features, name, len) \
54 _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \
55 if (!DEFAULT_MEMCMP (f, #name, len)) \
57 cpu_features->preferred[index_arch_##name] \
58 &= ~bit_arch_##name; \
62 /* Enable/disable a preferred feature NAME. */
63 # define CHECK_GLIBC_IFUNC_PREFERRED_BOTH(f, cpu_features, name, \
65 _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \
66 if (!DEFAULT_MEMCMP (f, #name, len)) \
69 cpu_features->preferred[index_arch_##name] &= ~bit_arch_##name; \
71 cpu_features->preferred[index_arch_##name] |= bit_arch_##name; \
75 /* Enable/disable a preferred feature NAME. Enable a preferred feature
76 only if the feature NEED is usable. */
77 # define CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH(f, cpu_features, name, \
79 _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \
80 if (!DEFAULT_MEMCMP (f, #name, len)) \
83 cpu_features->preferred[index_arch_##name] &= ~bit_arch_##name; \
84 else if (CPU_FEATURE_USABLE_P (cpu_features, need)) \
85 cpu_features->preferred[index_arch_##name] |= bit_arch_##name; \
91 TUNABLE_CALLBACK (set_hwcaps
) (tunable_val_t
*valp
)
93 /* The current IFUNC selection is based on microbenchmarks in glibc.
94 It should give the best performance for most workloads. But other
95 choices may have better performance for a particular workload or on
96 the hardware which wasn't available when the selection was made.
97 The environment variable:
99 GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz,....
101 can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature
102 yyy and zzz, where the feature name is case-sensitive and has to
103 match the ones in cpu-features.h. It can be used by glibc developers
104 to tune for a new processor or override the IFUNC selection to
105 improve performance for a particular workload.
107 NOTE: the IFUNC selection may change over time. Please check all
108 multiarch implementations when experimenting. */
110 const char *p
= valp
->strval
, *c
;
111 struct cpu_features
*cpu_features
= &GLRO(dl_x86_cpu_features
);
120 for (c
= p
; *c
!= ','; c
++)
143 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX
, 3);
144 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, CX8
, 3);
145 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, FMA
, 3);
146 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, HTT
, 3);
147 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, IBT
, 3);
148 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, RTM
, 3);
154 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX2
, 4);
155 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, BMI1
, 4);
156 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, BMI2
, 4);
157 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, CMOV
, 4);
158 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, ERMS
, 4);
159 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, FMA4
, 4);
160 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, SSE2
, 4);
161 CHECK_GLIBC_IFUNC_PREFERRED_OFF (n
, cpu_features
, I586
, 4);
162 CHECK_GLIBC_IFUNC_PREFERRED_OFF (n
, cpu_features
, I686
, 4);
168 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, LZCNT
, 5);
169 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, MOVBE
, 5);
170 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, SHSTK
, 5);
171 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, SSSE3
, 5);
172 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, XSAVE
, 5);
178 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, POPCNT
, 6);
179 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, SSE4_1
, 6);
180 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, SSE4_2
, 6);
181 if (!DEFAULT_MEMCMP (n
, "XSAVEC", 6))
183 /* Update xsave_state_size to XSAVE state size. */
184 cpu_features
->xsave_state_size
185 = cpu_features
->xsave_state_full_size
;
186 CPU_FEATURE_UNSET (cpu_features
, XSAVEC
);
193 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512F
, 7);
194 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, OSXSAVE
, 7);
200 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512CD
, 8);
201 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512BW
, 8);
202 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512DQ
, 8);
203 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512ER
, 8);
204 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512PF
, 8);
205 CHECK_GLIBC_IFUNC_CPU_OFF (n
, cpu_features
, AVX512VL
, 8);
207 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
, Slow_BSF
,
212 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
,
215 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
,
218 CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH (n
, cpu_features
,
226 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
,
233 CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH
234 (n
, cpu_features
, Prefer_No_AVX512
, AVX512F
,
240 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
,
247 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
,
250 CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n
, cpu_features
,
257 CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH
258 (n
, cpu_features
, Prefer_No_VZEROUPPER
, AVX
, disable
,
264 CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH
265 (n
, cpu_features
, AVX_Fast_Unaligned_Load
, AVX
,
271 CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH
272 (n
, cpu_features
, MathVec_Prefer_No_AVX512
, AVX512F
,
278 CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH
279 (n
, cpu_features
, Prefer_PMINUB_for_stringop
, SSE2
,
293 TUNABLE_CALLBACK (set_x86_ibt
) (tunable_val_t
*valp
)
295 if (DEFAULT_MEMCMP (valp
->strval
, "on", sizeof ("on")) == 0)
296 GL(dl_x86_feature_control
).ibt
= cet_always_on
;
297 else if (DEFAULT_MEMCMP (valp
->strval
, "off", sizeof ("off")) == 0)
298 GL(dl_x86_feature_control
).ibt
= cet_always_off
;
299 else if (DEFAULT_MEMCMP (valp
->strval
, "permissive",
300 sizeof ("permissive")) == 0)
301 GL(dl_x86_feature_control
).ibt
= cet_permissive
;
306 TUNABLE_CALLBACK (set_x86_shstk
) (tunable_val_t
*valp
)
308 if (DEFAULT_MEMCMP (valp
->strval
, "on", sizeof ("on")) == 0)
309 GL(dl_x86_feature_control
).shstk
= cet_always_on
;
310 else if (DEFAULT_MEMCMP (valp
->strval
, "off", sizeof ("off")) == 0)
311 GL(dl_x86_feature_control
).shstk
= cet_always_off
;
312 else if (DEFAULT_MEMCMP (valp
->strval
, "permissive",
313 sizeof ("permissive")) == 0)
314 GL(dl_x86_feature_control
).shstk
= cet_permissive
;