Repository navigation
Conversation
jan-wassenberg
left a comment
There was a problem hiding this comment.
Wow, that is quite a difference, thanks for pointing this out.
|
Please add a macro to allow users to opt out this. |
In my test, clang always clear destination register of gather, even in non-loop code. But I'll add the macro anyway. |
In highway, workarounds should typically have macros to allow them to be disabled. for example, if this bug is fixed in future gcc, then even older highway can manually disable this workaround. |
GCC can omit destination initialization for gathers with an all-ones mask. This leaves a false dependency on the previous destination value, limiting overlap between loop iterations when the gathered values feed further computation. See GCC Bugzilla 127946.
For GCC, use masked gather intrinsics with a zero merge source and an all-ones mask made opaque through empty inline assembly. This prevents GCC from removing destination initialization. The asm is nonvolatile and has no memory clobber; the intrinsic retains memory-access modeling.
Apply the workaround to 128-, 256-, and 512-bit integer and floating-point gathers. Preserve the original implementations for other compilers, and add a TODO to restrict the workaround once the fixed GCC version is known. Public APIs and explicitly masked gathers are unchanged.
On a Xeon Gold 6526Y unaffected by GDS, using GCC 14.3.1, a standalone gather-plus-eight-FMA microbenchmark shows median improvements of 2.1–5.0× at
-O2and 3.9–6.4× at-O3across the tested widths, over five alternating baseline/patched runs. Gather-only performance is roughly unchanged.benchmark source: (written by gpt astra, just demonstrate speedup, not part of this pr)
Benchmark results
Intel Xeon Gold 6526Y (not affected by GDS), GCC 14.3.1, Highway
AVX3_SPRtarget.Values are median timer ticks per element over five alternating baseline/patched runs, pinned to one CPU. Lower is better; speedup = baseline / patched.
Gather + eight dependent FMAs
Gather-only control