C++ 循环融合似乎没有发生

C++ loop fusion does not seem to happen

提问人:user5406764 提问时间:10/16/2023 最后编辑:user5406764 更新时间:10/16/2023 访问量:183

问:

考虑两个函数,func_a func_b,它们产生等效的结果:

int func_a(int const* const arr)
{
    int sum1 = 0;
    for (int i = 0; i < 200; ++i)
        sum1 += arr[i];

    int sum2 = 0;
    for (int i = 0; i < 200; ++i)
        sum2 += arr[i];

    return sum1 + sum2;
}

int func_b(int const* const arr)
{
    int sum1 = 0;
    int sum2 = 0;
    for (int i = 0; i < 200; ++i)
    {
        sum1 += arr[i];
        sum2 += arr[i];
    }
    return sum1 + sum2;
}

看看他们生成的程序集 (g++ 13.2 std=c++20 -Ofast):

func_a(int const*):
        lea     rdx, [rdi+800]
        mov     rax, rdi
        pxor    xmm0, xmm0
.L2:
        movdqu  xmm3, XMMWORD PTR [rax]
        add     rax, 16
        paddd   xmm0, xmm3
        cmp     rax, rdx
        jne     .L2
        movdqa  xmm1, xmm0
        psrldq  xmm1, 8
        paddd   xmm0, xmm1
        movdqa  xmm1, xmm0
        psrldq  xmm1, 4
        paddd   xmm0, xmm1
        movdqa  xmm1, xmm0
        pxor    xmm0, xmm0
.L3:
        movdqu  xmm4, XMMWORD PTR [rdi]
        add     rdi, 16
        paddd   xmm0, xmm4
        cmp     rdi, rdx
        jne     .L3
        movdqa  xmm2, xmm0
        psrldq  xmm2, 8
        paddd   xmm0, xmm2
        movdqa  xmm2, xmm0
        psrldq  xmm2, 4
        paddd   xmm0, xmm2
        paddd   xmm0, xmm1
        movd    eax, xmm0
        ret

func_b(int const*):
        lea     rax, [rdi+800]
        pxor    xmm0, xmm0
.L8:
        movdqu  xmm2, XMMWORD PTR [rdi]
        add     rdi, 16
        paddd   xmm0, xmm2
        cmp     rax, rdi
        jne     .L8
        movdqa  xmm1, xmm0
        psrldq  xmm1, 8
        paddd   xmm0, xmm1
        movdqa  xmm1, xmm0
        psrldq  xmm1, 4
        paddd   xmm0, xmm1
        movd    eax, xmm0
        add     eax, eax
        ret

Q1:为什么func_a中的两个环路没有融合?

作为参考,手动融合的func_b显示了我希望func_a的优化版本是什么。

C++ 循环 优化

评论

5赞 harold 10/16/2023
GCC 不实现循环融合。
1赞 500 - Internal Server Error 10/16/2023
在这种情况下,两个循环读取的值相同,所以我认为这将是一个优势。-- 我在阅读(更不用说编码)SIMD 代码方面没有那么有经验,但我对循环产生结果所需的逻辑量感到惊讶。
1赞 ChrisMM 10/16/2023
ICC 确实在 O3 上融合它们,但不是 O2
3赞 Jérôme Richard 10/16/2023
请注意,在某些情况下,循环融合可能会对性能造成不利影响(在这种微不足道的情况下,无论如何都可以轻松手动完成)。循环融合使代码更难矢量化,增加了寄存器压力,并可能导致有关缓存关联性(仅已知)和循环中使用的数组数量的缓存丢弃。事实上,AFAIK,GCC 因此实现了环裂变。这将导致与环路融合的混淆。矢量化和缓存比不从 L1 重新加载数据更重要。-march=...
4赞 Peter 10/16/2023
这是另一个基于错误前提的问题,即优化是强制性的,因此如果不实施,则必须有理由。该标准不要求进行此类优化,因此允许实现不提供此类优化。任何提供它的实现都可能将其设置为可选(例如,默认禁用,可选择通过优化设置激活)和/或接受分析(例如,仅在计算相关指标时执行[它们可能不是]并显示出好处)。

答: 暂无答案