|
3 | 3 |
|
4 | 4 | require "mkmf" |
5 | 5 |
|
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 |
21 | 33 | end |
22 | 34 |
|
| 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 | + |
23 | 79 | have_header("sys/cdefs.h") |
24 | 80 |
|
25 | 81 | $preload = %w[digest] |
|
0 commit comments