使用 clang -O2 (或使用在线演示)编译下一段代码后:
#include <stdio.h>
#include <stdlib.h>
int flop(int x);
int flip(int x) {
if (x == 0) return 1;
return (x+1)*flop(x-1);
}
int flop(int x) {
if (x == 0) return 1;
return (x+0)*flip(x-1);
}
int main(int argc, char **argv) {
printf("%d\n", flip(atoi(argv[1])));
}
我正在获得下一个 llvm 程序集片段flip
:
bb1.i: ; preds = %bb1
%4 = add nsw i32 %x, -2 ; <i32> [#uses=1]
%5 = tail call i32 @flip(i32 %4) nounwind ; <i32> [#uses=1]
%6 = mul nsw i32 %5, %2 ; <i32> [#uses=1]
br label %flop.exit
我认为这tail call
意味着删除当前堆栈(即返回将是上帧,所以下一条指令应该是ret %5
),但根据这段代码它会这样做mul
。在本机汇编中,call
没有尾部优化很简单(即使有适当的 llc 标志)
有人能解释一下为什么clang会生成这样的代码吗?
同样,我不明白为什么 llvmtail call
可以简单地检查下一个ret
将使用 prev 的结果,call
然后进行适当的优化或生成与尾调用指令等效的本机?