You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何func_a中的两个循环未发生C++循环融合?

为何GCC未对func_a的两个循环进行融合优化?

等价函数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

问题

为何func_a中的两个循环未发生循环融合?手动融合后的func_b是我期望的func_a优化版本。

回答

GCC的循环融合优化并非在所有等价场景下都会触发,func_a未被融合主要有几方面原因:

  • 数据流分析的局限性:func_a的两个循环是完全独立的,sum1和sum2分别在不同循环中累加,优化器的数据流分析没有将这两个变量的操作关联起来,没有识别到可以把它们的合并到同一个循环中执行。虽然最终数学结果等价,但优化器没有判定这两个循环属于可融合的高优先级场景。
  • -Ofast的优化侧重点:-Ofast虽属于激进优化选项,但它更偏向于放宽标准约束(如忽略NaN/Inf检查)、加速浮点运算等方向,对循环融合这类需要深度代码结构分析的优化,并没有强制触发所有可能的变换。
  • 循环融合的触发规则:GCC的循环融合通常更倾向于处理有内存访问复用、操作重叠的场景,而func_a的两个循环只是重复执行相同的读取和累加,优化器选择了分别对每个循环做SIMD向量化,而非先融合再优化。

从汇编也能明显看出差异:func_b只遍历数组一次,最后将累加结果翻倍;而func_a是两次完整遍历数组,即便用了SIMD优化,重复的内存访问开销依然高于前者。


内容的提问来源于stack exchange,提问作者user5406764

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:50:55