考虑以下代码:
int x;
int a (int b) {
b = a (b);
b += x;
return b;
}
为什么GCC会返回这个输出(Intel语法):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
Clang输出以下结果(AT&T语法):http://goo.gl/Zz2rKA - Godbolt的Clang浏览器
a: # @a
pushq %rax
callq a
addl x(%rip), %eax
popq %rdx
ret
当代码的一部分明显无法到达时怎么办?由于函数的第一个语句是...
b = a (b);
该函数将永远递归调用自身(直到堆栈溢出并导致segfault)。这意味着您永远不会超越该行,因此,其余的代码是无法访问的。理论上,可达性优化应该删除该代码,对吗?
两个编译器都在x64上运行,并使用以下标志:
-O3
- 最大优化-march=native
- [不必要]尽可能使用机器特定的优化-x c
- 假定输入语言为C
我认为它们应该返回更符合以下内容(双关语):
GCC (Intel 语法):
a:
.L1:
jmp .L1
Clang(AT&T语法):
a:
.LBB0_1:
jmp .LBB0_1
注意:这些样例是根据以前的观察手写的,可能不正确。
总体而言,为什么两个编译器都没有因为其他代码无法到达而将函数崩溃到单个递归跳转?
编辑:
回应杰克有关语义等价性的评论:
对于以下代码:
int j (int x) {
while (1) {};
x++;
return x;
}
GCC返回:http://goo.gl/CYSUW2。
j:
.L2:
jmp .L2
Clang 返回:
j: # @j
.LBB0_1: # =>This Inner Loop Header: Depth=1
jmp .LBB0_1
对于Adam评论中关于堆栈溢出的回应:
针对以下代码:
int r (int x) {
return r (x);
}
GCC 生成了一个递归跳转:http://goo.gl/eWo2Nb
r:
.L2:
jmp .L2
Clang 在提前完成时会返回清洁信息:http://goo.gl/CVJKiZ
r: # @r
ret