【问题标题】:Why is this a tail call?为什么这是尾声?
【发布时间】:2015-09-03 16:13:07
【问题描述】:

这是一个简单的hello world:

#include <stdio.h>

int main() {
    printf("hello world\n");
    return 0;
}

这里编译为 LLVM IR:

will@ox:~$ clang -S -O3 -emit-llvm ~/test_apps/hello1.c -o -
; ModuleID = '/home/will/test_apps/hello1.c'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@str = private unnamed_addr constant [12 x i8] c"hello world\00"

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  %puts = tail call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @str, i64 0, i64 0))
  ret i32 0
}

; Function Attrs: nounwind
declare i32 @puts(i8* nocapture readonly) #1

attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }

!llvm.ident = !{!0}

!0 = !{!"Ubuntu clang version 3.6.0-2ubuntu1 (tags/RELEASE_360/final) (based on LLVM 3.6.0)"}

description of tail-call optimisation 表示必须满足以下条件:

调用是尾调用 - 在尾部位置(ret 紧随其后 call 和 ret 使用 call 的值或者是 void)。

但在本例中,puts() 返回的值不应用作函数的返回值。

这是合法的尾随优化吗? main() 返回什么?

【问题讨论】:

    标签: optimization llvm tail-call-optimization


    【解决方案1】:

    LLVM 中的tail 标志有点奇怪。这只是意味着对 puts 的调用是尾调用优化的候选者,特别是它不允许访问调用者堆栈上的任何变量。代码生成器仍然必须确保调用处于适合尾调用优化的位置,然后才能真正将调用转换为跳转,而这里不是这种情况。

    如果您查看 LLVM 发出的程序集,您会发现没有发生尾调用优化:

    $ clang -O -S -o - bug.c
            [...]
    main:                                   # @main
            .cfi_startproc
    # BB#0:                                 # %entry
            pushq   %rax
    .Ltmp0:
            .cfi_def_cfa_offset 16
            movl    $.Lstr, %edi
            callq   puts
            xorl    %eax, %eax
            popq    %rdx
            retq
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多