【问题标题】:How gcc optimize sum from 1 to 100 into 5050gcc 如何将总和从 1 优化到 100 到 5050
【发布时间】:2021-04-29 23:24:50
【问题描述】:

我用gcc -O3 -S a.c编译了以下c程序:

#include <stdio.h>

int main() {
    int sum = 0;
    for (int i = 0; i <= 100; i++) {
        sum += i;
    }
    printf("%d", sum);
}

生成的汇编代码如下:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 15    sdk_version 10, 15, 4
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    leaq    L_.str(%rip), %rdi
    movl    $5050, %esi             ## imm = 0x13BA
    xorl    %eax, %eax
    callq   _printf
    xorl    %eax, %eax
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "%d"

.subsections_via_symbols

好像 GCC 运行代码并注意到循环时间已确定并且 GCC 替换了 整体计算,结果为 5050。

movl $5050, %esi

gcc 是如何做这种优化的呢? 这种优化的学术名称是什么?

【问题讨论】:

  • 它可能是以一种复杂的方式“不断折叠”。
  • 持续传播?
  • 似乎是专门针对算术级数的第一和第二次方之和的优化。例如 sum += 3*i*i + 2*i + 1; 得到优化,但添加第三次幂 i*i*i 运行实际循环。

标签: c gcc compiler-optimization


【解决方案1】:

我试图找到特定的标志,但没有运气。我只能用-O1 重现你的结果,所以我之后手动添加了-O1 启用的所有标志。但是当我这样做时,我无法重现结果。

并且可以在documentation中阅读

并非所有优化都直接由标志控制。此部分仅列出具有标志的优化。

所以我假设这是由-O1 添加的没有标志的东西完成的。

这是我尝试过的:

$ gcc -fauto-inc-dec  -fbranch-count-reg  -fcombine-stack-adjustments \
-fcompare-elim  -fcprop-registers  -fdce  -fdefer-pop  -fdelayed-branch  -fdse  \
-fforward-propagate  -fguess-branch-probability  -fif-conversion \
-fif-conversion2  -finline-functions-called-once  -fipa-profile  \
-fipa-pure-const  -fipa-reference  -fipa-reference-addressable \
-fmerge-constants  -fmove-loop-invariants  -fomit-frame-pointer \
-freorder-blocks  -fshrink-wrap  -fshrink-wrap-separate  -fsplit-wide-types  \
-fssa-backprop  -fssa-phiopt  -ftree-bit-ccp  -ftree-ccp  -ftree-ch \
-ftree-coalesce-vars  -ftree-copy-prop  -ftree-dce  -ftree-dominator-opts \
-ftree-dse  -ftree-forwprop  -ftree-fre  -ftree-phiprop  -ftree-pta \
-ftree-scev-cprop  -ftree-sink  -ftree-slsr  -ftree-sra  -ftree-ter \
-funit-at-a-time -S k.c 
cc1: warning: this target machine does not have delayed branches
$ grep "5050" k.s
$ gcc -O1 -S k.c
$ grep "5050" k.s
    movl    $5050, %esi
$ 

【讨论】:

  • 另外,-Og 不会优化计算,但 -O1 关闭所有选项,-Og 记录为禁用仍然可以。
【解决方案2】:

来自https://gcc.gnu.org/onlinedocs/gcc-4.5.2/gcc/Optimize-Options.html中的引用, 循环展开 (-funroll-loops) 和 RTL 上的前向传播传递 (-fforward-propagate) 启用优化级别 -O-O2-O3-Os

您可以尝试添加-funroll-loops-fforward-propagate 来确认吗?

【讨论】:

  • 不,-O1 -fno-unroll-loops -fno-forward-propagate 仍然是 optimizes it,而 -funroll-loops -fforward-propagate 没有。
  • gcc.gnu.org/wiki/FAQ#optimization-options 提到-O1 不等同于单个优化标志。请参阅 gcc.gnu.org/wiki/FAQ#optimization-flags 以了解各个优化级别启用的标志。
  • 对,但评论的重点是 -funroll-loops-fforward-propagate 对这种优化没有影响。优化是用-O1 完成的,没有-O1 就不能完成,不管你提到什么标志,所以它们与OP 的问题无关。
猜你喜欢
  • 1970-01-01
  • 2022-11-13
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多