x86/avx512/dpbf16: avoid GCC's broken 512-bit masked intrinsics#1419
Open
fo40225 wants to merge 1 commit into
Open
x86/avx512/dpbf16: avoid GCC's broken 512-bit masked intrinsics#1419fo40225 wants to merge 1 commit into
fo40225 wants to merge 1 commit into
Conversation
GCC's insn pattern for the masked/maskz forms of vdpbf16ps declares the
mask operand with the half-width mask mode (<avx512fmaskhalfmode>), so
_mm512_{mask,maskz}_dpbf16_ps load the __mmask16 argument with kmovb
and silently drop the upper 8 mask bits. Lanes 8-15 then behave as if
their mask bit were clear: the mask form passes src through and the
maskz form zeroes the lane. The bug is present in every GCC release
with AVX512BF16 support, GCC through at least GCC 16.1; clang is
unaffected.
This went unnoticed until CI runners gained AVX512-BF16 hardware
(GitHub's runner fleet now includes Zen4/Zen5), where -march=native
builds exercise the real intrinsics:
test/x86/avx512/dpbf16.c:1003: assertion failed:
r[10] ~= ... (-2.320000 ~= 102.099998) [mask: src passthrough]
test/x86/avx512/dpbf16.c:1192: assertion failed:
r[9] ~= ... (0.000000 ~= -1506.540039) [maskz: zeroed]
Route GCC around the buggy intrinsics via the unmasked native
vdpbf16ps plus mask_mov/maskz_mov, which GCC compiles to a correct
kmovw + vdpbf16ps + masked vmovaps sequence. The 128/256-bit variants
take a __mmask8 and are unaffected.
Verified on an AMD EPYC 9474F (zen4, avx512_bf16) with GCC 16.1.0:
before this change the masked intrinsics compute lanes 8-15
incorrectly, matching the CI failures byte for byte; after it all
dpbf16 tests pass. Intel SDE (-spr) shows lane-identical behavior,
confirming the bug is in GCC's codegen, not the hardware.
mr-c
requested changes
Jul 19, 2026
mr-c
left a comment
Collaborator
There was a problem hiding this comment.
Thank you very much for the investigation and fix @fo40225 !
We'll need a GCC bug number so a !defined(SIMDE_BUG_GCC_126NNN guard can be used instead of !defined(HEDLEY_GCC_VERSION).
The guard needs to be added to simde/simde-common.h alongside the others; that way, after fixes for various GCC versions are released, that can be implemented in one place.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
x86/avx512/dpbf16/native/{c,cpp}fails on CI runners that support AVX512-BF16 (GitHub's runner fleet now includes Zen4 / Emerald Rapids / Granite Rapids machines, so-march=nativebuilds exercise the real intrinsics).The failures are always in the
mm512_mask_/mm512_maskz_subtests, always in lanes 8-15, and the wrong values are exactly src-passthrough (mask form) or zero (maskz form):Root cause
A GCC code-generation bug, not a SIMDe emulation bug.
GCC's insn patterns
avx512f_dpbf16ps_<mode>_mask{,z}declare the mask operand with<avx512fmaskhalfmode>, which is QImode for V16SF, so_mm512_{mask,maskz}_dpbf16_psload their__mmask16argument withkmovband silently drop the upper 8 mask bits:The bug is present in every GCC release with AVX512BF16 support (GCC through at least GCC 16.1, still present on trunk).
clang emits
kmovdand is unaffected.This is also the actual root cause of issue 1095 : the emulated implementation was never wrong, so no test-vector regeneration is needed (vectors regenerated on hardware through GCC's masked intrinsics would bake this GCC bug into the expected values of the masked tests).
Fix
For GCC, implement the two 512-bit masked variants as the unmasked native
vdpbf16psplusmask_mov/maskz_mov.GCC compiles this to a correct, still fully native
kmovw+vdpbf16ps+ maskedvmovapssequence, so the cost is a single blend instruction.The 128/256-bit variants take a
__mmask8, for whichkmovbis correct, and are left untouched.Verification
avx512_bf16) with GCC 16.1.0, a minimal reproducer shows lanes 8-15 wrong for both masked forms before the fix; the SIMDe test built from master reproduces the CI failures byte for byte, and the test built from this branch passes all 9 dpbf16 subtests.-spr): lane-identical behavior to the AMD hardware, confirming the bug lives in GCC's generated code rather than in either vendor's silicon.Follow-up
This should be reported to GCC bugzilla (no existing report found); the likely fix there is changing the mask operand of the
avx512f_dpbf16ps_<mode>_mask{,z}patterns ingcc/config/i386from<avx512fmaskhalfmode>to<avx512fmaskmode>.Once a fixed GCC release exists, the guard here can become version-gated.