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
Post a Comment