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

为何GCC在-O0编译目标文件时LTO不执行函数死代码消除?

GCC LTO死代码消除差异:-O1 vs -O0编译目标文件的区别

示例代码

notmain.c

int __attribute__ ((noinline)) notmain(int i) {
    return i + 1;
}

int notmain2(int i) {
    return i + 2;
}

main.c

int notmain(int);

int main(int argc, char **argv) {
    return notmain(argc);
}

测试过程与现象

我用noinline属性确保现象并非notmain是否被内联带来的次生效应。

用-O1编译并反汇编

执行命令:

gcc -c -flto -O1 notmain.c
gcc -flto -O3 notmain.o main.c
objdump -d a.out

结果:notmain保留,notmain2被死代码消除:

0000000000001040 <main>:
    1040:       f3 0f 1e fa             endbr64
    1044:       e9 f0 00 00 00          jmp    1139 <notmain>
    1049:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001139 <notmain>:
    1139:       8d 47 01                lea    0x1(%rdi),%eax
    113c:       c3                      ret

用-O0编译并反汇编

改用以下命令:

gcc -c -flto -O0 notmain.c
gcc -flto -O3 notmain.o main.c
objdump -d a.out

结果:两个函数都保留:

0000000000001040 <main>:
    1040:       f3 0f 1e fa             endbr64
    1044:       e9 f0 00 00 00          jmp    1139 <notmain>
    1049:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001139 <notmain>:
    1139:       f3 0f 1e fa             endbr64
    113d:       55                      push   %rbp
    113e:       48 89 e5                mov    %rsp,%rbp
    1141:       89 7d fc                mov    %edi,-0x4(%rbp)
    1144:       8b 45 fc                mov    -0x4(%rbp),%eax
    1147:       83 c0 01                add    $0x1,%eax
    114a:       5d                      pop    %rbp
    114b:       c3                      ret

000000000000114c <notmain2>:
    114c:       f3 0f 1e fa             endbr64
    1150:       55                      push   %rbp
    1151:       48 89 e5                mov    %rsp,%rbp
    1154:       89 7d fc                mov    %edi,-0x4(%rbp)
    1157:       8b 45 fc                mov    -0x4(%rbp),%eax
    115a:       83 c0 02                add    $0x2,%eax
    115d:       5d                      pop    %rbp
    115e:       c3                      ret

核心问题

我想知道:-O1编译notmain.o时做了哪些改动,让LTO能对notmain2执行死代码消除,而-O0编译时却做不到?

排查尝试

我尝试找出-O1中哪个具体优化选项导致这个现象,把man gcc里列出的-O1启用的所有选项单独加进去编译:

gcc -c -flto -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-modref -fipa-profile -fipa-pure-const -fipa-reference -fipa-reference-addressable -fmerge-constants -fmove-loop-invariants -fmove-loop-stores -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 notmain.c
gcc -flto -O3 notmain.o main.c
objdump -d a.out

但此时notmain2依然保留,没被消除。

我又用lto-dump查看LTO中间代码,对比-O1和-O0编译的notmain.o里notmain2的Gimple代码:

-O1编译时的notmain2 Gimple代码

Gimple Body of Function: notmain2
int notmain2 (int i)
{
  int _2;

  <bb 2> [local count: 1073741824]:
  _2 = i_1(D) + 2;
  return _2;

}

-O0编译时的notmain2 Gimple代码

Gimple Body of Function: notmain2
int notmain2 (int i)
{
  int D.4724;
  int _2;

  <bb 2> :
  _2 = i_1(D) + 2;

  <bb 3> :
<L0>:
  return _2;

}

两者没有明显差异。

测试环境:Ubuntu 23.04,GCC 12.2.0。

内容的提问来源于stack exchange,提问作者Ciro Santilli OurBigBook.com

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 00:54:56