Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/scripts/get_native_properties.sh
625 views
1
#!/bin/sh
2
3
#
4
# Returns the best architecture supported by the CPU (as expected by src/Makefile ARCH=).
5
#
6
# Output format:
7
# "<true_arch>\n"
8
#
9
10
# ---------------------------
11
# Helpers (POSIX)
12
# ---------------------------
13
14
# Test hooks (optional env overrides)
15
# GP_UNAME_S: override `uname -s`
16
# GP_UNAME_M: override `uname -m`
17
# GP_CPUINFO: path to a cpuinfo-like fixture file (defaults to /proc/cpuinfo)
18
# GP_BITS: override getconf LONG_BIT result (32/64)
19
# GP_SYSCTL_FEATURES: override sysctl feature strings on Darwin x86_64
20
21
cpuinfo_path=${GP_CPUINFO:-/proc/cpuinfo}
22
23
# Normalize to a single-line, space-separated string.
24
normalize_ws() {
25
printf '%s\n' "$*" | tr '\n\t' ' ' | tr -s ' '
26
}
27
28
die() {
29
printf '%s\n' "$*" >&2
30
exit 1
31
}
32
33
# Populate $flags from /proc/cpuinfo when available,
34
# removing underscores and dots to reduce naming variations.
35
get_flags() {
36
if [ -r "$cpuinfo_path" ]; then
37
flags=$(
38
awk '
39
/^flags[ \t]*:|^Features[ \t]*:/ {
40
if (!found) {
41
gsub(/^flags[ \t]*:[ \t]*|^Features[ \t]*:[ \t]*|[_.]/, "");
42
line=$0
43
found=1
44
}
45
}
46
END { print line }
47
' "$cpuinfo_path" 2>/dev/null
48
)
49
else
50
flags=''
51
fi
52
flags=$(printf '%s\n' "$flags" | tr '[:upper:]' '[:lower:]')
53
flags=$(normalize_ws "$flags")
54
}
55
56
# Populate $flags from sysctl on Darwin x86_64.
57
get_sysctl_flags() {
58
if [ -n "${GP_SYSCTL_FEATURES:-}" ]; then
59
flags=$(printf '%s\n' "$GP_SYSCTL_FEATURES")
60
else
61
flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features 2>/dev/null)
62
fi
63
flags=$(printf '%s\n' "$flags" | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '._')
64
flags=$(normalize_ws "$flags")
65
}
66
67
# Best-effort bitness for fallback arch selection.
68
get_bits() {
69
if [ -n "${GP_BITS:-}" ]; then
70
bits=$GP_BITS
71
else
72
bits=$(getconf LONG_BIT 2>/dev/null)
73
fi
74
case $bits in
75
32|64) : ;;
76
*) bits=64 ;;
77
esac
78
}
79
80
# Extract ARM architecture level (5/6/7/8/...) from /proc/cpuinfo when present.
81
get_arm_arch_level() {
82
[ -r "$cpuinfo_path" ] || return 1
83
awk '
84
/^CPU architecture[ \t]*:/{
85
s=$0
86
sub(/^[^:]*:[ \t]*/, "", s)
87
if (match(s, /[0-9]+/)) { print substr(s, RSTART, RLENGTH); exit }
88
}
89
/^Processor[ \t]*:/{
90
s=$0
91
sub(/^[^:]*:[ \t]*/, "", s)
92
if (match(s, /ARMv[0-9]+/)) { print substr(s, RSTART+4, RLENGTH-4); exit }
93
}
94
' "$cpuinfo_path" 2>/dev/null
95
}
96
97
# Best-effort ARM architecture level (5/6/7/8/...) with a minimal fallback.
98
# Prefer /proc/cpuinfo when available; fall back to uname -m only when it encodes it.
99
get_arm_level() {
100
arm_level=$(get_arm_arch_level || :)
101
if [ -n "$arm_level" ]; then
102
printf '%s\n' "$arm_level"
103
return 0
104
fi
105
case ${1:-} in
106
armv5*) printf '5\n' ;;
107
armv6*) printf '6\n' ;;
108
armv7*) printf '7\n' ;;
109
armv8l) printf '8\n' ;;
110
*) return 1 ;;
111
esac
112
}
113
114
# Whole-token membership check.
115
has_flag() {
116
case " $flags " in
117
*" $1 "*) return 0 ;;
118
*) return 1 ;;
119
esac
120
}
121
122
match_flags() {
123
for f; do
124
has_flag "$f" || return 1
125
done
126
return 0
127
}
128
129
match_any_flags() {
130
for f; do
131
has_flag "$f" && return 0
132
done
133
return 1
134
}
135
136
# SSE3 is often exposed as "pni" in /proc/cpuinfo.
137
match_sse3() {
138
match_any_flags sse3 pni
139
}
140
141
# AMD Zen1/2 exclusion logic (used for bmi2 tier).
142
# https://web.archive.org/web/20250821132355/https://en.wikichip.org/wiki/amd/cpuid
143
is_znver_1_2() (
144
[ -r "$cpuinfo_path" ] || exit 1
145
vendor_id=$(awk '/^vendor_id/{print $3; exit}' "$cpuinfo_path" 2>/dev/null)
146
cpu_family=$(awk '/^cpu family/{print $4; exit}' "$cpuinfo_path" 2>/dev/null)
147
[ "$vendor_id" = "AuthenticAMD" ] && [ "$cpu_family" = "23" ]
148
)
149
150
match_not_znver12_and_flags() {
151
is_znver_1_2 && return 1
152
match_flags "$@"
153
}
154
155
match_sse3_popcnt() {
156
has_flag popcnt || return 1
157
match_sse3
158
}
159
160
match_true() { return 0; }
161
162
# Generic selector: reads lines like "arch|predicate|arg1 arg2 ..."
163
# First match wins; blank lines and lines starting with '#' are ignored.
164
select_arch_from_table() {
165
while IFS='|' read -r arch pred args; do
166
[ -z "$arch" ] && continue
167
case $arch in \#*) continue ;; esac
168
169
if [ -n "$args" ]; then
170
# Intentional splitting of args into words for the predicate.
171
# shellcheck disable=SC2086
172
$pred $args && { printf '%s\n' "$arch"; return 0; }
173
else
174
$pred && { printf '%s\n' "$arch"; return 0; }
175
fi
176
done
177
return 1
178
}
179
180
# ---------------------------
181
# Arch selection (table-driven)
182
# ---------------------------
183
184
set_arch_loongarch64() {
185
true_arch=$(
186
select_arch_from_table <<'EOF'
187
loongarch64-lasx|match_flags|lasx
188
loongarch64-lsx|match_flags|lsx
189
loongarch64|match_true|
190
EOF
191
)
192
}
193
194
set_arch_x86_64() {
195
true_arch=$(
196
select_arch_from_table <<'EOF'
197
# Strongest -> weakest (first match wins)
198
x86-64-avx512icl|match_flags|avx512f avx512cd avx512vl avx512dq avx512bw avx512ifma avx512vbmi avx512vbmi2 avx512vpopcntdq avx512bitalg avx512vnni vpclmulqdq gfni vaes
199
x86-64-vnni512|match_flags|avx512vnni avx512dq avx512f avx512bw avx512vl
200
x86-64-avx512|match_flags|avx512f avx512bw
201
x86-64-avxvnni|match_flags|avxvnni
202
x86-64-bmi2|match_not_znver12_and_flags|bmi2
203
x86-64-avx2|match_flags|avx2
204
x86-64-sse41-popcnt|match_flags|sse41 popcnt
205
x86-64-ssse3|match_flags|ssse3
206
x86-64-sse3-popcnt|match_sse3_popcnt|
207
x86-64|match_true|
208
EOF
209
)
210
}
211
212
set_arch_x86_32() {
213
true_arch=$(
214
select_arch_from_table <<'EOF'
215
x86-32-sse41-popcnt|match_flags|sse41 popcnt
216
x86-32-sse2|match_flags|sse2
217
x86-32|match_true|
218
EOF
219
)
220
}
221
222
# PPC64 needs a little parsing to distinguish vsx vs altivec.
223
set_arch_ppc_64() {
224
if [ -r "$cpuinfo_path" ] && grep -q "altivec" "$cpuinfo_path" 2>/dev/null; then
225
# Typical: "cpu : POWER8E" (extract the number after POWER)
226
power=$(
227
awk -F: '/^cpu[ \t]*:/{print $2; exit}' "$cpuinfo_path" 2>/dev/null \
228
| sed -n 's/.*[Pp][Oo][Ww][Ee][Rr][^0-9]*\([0-9][0-9]*\).*/\1/p'
229
)
230
if [ -z "$power" ]; then
231
power=$(
232
awk -F: '/^cpu[ \t]*:/{print $2; exit}' "$cpuinfo_path" 2>/dev/null \
233
| sed -n 's/.*\([0-9][0-9]*\).*/\1/p'
234
)
235
fi
236
case $power in
237
''|*[!0-9]*)
238
true_arch='ppc-64-altivec'
239
;;
240
*)
241
if [ "$power" -gt 7 ] 2>/dev/null; then
242
true_arch='ppc-64-vsx'
243
else
244
true_arch='ppc-64-altivec'
245
fi
246
;;
247
esac
248
else
249
true_arch='ppc-64'
250
fi
251
}
252
253
# ---------------------------
254
# OS / machine dispatch
255
# ---------------------------
256
257
uname_s=$(uname -s 2>/dev/null)
258
uname_m=$(uname -m 2>/dev/null)
259
uname_s=${GP_UNAME_S:-$uname_s}
260
uname_m=${GP_UNAME_M:-$uname_m}
261
262
case $uname_s in
263
Darwin)
264
case $uname_m in
265
arm64)
266
true_arch='apple-silicon'
267
;;
268
x86_64)
269
get_sysctl_flags
270
set_arch_x86_64
271
;;
272
*)
273
get_bits
274
if [ "$bits" = "32" ]; then
275
true_arch='general-32'
276
else
277
true_arch='general-64'
278
fi
279
;;
280
esac
281
;;
282
283
Linux)
284
get_flags
285
case $uname_m in
286
x86_64)
287
set_arch_x86_64
288
;;
289
i?86)
290
set_arch_x86_32
291
;;
292
ppc64*)
293
set_arch_ppc_64
294
;;
295
aarch64|arm64)
296
true_arch='armv8'
297
if match_flags asimddp; then
298
true_arch='armv8-dotprod'
299
fi
300
;;
301
armv5*|armv6*|armv7*|armv8l|arm*)
302
arm_level=$(get_arm_level "$uname_m" || :)
303
case $arm_level in
304
5|6)
305
true_arch='general-32'
306
;;
307
7|8)
308
true_arch='armv7'
309
if match_flags neon; then
310
true_arch='armv7-neon'
311
fi
312
;;
313
*)
314
true_arch='general-32'
315
if match_flags neon; then
316
true_arch='armv7-neon'
317
fi
318
;;
319
esac
320
;;
321
loongarch64*)
322
set_arch_loongarch64
323
;;
324
riscv64)
325
true_arch='riscv64'
326
;;
327
e2k*)
328
true_arch='e2k'
329
;;
330
ppc|ppc32|powerpc)
331
true_arch='ppc-32'
332
;;
333
*)
334
# Don't hard-fail: fall back to general-* so ARCH=native still builds
335
get_bits
336
if [ "$bits" = "32" ]; then
337
true_arch='general-32'
338
else
339
true_arch='general-64'
340
fi
341
;;
342
esac
343
;;
344
345
MINGW*ARM64*)
346
# Windows ARM64 (MSYS2/MinGW)
347
# Can't reliably detect ARM CPU features here
348
true_arch='armv8-dotprod'
349
;;
350
351
CYGWIN*|MINGW*|MSYS*)
352
# Windows x86_64 (MSYS2/Cygwin/MinGW)
353
get_flags
354
set_arch_x86_64
355
;;
356
357
*)
358
die "Unsupported system type: $uname_s"
359
;;
360
esac
361
362
printf '%s\n' "$true_arch"
363
364