2015-09-03 81 views
4

下面是一個簡單的Hello World:爲什麼這是一個尾巴呼叫?

#include <stdio.h> 

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

這被編譯成LLVM IR:

[email protected]:~$ 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立即跟在 呼叫和ret使用呼叫值或無效)。

然而在這個例子中puts()返回的值不應該被用作函數的返回值。

這是一個合法的尾呼優化? main()返回什麼?

回答

3

LLVM中的tail標誌有點奇怪。它只是意味着對puts的調用是tail call優化的候選者,特別是不允許訪問調用者堆棧上的任何變量。代碼生成器仍然必須確保該呼叫在它實際上將呼叫轉變爲跳轉之前處於適合於尾部呼叫優化的位置,並且這不是這種情況。

如果你看一下由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