хвостовой вызов, сгенерированный clang 1.1 и 1.0 (llvm 2.7 и 2.6) - PullRequest
1 голос
/ 24 мая 2010

После компиляции следующий фрагмент кода с помощью 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 генерирует такой код?

Также я не могу понять, почему у llvm есть tail call, если он может просто проверить, что следующий ret будет использовать результат prev call, а затем выполнить соответствующую оптимизацию или сгенерировать собственный эквивалент команды tail-call? 1021 *

1 Ответ

3 голосов
/ 25 мая 2010

Посмотрите инструкцию 'call' в Справочном руководстве по языку сборки LLVM . Там написано:

Необязательный маркер "tail" указывает, что функция вызываемого абонента не имеет доступа к allocas или varargs в вызывающем абоненте. Обратите внимание, что вызовы могут быть помечены как "tail", даже если они не происходят до инструкции ret.

Вполне вероятно, что один из этапов оптимизации LLVM в Clang анализирует, получает ли вызываемый доступ какие-либо сообщения или переменные в вызывающем абоненте. Если это не так, проход помечает вызов как хвостовой вызов и позволяет другой части LLVM выяснить, что делать с маркером «хвоста». Может быть, функция не может быть реальным вызовом хвоста прямо сейчас, но после дальнейших преобразований это может быть. Я предполагаю, что это сделано таким образом, чтобы упорядочение проходов было менее важным.

...