4

I'm playing a little bit with constexpr recursion and try to see how it is compiled and I don't understand under which circumstances gcc choose to calculate the recursion at compile time or at run time.

I'm using the following factorial calculation code :

#include <iostream>

constexpr unsigned int factorial(unsigned int i)
{
  return i > 0 ? i*factorial(i-1) : 1;
}

int main(void)
{
  std::cout << factorial(X) << std::endl;
}

and I change the value x in the factorial.

  • When compiling without optimization, the expression is not calculated at compile time.
  • When compiling with the -O1 flag, the expression is still not calculated at compile time.
  • With -O2, the expression is calculated at compile time if x < 9. After this value, the factorial is implemented inline as a loop. Changing the value of -fconstexpr-depth flag doesn't change a thing.
  • With -O3, the expression is calculated at compile time if x < 7. After this value, the factorial is implemented inline with x86 xmm extension.
  • If I change the product for an sum in the factorial function, I obtain compile time calculation up to 10000 or more and reducing or increasing the value of -fconstexpr-depth doesn't change anything.

Does anyone knows what are the rules for gcc 4.7 to implement the recursive function as compile-time or run-time?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • Try `typedef char dummy[factorial(10)]` and see if it compiles. Array sizes must be constant expressions. – Kerrek SB Jan 20 '13 at 01:55
  • If you check on the bug list of gcc, it contains lots with `constexpr`. I would not rely on `constexpr` being correctly implemented and/or working by gcc (4.7.2 or even 4.8.0). – Walter Jan 20 '13 at 18:43

2 Answers2

2

constexpr is only guaranteed to be evaluated at compile-time if it's needed at compile-time. For instance, this is guaranteed to be computed at compile-time, because enum values must be constant:

enum { VALUE = factorial(X) };
cout << VALUE << endl;

In any case where it's not needed at compile-time, it has the same effect as declaring it as inline: it's just a hint, and the compiler is free to do what it wants.

Just like inline, most compilers nowadays will completely ignore your hint. For performance reasons, the compiler wants to be able to inline things even when you haven't asked it to, and has its own algorithm to determine when it is and isn't worthwhile, so why would it bother looking at the inline keyword at all?

Rick Yorgason
  • 1,616
  • 14
  • 22
1

Declaring a function constexpr does not mean that it will be evaluated at compile-time. It means that it can be used to compute a value which is needed at compile-time. In any other context, it's just an ordinary function, and it will be evaluated at runtime unless the compiler determines that evaluating it at compile time satisfies the "as-if" rule, and is worthwhile doing.

In other words, I'd expect you'd find exactly the same pattern of compile-time/run-time execution if you left constexpr out of the declaration of the factorial function.

rici
  • 234,347
  • 28
  • 237
  • 341