强制 clang 发出操作码的 pmull2/umull2 变体

问题描述

我有这个(和类似的)代码片段,我希望在其中发出 umull2 或 pmull2 指令。编译器 clang-11.0.1,选项 -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};
}

而不是像这样的代码

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

编译器选择了

    ldrb    w9,v0.8b
    ext     v6.16b,v6.16b,#8 // aligns top 8 bytes over bottom 8 bytes  
    pmull   v7.8h,v1.8b        // uses a copy of v0.8 also shifted by 8 bytes
    ext     v2.16b,#8
    pmull   v6.8h,v4.8b
    pmull   v2.8h,v5.8b

处理 uint8x16_t 或 uint16x8_t 无关紧要——这似乎是 clang 避免访问寄存器的最高位的反复出现的主题。我还没有找到一种 -mtune=cortex-73 类型的选项来强制生成不同的代码,所以我至少可以评估这是否通常性能较低(我希望它在小内核上)。 ARM64 gcc 按预期工作。

如果已知 ext 指令与 pmull 双重发出,而两个 pmull 则不会,这可能无关紧要(除了明智的大小和分配较少的寄存器)。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)