Skip to content

x86/clmul: use VEX-encoded 256-bit VPCLMULQDQ on CPUs without AVX-512#1417

Draft
fo40225 wants to merge 1 commit into
simd-everywhere:masterfrom
fo40225:fix_AVX512VL
Draft

x86/clmul: use VEX-encoded 256-bit VPCLMULQDQ on CPUs without AVX-512#1417
fo40225 wants to merge 1 commit into
simd-everywhere:masterfrom
fo40225:fix_AVX512VL

Conversation

@fo40225

@fo40225 fo40225 commented Jul 18, 2026

Copy link
Copy Markdown

Problem

simde_mm256_clmulepi64_epi128 requires both SIMDE_X86_VPCLMULQDQ_NATIVE and SIMDE_X86_AVX512VL_NATIVE to use the native intrinsic.

CPUs that support VPCLMULQDQ but lack AVX-512 notably AMD Zen 3 (Ryzen 5000 / EPYC 7003) fall back to the portable carry-less multiply emulation, which is orders of magnitude slower than the single hardware instruction.

Root cause

The guard follows the Intel Intrinsics Guide, which lists AVX512VL as a CPUID requirement but the Guide only documents the EVEX-encoded form.

Per the Intel SDM and AMD APM the instruction has two encodings:

Encoding CPUID requirement
VEX.256 VPCLMULQDQ + AVX
EVEX.256 VPCLMULQDQ + AVX512VL

The C intrinsic is not tied to an encoding: GCC ≥ 9.1 (PR target/88541) and Clang ≥ 10 emit the VEX form when compiling with -mvpclmulqdq -mavx and no AVX-512.

Changes

  • Native dispatch guard (256-bit): follow the pattern gfni.h already uses for the same VEX/EVEX situation VPCLMULQDQ && (AVX512VL || (AVX && !AVX512F)).
    The !AVX512F exclusion avoids configurations where a compiler could pick the EVEX encoding without AVX512VL being available.
  • Native alias guards (256- and 512-bit): &&||.
    An alias must be defined whenever any required feature is missing; with &&, a target having exactly one of the two features got neither the native definition nor the SIMDe alias, breaking SIMDE_ENABLE_NATIVE_ALIASES builds.
    This matches the existing convention elsewhere (e.g. sse2.h, gfni.h).
  • The 512-bit dispatch guard is unchanged: ZMM operations have no VEX encoding and inherently require AVX512F.

Verification

With GCC 13, simde_mm256_clmulepi64_epi128 now compiles to a single vpclmulqdq under -march=znver3 and -mvpclmulqdq -mavx (previously: portable fallback), still uses the native intrinsic under -mvpclmulqdq -mavx512vl, and correctly falls back with -mvpclmulqdq -mavx512f (no VL) and with plain -mpclmul -mavx2.

GFNI already handles this correctly, and SIMDe has no 256/512-bit VAES implementations, so this was the only remaining intrinsic affected by the VEX/EVEX distinction.

The Intel Intrinsics Guide lists VPCLMULQDQ + AVX512VL for
_mm256_clmulepi64_epi128, but that only describes the EVEX-encoded
form. The instruction also has a VEX.256 encoding which merely
requires VPCLMULQDQ + AVX, and compilers emit it when AVX-512 is not
enabled (GCC since 9.1 / PR target/88541, Clang since 10). Requiring
AVX512VL_NATIVE forced CPUs with VPCLMULQDQ but no AVX-512 -- notably
AMD Zen 3 -- onto the slow portable fallback.

Follow the pattern already used in gfni.h: use the native intrinsic
when AVX512VL is available, or when AVX is available without AVX512F
(the latter condition avoids compilers encoding the 256-bit form as
EVEX, which would require AVX512VL). The 512-bit intrinsic is
unchanged; ZMM has no VEX encoding.

Also fix the native alias guards to use OR instead of AND: an alias
must be defined whenever any required feature is missing, otherwise a
target with exactly one of the two features gets neither the native
definition nor the SIMDe alias and fails to compile under
SIMDE_ENABLE_NATIVE_ALIASES.
@fo40225
fo40225 marked this pull request as draft July 19, 2026 02:47
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.

1 participant