Skip to content

Detect AVX2 and AVX-512 support at runtime - #376

Draft
wegank wants to merge 1 commit into
algebraic-solving:masterfrom
wegank:runtime-avx-dispatch
Draft

wegank wants to merge 1 commit into
algebraic-solving:masterfrom
wegank:runtime-avx-dispatch

Conversation

@wegank

@wegank wegank commented Oct 1, 2026

Copy link
Copy Markdown
Member

Fixes #71.

So far, configure inspected the CPU of the build machine (AX_EXT) and compiled all of msolve with the SIMD extensions found there. Binaries built on a recent machine thus crash with an illegal instruction on older x86-64 CPUs, and Linux distributions, which must target the baseline architecture, cannot ship the vectorized code at all.

This PR compiles the AVX2 and AVX-512 kernels whenever the compiler supports them and selects them at runtime, so that the same binary runs on every x86-64 CPU and uses the best kernels available.

Changes

  • New header src/msolve/cpu_features.h: TARGET_AVX2 / TARGET_AVX512 function attributes, runtime checks cpu_has_avx2() / cpu_has_avx512() (via __builtin_cpu_supports), and the immintrin.h / arm_neon.h includes. If the extensions are enabled globally (e.g. -march=native), the checks are resolved at compile time.
  • neogb: the inline #if SIMD branches of the row reduction routines in la_ff_8.c, la_ff_16.c and la_ff_32.c are moved into separate _scalar / _neon / _avx2 / _avx512 kernels with a small dispatcher. The kernel bodies are unchanged, and each routine keeps using exactly the instruction sets it used before (e.g. the trace/sat/sba routines still only use AVX2). The four identical AVX2 copies of the 31 bit kernel in la_ff_32.c now share one kernel.
  • fglm: the kernels already were separate functions and only get the target attributes; dense_matrix_vector_product() replaces the compile-time selection.
  • configure.ac: AX_EXT is replaced by link checks whether the compiler can build the kernels, defining HAVE_AVX2_KERNELS and HAVE_AVX512_KERNELS (renamed from HAVE_AVX2 / HAVE_AVX512_F to make the new meaning explicit). SIMD_FLAGS / CPUEXT_FLAGS and the m4 macros only used by AX_EXT are removed.
  • INSTALL: short note on the runtime selection and on -march=native.

Things to be aware of

  • The code outside the kernels is now compiled for the baseline x86-64 architecture instead of with the host flags, so default builds on recent CPUs may be slightly slower there. Users building only for their own machine can add -march=native to CFLAGS. A benchmark on real AVX2/AVX-512 hardware would be welcome.
  • The AVX-512 kernels now require AVX-512 BW at runtime as well (the 8 and 16 bit kernels always needed it, previously this was implicit). CPUs with AVX-512 F but without BW (essentially Xeon Phi) use the AVX2 kernels.

Testing

All 68 tests of make check pass on:

  • arm64 macOS (NEON/scalar kernels)
  • x86_64 macOS under Rosetta, which lacks AVX2 (scalar kernels)
  • x86_64 Linux (GCC) without AVX2 (scalar kernels), and under qemu-x86_64 -cpu Haswell / -cpu max (AVX2 kernels)

Additionally, the disassembly of the x86_64 libraries shows AVX registers only inside the kernel functions, and the code compiles without warnings with -march=x86-64, -march=haswell and -march=skylake-avx512. The AVX-512 kernels could not be exercised at runtime locally (QEMU does not emulate AVX-512).

AI disclosure

The changes in this PR were made with the assistance of generative AI (Claude Code), and reviewed by me.

🤖 Generated with Claude Code

So far, configure inspected the CPU of the build machine and compiled all
of msolve with the SIMD extensions found there. Binaries built on a recent
machine thus crashed with an illegal instruction on older x86-64 CPUs, and
Linux distributions, which must target the baseline architecture, could not
ship the vectorized code at all (see algebraic-solving#71).

Now, the AVX2 and AVX-512 kernels are always compiled when the compiler
supports them, each marked with a function-level target attribute, while
the remaining code is compiled for the baseline architecture. The kernel
to use is chosen at runtime via __builtin_cpu_supports. The new header
src/msolve/cpu_features.h provides the target attributes, the runtime
checks and the SIMD intrinsics includes; with e.g. -march=native the
checks are resolved at compile time.

In neogb, the inline SIMD branches of the row reduction routines are moved
into separate scalar/NEON/AVX2/AVX-512 kernels, without changing which
instruction sets each routine uses. The fglm kernels already were separate
functions and only get the target attributes.

configure now only checks whether the compiler can build these kernels and
defines HAVE_AVX2_KERNELS and HAVE_AVX512_KERNELS accordingly. AX_EXT and
the m4 macros only used by it are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/msolve/cpu_features.h
Comment on lines +17 to +19
* Jérémy Berthomieu
* Christian Eder
* Mohab Safey El Din */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Jérémy Berthomieu
* Christian Eder
* Mohab Safey El Din */
* Weijia Wang */

(sorry for the previous suggestion, I had not selected the three relevant lines correctly)

Shouldn't this be your name here as this file's author? or keep others if you wish, but at least add yours (in this new file and all other substantially modified files)?

@wegank wegank Oct 1, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to keep the three names in the msolve block, as I am definitely not an author of msolve:

msolve/AUTHORS

Lines 1 to 3 in 7403904

Jérémy Berthomieu (Sorbonne Université)
Christian Eder (TU Kaiserslautern)
Mohab Safey El Din (Sorbonne Université)

That said, I can probably add my name in a separate block, as was done for MT19937 in #372.

(This comment is not by Claude Code; everything else in this PR is)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'm just more used to per-file copyright notices, which are usually about the contributors to that specific file. But maybe how to do this is not well stabilized in msolve yet. When I did some substantial work in some FGLM file (linalg-fglm.c), I was advised to add my name to this file's copyright. Don't hesitate to do the same.

@vneiger

vneiger commented Oct 1, 2026

Copy link
Copy Markdown
Contributor
  • Users building only for their own machine can add -march=native to CFLAGS

To avoid any slowdown when building for one's own machine, don't we want rather that by default "-march=native" is added to CFLAGS (without user intervention)? Or would this maybe break the purpose of this PR? I'm just reacting here because of the observation that "default builds on recent CPUs may be slightly slower there", which is maybe something not wanted... well, this is quantitatively vague, so it depends: if "slightly slower" means "barely noticeable", then fine.

@wegank

wegank commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

I think it's worth running some benchmarks. But indeed, using -march=native by default somewhere breaks the purpose of this PR, since the built binary would not run on targets with lower baseline.

@mohabsafey

Copy link
Copy Markdown
Contributor

I think that we need a clear view of the potential slowdown on different platforms before investigating more. The performance loss should clearly be negligeible including on intensive computations

@dimpase

dimpase commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

IMHO -march=native should only build for the detected host architecture, and in #367 there is a config change to use the compiler flags, so that the build can done for another arch in a clean way, without fiddling with CFLAGS

This PR is not the first experiment of this sort, as far as I recall MPIR, an abandoned fork of GMP, was doing a similar thing.
The main reason for MPIR to stale was the emergence of Spectre and similar viruses targeting CPUs, which triggered mitigations, hardware microcode changes breaking optimizations intoduced there.

Thus, I wonder whether microcode changes might break the code in this PR. If so, it's a non-starter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Detect AVX2 support at runtime

4 participants