10

I am experimenting new feature of the c++11, constexpr especially. If I want to code a pow with template I will simply do:

//pow
template<class T, std::size_t n>
struct helper_pow{
    inline static T pow(T const& a){
        return a*helper_pow<T,n-1>::pow(a);
    }
};

//final specialization pow 
template<class T>
struct helper_pow<T,0>{
    inline static T pow(T const& a){
        return 1;
    }
};

Now if I call my function into my code simply by:

pow<double,5>(a) // where a is double

the corresponding assembly will be (gcc 4.8.0, -O2):

   movapd  %xmm0, %xmm1
    movsd   %xmm0, 24(%rsp)
    mulsd   %xmm0, %xmm1
    movq    %rbx, %rdi
    mulsd   %xmm0, %xmm1
    mulsd   %xmm0, %xmm1
    mulsd   %xmm0, %xmm1

Fine the code is inline.

If know I am looking the constexpr version, I have

template <class T>
inline constexpr T pow(T const& x, std::size_t n){
    return n>0 ? x*pow(x,n-1):1;
} 

The corresponding assembly is now:

    movsd   24(%rsp), %xmm2
    leaq    24(%rsp), %rdi
    movl    $4, %esi
    movsd   %xmm2, 8(%rsp)
    call    __Z3powIdET_RS0_m

where the function __Z#powIdET_RS0_m seems define by

LCFI1:
    mulsd   %xmm1, %xmm0
    movapd  %xmm0, %xmm2
    mulsd   %xmm1, %xmm2
    mulsd   %xmm2, %xmm1
    movapd  %xmm1, %xmm0
    ret

So do you have any idea why with constexpr the function is not inline and consider as "an external" function ? Does it exist a way to force the inline of a constexpr function ? Best.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Timocafé
  • 765
  • 6
  • 18
  • 1
    Why is the argument to your constexpr `pow` not const? – Sebastian Redl Aug 20 '13 at 11:59
  • If I interpret the disassembly of my g++ 4.8.1 (`-O2`) correctly, it *does* inline (and unroll the recursion of) your `pow` for small exponents, if the exponent is a literal (known at compile-time should suffice). For larger exponents (e.g. 10), it introduces a function. At `-O3`, it inlines even for higher exponents (14). – dyp Aug 20 '13 at 12:11
  • Sebastian: I forget ^_^, DyP: interesting, I gonna try a new version of compiler – Timocafé Aug 20 '13 at 13:09
  • 1
    The `constexpr` version actually got better optimized, looks like it is `O(lg N)` rather than `O(N)` in the exponent, too bad it didn't get inlined. – Ben Voigt Aug 20 '13 at 16:04

2 Answers2

1

inline is nothing more than a hint for the compiler. It can do whatever it prefers. It exists compiler specific stuff like pragmas and __declspec to force on or off the inlining on a function.

May be the non const lvalue reference of the constexpr version interfers. You should just pass by value to a pow anyway.

galop1n
  • 8,573
  • 22
  • 36
1

It is not an error for a particular instantiation of a constexpr function template to not be really constexpr, as long as you don't attempt to use it in a context that requires a constant expression. Maybe your instantiated template is not constexpr.

To find out, do this:

constexpr double powtest = pow(2.0, 5);

If the compiler complains, you know there's something wrong.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Right, I know this feature. Well I was more looking for switching my present implementation with template, by constexpr but with one "dynamic" parameter – Timocafé Aug 20 '13 at 13:16
  • 3
    Ah, so basically you're worried that the compiler inlined the old version and doesn't inline the new one. That's interesting indeed, especially since it apparently partially specializes the constexpr function. – Sebastian Redl Aug 20 '13 at 15:39
  • yes exactly, the inline remove a lot of management of the stack. I should read carefully the norm, and maybe post a question of the GCC forum about the feature. – Timocafé Aug 20 '13 at 15:47