Why isn't g++ tail call optimizing while gcc is?

前端 未结 3 1512
忘掉有多难
忘掉有多难 2020-12-31 15:36

I wanted to check whether g++ supports tail calling so I wrote this simple program to check it: http://ideone.com/hnXHv

using namespace std;

size_t st;

v         


        
3条回答
  •  南笙
    南笙 (楼主)
    2020-12-31 16:16

    The original code with temporary std::string object is still tail recursive, since the destructor for that object is executed immediately after exit from PrintStackTop("");, so nothing should be executed after the recursive return statement.

    However, there are two issues that lead to confusion of tail call optimization (TCO):

    • the argument is passed by reference to the PrintStackTop function
    • non-trivial destructor of std::string

    It can be verified by custom class that each of those two issues is able to break TCO. As it is noted in the previous answer by @Potatoswatter there is a workaround for both of those issues. It is enough to wrap call of PrintStackTop by another function to help the compiler to perform TCO even with temporary std::string:

    void PrintStackTopTail()
    {
        PrintStackTop("tail");
    }
    int TailCallFactorial(int n, int a = 1)
    {
        PrintStackTopTail();
    //...
    }
    

    Note that is not enough to limit the scope by enclosing { PrintStackTop("tail"); } in curly braces. It must be enclosed as a separate function.

    Now it can be verified with g++ version 4.7.2 (compilation options -O2) that tail recursion is replaced by a loop.

    The similar issue is observed in Pass-by-reference hinders gcc from tail call elimination

    Note that printing (st - (size_t) &stack_top) is not enough to be sure that TCO is performed, for example with the optimization option -O3 the function TailCallFactorial is self inlined five times, so TailCallFactorial(5) is executed as a single function call, but the issue is revealed for larger argument values (for example for TailCallFactorial(15);). So, the TCO may be verified by reviewing assembly output generated with the -S flag.

提交回复
热议问题