clang 1.1和1.0(llvm 2.7和2.6)生成的尾部调用

clang 1.1和1.0(llvm 2.7和2.6)生成的尾部调用,llvm,clang,Llvm,Clang,使用clang-O2(或使用)编译下一段代码后: 我认为tail call意味着丢弃当前堆栈(即返回到上一帧,因此下一条指令应该是ret%5),但根据此代码,它将为其执行mul。在本机程序集中,有简单的调用,没有尾部优化(即使有适当的llc标志) sombody能解释为什么clang会生成这样的代码吗 此外,如果llvm可以简单地检查nextret是否将使用prevcall的结果,然后进行适当的优化或生成本机等效的尾部调用指令,我也无法理解为什么llvm会有tail call。它说: 可选的“t

使用clang-O2(或使用)编译下一段代码后:

我认为
tail call
意味着丢弃当前堆栈(即返回到上一帧,因此下一条指令应该是
ret%5
),但根据此代码,它将为其执行
mul
。在本机程序集中,有简单的
调用
,没有尾部优化(即使有适当的llc标志)

sombody能解释为什么clang会生成这样的代码吗

此外,如果llvm可以简单地检查next
ret
是否将使用prev
call的结果,然后进行适当的优化或生成本机等效的尾部调用指令,我也无法理解为什么llvm会有
tail call
。它说:

可选的“tail”标记表示被调用者函数不访问调用者中的任何alloca或varargs。请注意,调用可能被标记为“tail”,即使它们不是在ret指令之前发生的


很可能有一个LLVM优化过程通过Clang分析被调用者是否访问调用者中的任何alloca或vararg。如果没有,pass会将调用标记为tail调用,并让LLVM的另一部分了解如何使用“tail”标记。也许这个函数现在不可能是真正的尾部调用,但经过进一步的转换之后,它可能是。我猜这样做是为了让过程的顺序变得不那么重要。

是的,
ret
不需要正好在
tail call
之后,因为llvm可能会决定对指令重新排序。隐马尔可夫模型。。。对于Clang来说,在不检查依赖项的情况下放置
tail
可能是明智的。让llvm检查它。
#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])));
}
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