混合 4 宽和 8 宽指令是否会严重损害性能?

问题描述 投票:0回答:0

我的 AVX 代码运行速度比 SSE4 版本慢得多,我正在尝试找出原因。

SSE4 中的这个小循环:

(gcc 13.1 的汇编)

.L6:
        movaps  xmm1, XMMWORD PTR [rbx+rsi]
        movaps  xmm3, XMMWORD PTR [rbp+0+rsi]
        movaps  xmm2, xmm4
        lea     eax, [0+rcx*4]
        movd    xmm0, eax
        add     rcx, 1
        add     rsi, 16
        addps   xmm3, xmm1
        cmpleps xmm1, xmm5
        pshufd  xmm0, xmm0, 0
        paddd   xmm0, xmm6
        cmpleps xmm2, xmm3
        pand    xmm1, xmm2
        movmskps edi, xmm1
        mov     rax, rdi
        sal     rdi, 4
        pshufb  xmm0, XMMWORD PTR shufmasks.0[rdi]
        popcnt  eax, eax
        movups  XMMWORD PTR [r8], xmm0
        lea     r8, [r8+rax*4]
        cmp     rcx, rdx
        jne     .L6

因为 AVX 没有 8 宽整数,所以我使用 8 宽寄存器,这样我就可以进行 8 宽浮点数学运算,但对于整数内容,我将它们就地拆分以在两个 4 宽指令中计算它们,然后将它们放回一起:

(gcc 13.1 的汇编)

.L6:
        lea     eax, [0+rcx*8]
        vmovaps ymm7, YMMWORD PTR [rbx+rsi]
        xor     r10d, r10d
        add     rcx, 1
        vmovd   xmm1, eax
        xor     eax, eax
        vpshufd xmm0, xmm1, 0
        vcmpleps ymm6, ymm7, ymm3
        vmovdqa xmm1, xmm0
        vpaddd  xmm0, xmm0, xmm5
        vpaddd  xmm1, xmm1, xmm2
        vinsertf128 ymm0, ymm0, xmm1, 0x1
        vaddps  ymm1, ymm7, YMMWORD PTR [r12+rsi]
        add     rsi, 32
        vcmpleps ymm1, ymm4, ymm1
        vandps  ymm1, ymm1, ymm6
        vmovaps xmm6, xmm0
        vextractf128 xmm0, ymm0, 0x1
        vmovaps xmm7, xmm1
        vextractf128 xmm1, ymm1, 0x1
        vmovmskps edx, xmm7
        popcnt  eax, edx
        sal     rdx, 4
        vpshufb xmm6, xmm6, XMMWORD PTR shufmasks.0[rdx]
        vmovmskps edx, xmm1
        popcnt  r10d, edx
        sal     rdx, 4
        vmovdqa XMMWORD PTR [rsp+32], xmm6
        vpshufb xmm0, xmm0, XMMWORD PTR shufmasks.0[rdx]
        movsx   rdx, eax
        add     eax, r10d
        vmovups XMMWORD PTR [rsp+32+rdx*4], xmm0
        vmovdqa ymm6, YMMWORD PTR [rsp+32]
        cdqe
        vmovdqu YMMWORD PTR [rdi], ymm6
        lea     rdi, [rdi+rax*4]
        cmp     rcx, r8
        jne     .L6

(gcc 12.2.0 的汇编)

.L4:
    vmovaps ymm11, YMMWORD PTR [rbx+rsi]
    vaddps  ymm12, ymm11, YMMWORD PTR [r12+rsi]
    xor eax, eax
    add rsi, 32
    lea r11d, 0[0+rcx*8]
    add rcx, 1
    vcmpleps    ymm14, ymm11, ymm3
    vmovd   xmm1, r11d
    xor r11d, r11d
    vcmpleps    ymm13, ymm4, ymm12
    vpshufd xmm0, xmm1, 0
    vpaddd  xmm7, xmm0, xmm5
    vpaddd  xmm9, xmm0, xmm8
    vinsertf128 ymm10, ymm7, xmm9, 0x1
    vandps  ymm15, ymm13, ymm14
    vextractf128    xmm0, ymm10, 0x1
    vextractf128    xmm1, ymm15, 0x1
    vmovmskps   r13d, xmm15
    vmovmskps   r14d, xmm1
    popcnt  eax, r13d
    sal r13, 4
    movsx   rdx, eax
    popcnt  r11d, r14d
    sal r14, 4
    vpshufb xmm7, xmm10, XMMWORD PTR [r8+r13]
    add eax, r11d
    vpshufb xmm9, xmm0, XMMWORD PTR [r8+r14]
    vmovdqa XMMWORD PTR 32[rsp], xmm7
    cdqe
    vmovups XMMWORD PTR 32[rsp+rdx*4], xmm9
    vmovdqa ymm10, YMMWORD PTR 32[rsp]
    vmovdqu YMMWORD PTR [rdi], ymm10
    lea rdi, [rdi+rax*4]
    cmp rcx, r9
    jne .L4

AVX 版本的长度是原来的 2 倍,但工作量却是原来的 2 倍,因此它应该是均衡的。但是当我测量这段代码时,AVX 版本的运行速度与标量版本一样慢。 AVX 循环中有什么特别慢的地方吗?在同一个循环中混合 4 宽和 8 宽指令是否会严重损害性能?或者是别的什么?我可以修复这个问题以使 AVX 版本至少赶上 SSE4 版本吗?

x86-64 simd avx
© www.soinside.com 2019 - 2024. All rights reserved.