Skip to content

Commit 6865b37

Browse files
tenderlovebyroot
andcommitted
Add SIMD support for various platforms
We need extconf to detect which SIMD features the compiler and processor support, then we can compile in SIMD support for BLAKE3 Co-Authored-By: Jean Boussier <jean.boussier@gmail.com>
1 parent 13dcf1d commit 6865b37

1 file changed

Lines changed: 71 additions & 15 deletions

File tree

ext/digest/blake3/extconf.rb

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,79 @@
33

44
require "mkmf"
55

6-
# Build the portable (no-SIMD) BLAKE3 implementation: only blake3.c,
7-
# blake3_dispatch.c and blake3_portable.c are compiled. The SIMD
8-
# backends (SSE2/SSE4.1/AVX2/AVX512/NEON) are intentionally left out to
9-
# keep the build simple and dependency-free. Each instruction set has
10-
# to be disabled explicitly, otherwise blake3_dispatch.c references
11-
# symbols from the omitted backends. In particular NEON auto-enables on
12-
# AArch64 (see blake3_impl.h), so BLAKE3_USE_NEON must be forced off too.
13-
$defs << "-DBLAKE3_NO_SSE2"
14-
$defs << "-DBLAKE3_NO_SSE41"
15-
$defs << "-DBLAKE3_NO_AVX2"
16-
$defs << "-DBLAKE3_NO_AVX512"
17-
$defs << "-DBLAKE3_USE_NEON=0"
18-
19-
$objs = %w[blake3init blake3 blake3_dispatch blake3_portable].map do |o|
20-
"#{o}.#{$OBJEXT}"
6+
# BLAKE3 build configuration.
7+
#
8+
# The binding is always built from the portable C code (blake3.c,
9+
# blake3_dispatch.c, blake3_portable.c). On architectures BLAKE3 ships
10+
# optimized backends for, we additionally compile the SIMD implementations
11+
# and let blake3_dispatch.c select the fastest one supported by the CPU the
12+
# program is actually running on (via CPUID on x86). This means a binary
13+
# built on an AVX-512-capable machine still runs correctly on an older CPU.
14+
#
15+
# Each SIMD translation unit must be compiled with its own instruction-set
16+
# flag, which a single global $CFLAGS can't express, so we emit one explicit
17+
# object rule per backend at the end (see below). Any x86 backend we do NOT
18+
# compile is disabled with -DBLAKE3_NO_<ISA>; that macro is honoured both by
19+
# the dispatcher and by sibling backends (e.g. blake3_avx2.c falls back to
20+
# SSE4.1 helpers), keeping the set of referenced symbols consistent.
21+
22+
objs = %w[blake3init blake3 blake3_dispatch blake3_portable]
23+
24+
# Extra per-object compiler flags, keyed by object basename.
25+
simd_cflags = {}
26+
27+
# Probe used to confirm the compiler both accepts +flag+ and can compile the
28+
# intrinsics the backend relies on.
29+
def blake3_have_isa?(name, flag, snippet)
30+
checking_for("#{name} intrinsics (#{flag})") do
31+
try_compile(snippet, flag)
32+
end
2133
end
2234

35+
case RbConfig::CONFIG["host_cpu"]
36+
when /\A(x86_64|amd64|x64)\z/i
37+
# Try to detect which SIMD features this x86 machine and compiler has
38+
x86_backends = [
39+
["blake3_sse2", "SSE2", "-msse2",
40+
"#include <immintrin.h>\nint main(void){ volatile __m128i x = _mm_setzero_si128(); (void)x; return 0; }\n",
41+
"BLAKE3_NO_SSE2"],
42+
["blake3_sse41", "SSE4.1", "-msse4.1",
43+
"#include <immintrin.h>\nint main(void){ volatile __m128i x = _mm_setzero_si128(); return _mm_testz_si128(x, x); }\n",
44+
"BLAKE3_NO_SSE41"],
45+
["blake3_avx2", "AVX2", "-mavx2",
46+
"#include <immintrin.h>\nint main(void){ volatile __m256i x = _mm256_setzero_si256(); (void)x; return 0; }\n",
47+
"BLAKE3_NO_AVX2"],
48+
["blake3_avx512", "AVX-512", "-mavx512f -mavx512vl",
49+
"#include <immintrin.h>\nint main(void){ volatile __m512i x = _mm512_setzero_si512(); (void)x; return 0; }\n",
50+
"BLAKE3_NO_AVX512"],
51+
]
52+
53+
x86_backends.each do |obj, name, flag, snippet, no_macro|
54+
if blake3_have_isa?(name, flag, snippet)
55+
objs << obj
56+
simd_cflags[obj] = flag
57+
else
58+
$defs << "-D#{no_macro}"
59+
end
60+
end
61+
when /\A(aarch64|arm64)\z/i
62+
# NEON is part of the AArch64 baseline, so no runtime detection or special
63+
# compiler flag is needed. Leave BLAKE3_USE_NEON to auto-detect, which is
64+
# 1 on little-endian AArch64 (see blake3_impl.h).
65+
objs << "blake3_neon"
66+
else
67+
# No optimized backend wired up for this architecture (e.g. 32-bit x86,
68+
# ppc): build portable-only. Disabling every x86 ISA keeps the dispatcher
69+
# from referencing backends we didn't compile, and NEON is forced off.
70+
$defs << "-DBLAKE3_NO_SSE2"
71+
$defs << "-DBLAKE3_NO_SSE41"
72+
$defs << "-DBLAKE3_NO_AVX2"
73+
$defs << "-DBLAKE3_NO_AVX512"
74+
$defs << "-DBLAKE3_USE_NEON=0"
75+
end
76+
77+
$objs = objs.map { |o| "#{o}.#{$OBJEXT}" }
78+
2379
have_header("sys/cdefs.h")
2480

2581
$preload = %w[digest]

0 commit comments

Comments
 (0)