views:

175

answers:

3

I know I can pass a function pointer as a template parameter and get a call to it inlined but I wondered if any compilers these days can inline an 'obvious' inline-able function like:

inline static void Print()
{
 std::cout << "Hello\n";
}

....

void (*func)() = Print;

func();

Under Visual Studio 2008 its clever enough to get it down to a direct call instruction so it seems a shame it can't take it a step further?

+1  A: 

Well the compiler doesn't really know if that variable will be overwritten somewhere or not (maybe in another thread?) so it errs on the side of caution and implements it as a function call.

I just checked in VS2010 in a release build and it didn't get inlined.

By the way, you decorating the function as inline is useless. The standard says that if you ever get the address of a function, any inline hint will be ignored.

edit: note however that while your function didn't get inlined, the variable IS gone. In the disassembly the call uses a direct address, it doesn't load the variable in a register and calls that.

Blindy
Yes that's what I thought so I just tried __restrict on it and also const to no avail. Yes I tried inline and __forceinline as you never know :)IE: void (*const __restrict func)() = Local::Print;I was hoping in VS2010 they might have it due to lambda's etc - does __restrict change the situation in VS2010 by any chance?Thanks
wb
No, the compiler refuses to inline that, which is a bit strange because if it eliminates the variable, then there's no danger of the variable ever changing, so it could just replace the `call` with the function body. Oh well..
Blindy
the compiler doesn't have to assume that the variable could be overwritten in another thread. If there is a chance that the same thread could overwrite the variable, the compiler has to play it safe, but in a simple case like that shown by the OP, there's no risk of that either (which is also why it's able to eliminate the variable). The compiler *should* be able to inline a simple case like that.
jalf
Yes, see my edit, it DOES realize the variable won't be overwritten so it just drops it altogether and makes a hardcoded call to the `Print` function. It should inline it, but it doesn't.
Blindy
It would be nice indeed if MSVC++ could do what GCC can in this situation. Still its useful to know it should be able to do it for sure.
wb
+2  A: 

GNU's g++ 4.5 inlines it for me starting at optimization level -O1

main:
    subq    $8, %rsp
    movl    $6, %edx
    movl    $.LC0, %esi
    movl    $_ZSt4cout, %edi
    call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_E
    movl    $0, %eax
    addq    $8, %rsp
    ret

where .LC0 is the .string "Hello\n".

To compare, with no optimization, g++ -O0, it did not inline:

main:
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp
    movq    $_ZL5Printv, -8(%rbp)
    movq    -8(%rbp), %rax
    call    *%rax
    movl    $0, %eax
    leave
    ret
Cubbi
Great that's good to know as there are various helpful constructs where this would make their use zero performance impact :)A shame that Visual C++ isn't as smart yet!Thanks.
wb
+2  A: 

Newer releases of GCC (4.4 and up) have an option named -findirect-inlining. If GCC can prove to itself that the function pointer is constant then it makes a direct call to the function or inlines the function entirely.

Zan Lynx