[ Reported to the Debian BTS as report #173513. Please CC 173513@bugs.debian.org on replies. Log of report can be found at http://bugs.debian.org/173513 ] Currently GCC will not inline a call of a function pointer that is known at compile time. For example, the following code will still result in the instruction "call funk" when run with -finline-functions on i386: #include <stdio.h> static char* funk() { return "Hello World.\n"; } static void funky(char*(*func)()) { printf("%s", func()); } void main() { funky(funk); } Although the call to funky is inlined, the call to funk is not, because in the source code it appears as a call of a function pointer. But as a consequence of funky being inlined, it would be possible to inline funk as well. Release: 3.2.1 (Debian) (Debian unstable) Environment: System: Debian GNU/Linux (unstable) Architecture: i686 host: i386-linux Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,proto,pascal,objc,ada --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.2 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-java-gc=boehm --enable-objc-gc i386-linux Thread model: posix gcc version 3.2.2 20021212 (Debian prerelease)
State-Changed-From-To: open->analyzed State-Changed-Why: Confirmed on all branches
Mark this a dup of bug 3713 which was for c++ but now for all languages. *** This bug has been marked as a duplicate of 3713 ***
Subject: Re: Bug#173513: Inline constant function pointers pinskia at physics dot uc dot edu writes: > Mark this a dup of bug 3713 which was for c++ but now for all languages. > > *** This bug has been marked as a duplicate of 3713 *** I fail to see a resolution to this report. The call to funk is not inlined.
Subject: Re: Inline constant function pointers On Tuesday, Jul 8, 2003, at 00:50 US/Eastern, doko at cs dot tu-berlin dot de wrote: > ------- Additional Comments From doko at cs dot tu-berlin dot de > 2003-07-08 04:50 ------- > Subject: Re: Bug#173513: Inline constant function pointers > > pinskia at physics dot uc dot edu writes: >> Mark this a dup of bug 3713 which was for c++ but now for all >> languages. >> >> *** This bug has been marked as a duplicate of 3713 *** > > I fail to see a resolution to this report. The call to funk is not > inlined. This bug was the same bug as 3713 which means that they were the same bug. Having two bugs referring to the same bug in the database is usually not good because we cannot keep track of which bugs are important and which bugs or not and we also cannot keep track of which bugs get fixed, that is why bugs are marked as duplicates of each other. I hope this bug gets fixed for the tree-ssa branch which makes working on the tree a lot easier and the it can fold the constant function pointer and then maybe inline it. Thanks, Andrew Pinski
Actually this is different than PR 3713.
And I have a patch which is for tree-ssa.
I should say that I have a partial fix for the tree-ssa, what needs to be done is inlining again.
Patch which also helps it the same way as my cast pass (which I am not going to submit at all).
The patch which helps is here: <http://gcc.gnu.org/ml/gcc-patches/2004-05/msg00991.html>.
I just hit this bug in a hairy piece of code which I reduced to the testcase below (a should compile to the same thing as expected). It's the same as this bug but with two layers of indirection instead of one. #define inline inline __attribute__((always_inline)) #define regparm __attribute__((regparm(3))) extern void regparm f(void); static inline void regparm e(void) { f(); } static inline void regparm d(void) { f(); } static inline void regparm c(int x, void (regparm *p1)(void), void (regparm *p2)(void)) { if (x) p1(); else p2(); } static inline void regparm b(int x, void (regparm *p)(int x, void (regparm *p1)(void), void (regparm *p2)(void))) { p(x, d, e); } void regparm a(int x) { b(x, c); } void regparm expected(int x __attribute__((unused))) { f(); }
This is present in 3.4 too -------------------------------------------- static inline int foo () { return 100; } typedef int (*fptr)(); static const fptr a [] = { foo }; static inline int call (int i) { return a [i](); } static inline int call2 (fptr f) { return f(); } static const fptr F = foo; int main () { return call (0) + call2 (foo) + F() +foo(); } --------------------------------------------------- Here only F() and foo() are added at compile time but it would be better if gcc just returned 400 w/o any other code. Please fix!
*** This bug has been marked as a duplicate of 3713 ***
Again this is different than PR 3713. (steven is closing bugs which are not really fixed or dups right now).
*** Bug 28470 has been marked as a duplicate of this bug. ***
*** Bug 32751 has been marked as a duplicate of this bug. ***
OK, this is fixed in gcc 4.3 (woot!), but the unused "funk" is still omitted. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35728
Note this is only fixed because we run inlining "twice". It isn't fixed properly in that the new inlining opportunity should be exposed during the first inlining pass.
I'm now working on a proper fix.
As of revision 138092 we are handling this much better. The example in bug description gets inlined at -O2 even with -fno-early-inlining. The example in comment #10 does not work as expected yet. The new edge is discovered but the always_inline attribute is disregarded and the inlined does not decide to inline it on its own. I will try to fix this but it should be noted that few guarantees can be made about indirect calls to always_inline functions and about always_inline functions which have their addresses taken in general. As far as the third example in comment #11 is concerned, the only problem is loading the target function from the array. The loaded value is not recognized to be constant early enough to be considered for inlining. That is really a separate issue though, quite different from the one originally described. I will have a look at what we can do earlier but I will close the bug if this is the only outstanding issue and I don't see an easy fix.
OK, here is the status regarding the trunk (4.4) and the test cases posted here: 1. The test case in the bug description now works in the sense that funk is inlined even when not performing early inlining because both indirect inlining and copy propagation can help the inliner do this. 2. When compiling the code from comment #10 with indirect inlining turned on (default on -O2) we end up with (taken from the "optimized" tree dump): a (int x) { <bb 2>: if (x != 0) goto <bb 3>; else goto <bb 4>; <bb 3>: f (); [tail call] goto <bb 5>; <bb 4>: f (); [tail call] <bb 5>: return; } Which obviously might be optimized even further but this is no longer an inlining issue. 3. Finally, let's look at code from comment #11. The function main still retains one call to foo(), specifically the one that came from function call(). The reason is that early cpp does not see the index being constant and thus does not replace the array_ref directly with the constant. Arguments could be made that cpp should be run few more times at various places (after ipa-cp, for example) but IMHO pass ordering would need bigger justification than this artificial example and this would be very difficult to implement while also retaining the three phase division of ipa passes for lto. Because we are done with all three examples as far as inlining is concerned, I think this is fixed.