Почему это вызов?

Вот простой привет мир:

#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)"}

В описании оптимизации хвостового вызова сказано, что должны быть выполнены следующие условия:

Вызов является хвостовым вызовом - в конечной позиции (ret следует сразу за вызовом, а ret использует значение call или является недействительным).

Тем не менее в этом примере значение, возвращаемое puts() не должен использоваться в качестве возвращаемого значения функции.

Это легальная оптимизация? Что значит main() вернуть?

1 ответ

Решение

tail Флаг в LLVM немного странный. Это просто означает, что вызов put является кандидатом для оптимизации хвостового вызова, в частности, ему не разрешен доступ к какой-либо переменной в стеке вызывающей стороны. Генератор кода все еще должен убедиться, что вызов находится в положении, подходящем для оптимизации хвостового вызова, прежде чем он фактически превратит вызов в переход, и здесь это не так.

Если вы посмотрите на сборку, генерируемую 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
Другие вопросы по тегам