为什么GCC在使用-O 0编译目标文件时没有使用LTO消除函数死代码?

zsbz8rwp  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(89)

范例:
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


但是,如果我这样做:

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


所以我的问题是-O1notmain.o目标文件中做了什么改变,导致优化没有完成?
有趣的是,我还尝试将-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:

lto-dump -dump-body=notmain2 notmain.o


但是我看不出有什么明显不同,对于-O1

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

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

}


使用-O0

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上测试。

vyswwuz2

vyswwuz21#

如果所有这些都失败了,请阅读手册。
请注意,仅在链接时而不是在编译时指定优化级别选项通常是无效的,原因有二。首先,不进行优化的编译会抑制在链接时收集有效优化所需信息的编译器遍数。第二,一些早期的优化过程只能在编译时执行,而不能在链接时执行。

相关问题