简体   繁体   English

为什么编译器不能优化这些无法访问的指令?

[英]Why doesn't the compiler optimize out these unreachable instructions?

Given this code: 鉴于此代码:

int x;

int a (int b) {
    b = a (b);
    b += x;
    return b;
}

why does GCC return this output (Intel Syntax): http://goo.gl/8D32F1 - Godbolt's GCC Explorer 为什么GCC会返回此输出(英特尔语法): http//goo.gl/8D32F1 - Godbolt的GCC Explorer

a:
    sub rsp, 8
    call    a
    mov edx, DWORD PTR x[rip]
    add rsp, 8
    lea eax, [rax+rdx*8]
    add eax, edx
    ret

and Clang return this output (AT&T Syntax): http://goo.gl/Zz2rKA - Godbolt's Clang Explorer 和Clang返回此输出(AT&T语法): http//goo.gl/Zz2rKA - Godbolt的Clang Explorer

a:                                      # @a
    pushq   %rax
    callq   a
    addl    x(%rip), %eax
    popq    %rdx
    ret

when part of the code is clearly unreachable? 当部分代码明显无法访问时? Since the very first statement of the function is 因为函数的第一个陈述是

b = a (b);

the function will forever keep calling itself recursively (until the stack overflows and you get a segfault). 该函数将永远保持递归调用自身(直到堆栈溢出,你得到一个段错误)。 This means that you will never go beyond that line, and therefore, the rest of the code is unreachable. 这意味着您永远不会超越该行,因此,其余代码无法访问。 Reachability optimization should in theory remove the code, correct? 可达性优化理论上应该删除代码,对吗?


Both compilers were running on x64 and with the following flags 两个编译器都在x64上运行,并带有以下标志

  • -O3 - max optimization -O3 - 最大化优化
  • -march=native - [unnecessary] use machine specific optimizations when possible -march=native - [不必要]尽可能使用机器特定的优化
  • -xc - assume input language is C -xc - 假设输入语言为C.

I was thinking that they should have returned something more along the lines (pun intended) of this: 我当时认为他们应该返回更多内容(双关语):

GCC (Intel Syntax): GCC(英特尔语法):

a:
.L1:
    jmp .L1

Clang (AT&T Syntax): Clang(AT&T语法):

a:
.LBB0_1:
    jmp .LBB0_1

note: these samples were written by hand from memory of previous observations and may be incorrect. 注意:这些样本是从以前观察的记忆中手工编写的,可能不正确。


So overall, why don't either of the compilers collapse the function into a single recursive jump due to the rest of the code being unreachable? 总的来说,为什么没有任何一个编译器将函数折叠成单个递归跳转,因为其余代码无法访问?


EDIT: 编辑:

Response to Jack's comment on semantic equivalence: 回应杰克关于语义等价的评论:

For the following code: 对于以下代码:

int j (int x) {
    while (1) {};
    x++;
    return x;
}

GCC returns: http://goo.gl/CYSUW2 GCC返回: http//goo.gl/CYSUW2

j:
.L2:
    jmp .L2

Clang returns: Clang回归:

j:                                      # @j
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
    jmp .LBB0_1

Response to Adam's comment on blowing out the stack: 回应亚当关于吹掉堆栈的评论:

For this code: 对于此代码:

int r (int x) {
    return r (x);
}

GCC generates a recursive jump: http://goo.gl/eWo2Nb GCC生成递归跳转: http//goo.gl/eWo2Nb

r:
.L2:
    jmp .L2

Clang returns cleanly early: http://goo.gl/CVJKiZ Clang很早就回来了: http//goo.gl/CVJKiZ

r:                                      # @r
    ret

The compilers you're using probably implement data flow analysis only at the block level within a single function frame, not taking into consideration recursion. 您正在使用的编译器可能仅在单个函数框架内的块级别实现数据流分析,而不考虑递归。 (Or perhaps, only interesting recursion, namely tail recursion.) Since the recursive call isn't a tail call, it isn't interesting from an optimization point of view. (或许,只有有趣的递归,即尾递归。)由于递归调用不是尾调用,从优化的角度来看它并不有意思。

Your function has a problem: the way it is compiled, it blows up the stack. 你的函数有一个问题:它的编译方式,它会炸毁堆栈。 It is compiled that way because the call isn't a tail call; 它是这样编译的,因为调用不是尾调用; it is not a legitimate optimization to treat it as one. 将它视为一个合法的优化并不合理。

The call could be considered a "pseudo tail call" on grounds that that the code after the call is never invoked, and so if we remove that code, then the recursive call is the last thing which the function does. 该调用可以被认为是“伪尾调用”,理由是调用后的代码永远不会被调用,因此如果我们删除该代码,那么递归调用是函数执行的最后一件事。 Then we could reduce the stack-blowing code to a mere infinite loop. 然后我们可以将堆栈代码减少到仅仅是无限循环。 This cannot really be called an optimization, though; 但是,这实际上不能称为优化; it's the replacement of one bug manifestation by a different bug manifestation. 它是由不同的bug表现形式替换一个bug表现形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM