Frage

Here is my understanding of things:

A function "f" is tail recursive when calling itself is its last action. Tail-recursion can be significantly optimized by forming a loop instead of calling the function again; the function's parameters are updated in place, and the body is ran again. This is called recursive tail call optimization.

LLVM implements recursive tail call optimization when using fastcc, GHC, or the HiPE calling convention. http://llvm.org/docs/CodeGenerator.html#tail-call-optimization

I have some questions: Let's consider the silly example:

int h(int x){
  if (x <= 0)
    return x;
  else
    h(x-1);
}

1) In their example, the keyword "tail" preceeds call. Elsewhere I read that this keyword is optional. Suppose the function above is translated to LLVM appropriately, do the last few lines need to be

%x' = load *i32 %x
%m = tail call fastcc i32 @h(i32 %x')
ret %m

2) What is the meaning of the inreg option in their example?

3) I would not want to perform tail call optimizations all over the place, only for recursive functions. Is there a way I can get LLVM to only perform the optimization (when available) for recursive functions?

War es hilfreich?

Lösung

Apparently the answer is yes. You have to change the definition of h to see this (because the optimizer is too good! It figures out that h is either the identity or returns 0).

Consider

int factorial (int x, int y){
  if (x==0)
    return y;
  else
    return factorial(x-1,y*x);
}

Compiled with clang -S -emit-llvm, so that no optimization is performed. One sees that no calling conventions are directly specified, which means that the default calling convention is enough to support tail recursion optimization (whether or not it supports tail calling in general is a different story -- it would be interesting to know, but I guess that is really a different question).

The file emitted by clang -S -emit-llvm is main.s (assuming the factorial definition is in main.c). If you run

opt -O3 main.s -S -o mainOpt.s

then you can see that the tail recursion is eliminated. There is an optimization called tailcallelim which may be turned on as -O3. It's hard to tell because the help file, opt --help, says only that -O3 is similar to gcc -O3.

The point is that we can see that the calling convention does not need to specified for this. Maybe fastcc is not needed, or maybe it is default? So (1) is partially answered; however, I still do not know (2) or (3).

Andere Tipps

There are two different things here:

  1. You can optimise self-recursive tail calls into a loop. LLVM provides an optimisation pass that does this. It does not require a specific calling convention.
  2. You can use a different calling convention to guarantee tail call optimisation of all calls in tail position (i.e. including calls to other functions). With LLVM, you need to specify the calling convention on the function, on the call instruction and mark the call as a tail call.

Sounds like you want the former.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top