为什么下面的函数没有使用 Clang 生成尾递归?

Why the following function doesn't generate tail recursion with Clang?

本文关键字:Clang 尾递归 函数 为什么      更新时间:2023-10-16

在clang下,以下函数为尾部递归函数生成目标代码:

template<typename T>
constexpr bool is_prime(T number, T limit, T counter)
{
    return counter >= limit
        ? number % limit != 0
        : number % counter
            ? is_prime(number, number / counter, counter + 2)
            : false;
}
template<typename T>
constexpr bool is_prime(T n)
{
    return n == 2 || n == 3 || n == 5
        ? true
        : n <= 1 || n % 2 == 0
            ? false
            : is_prime(n, n / 3, T{3});
}

但是改变一行(让布尔结果"非规范化"),它停止生成尾部递归对象代码:

template<typename T>
constexpr bool is_prime(T number, T limit, T counter)
{
    return counter >= limit
        ? number % limit    // changed here
        : number % counter
            ? is_prime(number, number / counter, counter + 2)
            : false;
}
template<typename T>
constexpr bool is_prime(T n)
{
    return n == 2 || n == 3 || n == 5
        ? true
        : n <= 1 || n % 2 == 0
            ? false
            : is_prime(n, n / 3, T{3});
}

是clang没有正确优化它还是有一个合理的原因?

为了强制运行时求值,x是一个运行时整素数≥ 13(一个递归)或一个足够大的constexpr素数,因为大的递归深度会阻止编译时求值:

is_prime(x);

如果您有exp1 ? exp2 : exp3,为了确定?:语句的类型,将exp3的类型转换为exp2的类型(如果可能的话)。这意味着您的bool结果被转换为类型T,并且必须转换回bool才能返回。

这意味着递归调用不是最后一条语句。我相信如果你颠倒三元运算符的顺序,你会得到尾递归的结果。

template<typename T>
constexpr bool is_prime(T number, T limit, T counter)
{
    return counter < limit
        ? (number % counter
            ? is_prime(number, number / counter, counter + 2)
            : false)
        : number % limit;
}