Forcing clang to emit pmull2/umull2 variants of opcodes

Viewed 106

I have this (and similar) pieces of code where I expect umull2 or pmull2 instructions to be emitted. Compiler clang-11.0.1, options -O3 -std=c++11 -target aarch64

#include "stdint.h"
#include "arm_neon.h"
inline poly16x8_t vmull_low_p8(poly8x16_t a, poly8x16_t b) {
    return vmull_p8(vget_low_p8(a), vget_low_p8(b));
}
// evaluates polynomials of length `len > 0` using Horner's method
// for 16 points `x`, `X = x 2^m mod n`
poly16x8x2_t p(const uint8_t *input, int len, poly8x16_t x, poly8x16_t X) {
    auto ptr = input + len;
    auto L = vdupq_n_p16(*--ptr), H = L;
    while (ptr > input) {
        auto s = vuzpq_p8(vreinterpretq_p8_p16(L), vreinterpretq_p8_p16(H));
        auto a = vmull_low_p8(s.val[0], x);
        auto b = vmull_high_p8(s.val[0], x);
        auto A = vmull_low_p8(s.val[1], X);
        auto B = vmull_high_p8(s.val[1], X);
        auto C = vdupq_n_p16(*--ptr);
        L = C ^ a ^ A;
        H = C ^ b ^ B;
    }
    return {L,H};
}

Instead of having code like

    ldrb    w9, [x8, #-1]!
    uzp1    v6.16b, v2.16b, v3.16b
    uzp2    v2.16b, v2.16b, v3.16b
    pmull   v3.8h, v6.8b, v0.8b
    pmull2  v7.8h, v6.8b, v0.8b
    pmull   v6.8h, v6.8b, v4.8b
    pmull2  v2.8h, v2.8b, v4.8b

the compiler has chosen to

    ldrb    w9, [x8, #-1]!
    uzp1    v6.16b, v2.16b, v3.16b
    uzp2    v2.16b, v2.16b, v3.16b
    pmull   v3.8h, v6.8b, v0.8b
    ext     v6.16b, v6.16b, v6.16b, #8 // aligns top 8 bytes over bottom 8 bytes  
    pmull   v7.8h, v2.8b, v1.8b        // uses a copy of v0.8 also shifted by 8 bytes
    ext     v2.16b, v2.16b, v2.16b, #8
    pmull   v6.8h, v6.8b, v4.8b
    pmull   v2.8h, v2.8b, v5.8b

Working on uint8x16_t or uint16x8_t does not matter -- and this seems to be a recurring theme of clang avoiding the top bits of a register to be accessed. I haven't found a -mtune=cortex-73 kind of an option that would force a different code generation, so I could at least assess if this is generally less performant (which I expect it to be on little cores). ARM64 gcc works as expected.

This may not matter (except for size wise and having less registers allocated) if the ext instructions are known to double-issue with pmull where as two pmulls would not.

0 Answers
Related