Skip to content

Request to revert: polyval: use avx+pclmulqdq features on x86/x86_64 #317 #346

Closed

Description

@SirDMZ

PCLMULQDQ: Introduced in 2010. Fairly Old. The code needs this. Safe to feature gate out.

VEX: vpclmulqdq in asm in this code base is VEX-encoded 128-bit (needs only AVX+PCLMULQDQ) AVX came out in 2011. Fairly Old.

Per Issue 184, the desire is to have vpclmulqdq asm produced. Per my benchmarking it is 0.5% faster, and potentially 4% faster depending on other factors.
Per issue 315, while AVX is fairly old, some... cheaper CPU's didn't/don't ship with it, breaking the goal of producing VEX (vpclmulqdq in asm).

So cool. Lets feature gate up this high. Fairly old. AVX2 came out in full in 2017 (AMD Zen1), so almost 10 years ago.

There's potential further discussion to have with AVX1 vs AVX2, but someone else can advocate for that.

VPCLMULQDQ the CPUID Flag: arrives with Intel Ice Lake and newer, and AMD Zen 4. Which rules out a lot of actually still in use CPU's. Feature gating this high prevents fast code on cpu's that support it. This is VEX.256. The code doesn't currently use such widths.

The performance hit is 0.26GiB/s vs 5.94GiB/s in my benchmarks on a LOT of genuinely still used CPU's.

; Legacy SSE (PCLMULQDQ flag)
pclmulqdq xmm0, xmm1, 0x00 ; xmm0 = xmm0 * xmm1

; VEX 128-bit (AVX + PCLMULQDQ — NOT the new flag)
vpclmulqdq xmm0, xmm1, xmm2, 0x00 ; 3-operand, 1 multiply

; VPCLMULQDQ flag — YMM (VEX.256)
vpclmulqdq ymm0, ymm1, ymm2, 0x11 ; 2 independent 64x64→128 multiplies

; VPCLMULQDQ + AVX512F — ZMM (EVEX.512)
vpclmulqdq zmm0, zmm1, zmm2, 0x10 ; 4 independent multiplies

Maybe in future, the codebase could get optimisations for these wider options. There's currently a separate issue for that.

#318 can still be technically correct. it IS optimised for VEX 128-bit which in asm is vpclmulqdq . I don't propose reverting it.

Steam hardware survey doesn't appear to expose these exact flags, but AVX 2 is at 95% and AVX512F is at 23%.

Activity

  1. tarcieri commented on Jul 10, 2026

    @tarcieri
    Member

    Okay, so if I understand correctly: "vpclmulqdq" seems to mean two different things:

    1. It's the notation used in ASM when invoking PCLMULQDQ with VEX operands, regardless of if they're 128-bit or 256-bit
    2. It's also seemingly used in many contexts to refer specifically to the AVX2 version with 256-bit operands

    So I think the #[target_feature(enable = "avx", enable = "pclmulqdq")] attributes in #317 are correct, and the real problem is:

    cpufeatures::new!(clmul, "vpclmulqdq");

    So we should just change that to:

    cpufeatures::new!(clmul, "avx", "pclmulqdq");

    ...to match the target_feature gating (and remove all the TODO comments about vpclmulqdq)

    Sound good?

    (Ironically the goal of #317 was to make it work on more platforms, but it seems we accidentally made it work on fewer)

  2. newpavlov commented on Jul 10, 2026

    @newpavlov
    Member

    Yeah, we should generally mirror what we use in #[target_feature(...)]s. I think I expected that vpclmulqdq is equivalent to avx + pclmulqdq based on the reference, but I guess it's not true in practice.

  3. tarcieri commented on Jul 10, 2026

    @tarcieri
    Member

    Perhaps the target_feature TODOs are fine. The real problem seems to be CPUID's idea of vpclmulqdq is the AVX2 version.

  4. SirDMZ commented on Jul 11, 2026

    @SirDMZ
    Author

    Per https://docs.rs/cpufeatures/latest/src/cpufeatures/x86.rs.html
    ("vpclmulqdq", "zmm", 1, ecx, 10)

    So yes! their detect is filtering to what I read as AVX-512. Which is... worse than I had originally thought, but not that I can benchmark to detect. Oops. Unsure of why they might have done that.

    We probably want, which to my understanding aligns with the code.
    cpufeatures::new!(clmul, "avx", "pclmulqdq");

  5. SirDMZ commented on Jul 11, 2026

    @SirDMZ
    Author

    RustCrypto/utils@481df9d

    Confirmed, they assumed vpclmulqdq is a AVX512 feature. So that's how their feature gating works.

  6. tarcieri commented on Jul 11, 2026

    @tarcieri
    Member

    I opened #347 to address this.

    @SirDMZ if you can confirm this fixes the issue, I can cut a release. Unfortunately I don't have any hardware old enough for this distinction to matter to test on myself.

  7. SirDMZ commented on Jul 11, 2026

    @SirDMZ
    Author

    TLDR: yes, this fixes it.

    I forked polyval, and have been running that all day with this change applied.

    I've updated the benchmark to reflect the discussed change. Test here is on Ryzen 3000 series.

    results.txt

    Edit: apparently github didn't like the formatting of the benchmark results.

  8. newpavlov commented on Jul 11, 2026

    @newpavlov
    Member

    So yes! their detect is filtering to what I read as AVX-512.

    Hm, it may be worth to create a cpufeatures issue for that and look into what std does with the feature.

  9. tarcieri commented on Jul 11, 2026

    @tarcieri
    Member

    This was released in polyval v0.7.2 in #348

  10. added a commit that references this issue on Jul 28, 2026
    feb26f6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions