开发者

Do compilers optimize away calls to trivial functions made through pointers?

开发者 https://www.devze.com 2023-03-10 16:37 出处:网络
Say I have a function that takes a function pointer: in开发者_开发知识库t funct(double (*f)(double));

Say I have a function that takes a function pointer:

in开发者_开发知识库t funct(double (*f)(double));

And I pass it a function that doesn't actually do anything:

double g(double a) { return 1.0;}
//...
funct(g);

Will the compiler optimize out the calls to g? Or will this still have overhead? If it does have overhead, how much? Enough that it is worth overloading the function to receive both function pointers and constant values?


Newer versions of GCC (4.4 and later) can inline and optimize a known function pointer using the option -findirect-inlining. This only works when GCC also knows all of the code that uses the pointer.

For example, the C library function qsort will not benefit from this optimization. The compiled machine code for qsort is in the library, it expects a function pointer and the compiler cannot change that.

However, if you had your own implementation of qsort and you placed it in a header file or you used the very new GCC link-time optimization features, then GCC would be able to take your calling code, the function pointed to, and your qsort source and compile it all together, optimized for your data types and your comparison function.

Now, the only times that this really matters is when the function call overhead is much larger than the function itself. In your example of a function that does nothing much, using a function pointer is serious overhead. In my example of a qsort comparison, the function pointer call is also quite expensive. But in some other application like Windows event dispatch, it hardly matters.

Since you are using C++ you should study templates. A template function can accept a so-called function object which is just an object that implements operator() and it can accept function pointers. Passing a function object will allow the C++ compiler to inline and optimize almost all of the code involved.


Any modern compiler can (and will) easily optimize out (i.e. inline) calls made through function pointers is situations when the compiler knows where the pointer is pointing to at compile time.

In your specific example in general case the value of the pointer cannot be predicted at compile time at the point of the call, since it is passed from outside as a parameter of function funct. In situations when the function funct itself is small enough to get inlined, the run-time parameter gets eliminated and the whole code of funct gets "dissolved" in the functs caller context. In the value of the pointer is known in that caller context, then, again, the compiler can easily eliminate the call through the pointer.

Finally, if the function funct is relatively heavy (meaning it does not get inlined), the you should probably expect the compiler to generate an ordinary run-time call through the pointer from inside of funct. The potential for call elimination exists in this case as well, since the compiler can theoretically generate a separate version of funct for each compile-time value of g. For example, if you have

int funct(int x1, int x2, int x3, double (*f)(double));

which is called with only two possible arguments for parameter f

funct(rand(), rand(), rand(), g1);
...
funct(rand(), rand(), rand(), g2);

then the compiler can "reduce" it into two functions

int funct_g1(int x1, int x2, int x3);
int funct_g2(int x1, int x2, int x3);

without a function pointer parameters and with direct calls to either g1 and g2 inside. (Of course, this optimization is not in any way tied to function pointers and can be applied to any function parameter that is used with only a small fixed set of arguments. In fact, this is similar to C++ templates.) But I'm not aware of any compilers that would do anything like that.


The compiler will probably not optimize it, because the function funct can receive pointers to different functions, not just g, and they don't have to come from the same compiling unit (thus the compiler cannot assume it knows about all the possible calls).

You need to benchmark your code to see if the optimization you're talking about is necessary, and if it is - just do it. But unless funct calls g a lot, I wouldn't expect this to matter.

0

精彩评论

暂无评论...
验证码 换一张
取 消