Visual C++ ~ Not inlining simple const function pointer calls -


dear stackoverflowers,

i got simple piece of code compiling on microsoft visual studio c++ 2012:

int add(int x, int y) {     return x + y; }  typedef int (*func_t)(int, int);  class { public:     const static func_t fp; };  const func_t a::fp = &add;  int main() {  int x = 3;  int y = 2;  int z = a::fp(x, y);  return 0; } 

the compiler generates following code:

int main() { 000000013fba2430  sub         rsp,28h   int x = 3; int y = 2; int z = a::fp(x, y); 000000013fba2434  mov         edx,2   000000013fba2439  lea         ecx,[rdx+1]   000000013fba243c  call        qword ptr [a::fp (013fba45c0h)]   return 0; 000000013fba2442  xor         eax,eax } 

i compiled on 'full optimisation' (/obx flag) , 'any suitable' inline function expansion. (/ob2 flag)

i wondering why compiler doesn't inline call expecially since it's const. of have idea why not inlined , if it's possible make compiler inline it?

christian

edit: running tests , msvc fails inline function pointers when:

-i move const pointer out of class , make global.

-i move const pointer out of class , make local in main.

-i make pointer non-const , move in locally.

-when make return type void , giving no parameters

i kind start believing microsoft visual studio cannot inline function pointers @ all...

the problem isn't inlining, compiler @ every opportunity. problem visual c++ doesn't seem realize pointer variable compile-time constant.

test-case:

// function_pointer_resolution.cpp : defines entry point console application. //  extern void show_int( int );  extern "c" typedef int binary_int_func( int, int );  extern "c" binary_int_func sum; extern "c" binary_int_func* const sum_ptr = sum;  inline int call( binary_int_func* binary, int a, int b ) { return (*binary)(a, b); }  template< binary_int_func* binary > inline int callt( int a, int b ) { return (*binary)(a, b); }  int main( void ) {     show_int( sum(1, 2) );     show_int( call(&sum, 3, 4) );     show_int( callt<&sum>(5, 6) );     show_int( (*sum_ptr)(1, 7) );     show_int( call(sum_ptr, 3, 8) ); //  show_int( callt<sum_ptr>(5, 9) );     return 0; }  // sum.cpp extern "c" int sum( int x, int y ) {     return x + y; }  // show_int.cpp #include <iostream>  void show_int( int n ) {     std::cout << n << std::endl; } 

the functions separated multiple compilation units give better control on inlining. specifically, don't want show_int inlined, since makes assembly code messy.

the first whiff of trouble valid code (the commented line) rejected visual c++. g++ has no problem it, visual c++ complains "expected compile-time constant expression". predictor of future behavior.

with optimization enabled , normal compilation semantics (no cross-module inlining), compiler generates:

_main   proc                        ; comdat  ; 18   :    show_int( sum(1, 2) );      push    2     push    1     call    _sum     push    eax     call    ?show_int@@yaxh@z           ; show_int  ; 19   :    show_int( call(&sum, 3, 4) );      push    4     push    3     call    _sum     push    eax     call    ?show_int@@yaxh@z           ; show_int  ; 20   :    show_int( callt<&sum>(5, 6) );      push    6     push    5     call    _sum     push    eax     call    ?show_int@@yaxh@z           ; show_int  ; 21   :    show_int( (*sum_ptr)(1, 7) );      push    7     push    1     call    dword ptr _sum_ptr     push    eax     call    ?show_int@@yaxh@z           ; show_int  ; 22   :    show_int( call(sum_ptr, 3, 8) );      push    8     push    3     call    dword ptr _sum_ptr     push    eax     call    ?show_int@@yaxh@z           ; show_int     add esp, 60                 ; 0000003ch  ; 23   :    //show_int( callt<sum_ptr>(5, 9) ); ; 24   :    return 0;      xor eax, eax  ; 25   : }      ret 0 _main   endp 

there's huge difference between using sum_ptr , not using sum_ptr. statements using sum_ptr generate indirect function call call dword ptr _sum_ptr while other statements generate direct function call call _sum, when source code used function pointer.

if enable inlining compiling function_pointer_resolution.cpp , sum.cpp /gl , linking /ltcg, find compiler inlines direct calls. indirect calls stay as-is.

_main   proc                        ; comdat  ; 18   :    show_int( sum(1, 2) );      push    3     call    ?show_int@@yaxh@z           ; show_int  ; 19   :    show_int( call(&sum, 3, 4) );      push    7     call    ?show_int@@yaxh@z           ; show_int  ; 20   :    show_int( callt<&sum>(5, 6) );      push    11                  ; 0000000bh     call    ?show_int@@yaxh@z           ; show_int  ; 21   :    show_int( (*sum_ptr)(1, 7) );      push    7     push    1     call    dword ptr _sum_ptr     push    eax     call    ?show_int@@yaxh@z           ; show_int  ; 22   :    show_int( call(sum_ptr, 3, 8) );      push    8     push    3     call    dword ptr _sum_ptr     push    eax     call    ?show_int@@yaxh@z           ; show_int     add esp, 36                 ; 00000024h  ; 23   :    //show_int( callt<sum_ptr>(5, 9) ); ; 24   :    return 0;      xor eax, eax  ; 25   : }      ret 0 _main   endp 

bottom-line: yes, compiler inline calls made through compile-time constant function pointer, long function pointer not read variable. use of function pointer got optimized:

call(&sum, 3, 4); 

but did not:

(*sum_ptr)(1, 7); 

all tests run visual c++ 2010 service pack 1, compiling x86, hosted on x64.

microsoft (r) 32-bit c/c++ optimizing compiler version 16.00.40219.01 80x86


Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

qt - Errors in generated MOC files for QT5 from cmake -