32

On GCC manual,

-foptimize-sibling-calls

Optimize sibling and tail recursive calls.

I know tail recursive calls, for example

int sum(int n) { return n == 1 ? 1 : n + sum(n-1); }

However, what does sibling calls mean?

buaagg
  • 599
  • 6
  • 11
  • 1
    [First Google hit](http://www.drdobbs.com/tackling-c-tail-calls/184401756) apparently has some info – Angew is no longer proud of SO Feb 26 '14 at 09:41
  • 3
    In practice, GCC synonym for "tail" (they refer to it as _a.k.a. tail_ in the internals documentation). Formally, _some function_ which has a return type of the same size _and_ a parameter list of the same total word size. Thus, e.g. `int foo(char, char)` and `int bar(short)` would be siblings and could be tail-optimized (so `foo` calling `bar` which calls `foo` would in principle work). – Damon Feb 28 '14 at 15:25
  • 1
    @AngewisnolongerproudofSO this question is the first Google hit for "sibling calls function meaning" so it should have some info too. – Boris Verkhovskiy Mar 04 '21 at 07:25

3 Answers3

19

Tail Calls

If a function call is a last action performed in another function, it is said to be a tail call.

The name stems from the fact that the function call appears at the tail position of other function.

int foo(int a, int b) {
    // some code ...
    return bar(b);    // Tail call which is neither sibling call nor tail recursive call.
}

bar appears at the tail position of foo. Call to bar is a tail call.


Tail Recursive Calls

Tail recursive call is a special case of tail call where callee function is same as caller function.

int foo(int a, int b) {
    if (a > 0) {
        return foo(a - 1, b + 1);    // Tail recursive call
    } else {
        return b;
    }
}

Sibling Calls

Sibling call is another special case of tail call where caller function and callee function do not need to be same, but they have compatible stack footprint.

That means the return types of both functions must be same, and the arguments being passed must take same stack space.

int foo(int a, int b) {
    // some code ...
    return bar(a - 1, b);    // Sibling call, also a tail call, but not a tail recursive call.
}

Every tail recursive call is a sibling call, Since the definition implies every function is a sibling of itself.


Why Distinction?

Because of identical stack footprint, replacing stack frame becomes relatively easier. Compiler writers don't have to resize stack frame, and in place mutation becomes straightforward.

Tanmay Patil
  • 6,882
  • 2
  • 25
  • 45
8

the compiler considers two functions as being siblings if they share the same structural equivalence of return types, as well as matching space requirements of their arguments.

http://www.drdobbs.com/tackling-c-tail-calls/184401756

Samuel Danielson
  • 5,231
  • 3
  • 35
  • 37
7

It must be something like this:

int ispair(int n) { return n == 0 ? 1 : isodd(n-1); }
int isodd(int n) { return n == 0 ? 0 : ispair(n-1); }

In general, if the function call is the last sentence, then it can be replaced by a jump.

void x() { ......; y(); }

In this case y() can be replaced by a jump (or an inline function) instead of using a standard function call.

Javier
  • 376
  • 2
  • 12