This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Inlining heuristics for C++



On Monday, July 9, 2001, at 06:46  PM, Daniel Berlin wrote:
[...]
> We proceed to recursively inline 128 functions into this simple main 
> function
> operator call. (Bet you didn't think there were 128 functions you could
> inline here)

   IMO, the bug here is that the library you are using declares too many 
inlines.  I (personally) believe that 'inline' should be a command, not 
a request, and that a warning should be issued if inlining fails for 
some reason.  If you have the compiler decide to not inline stuff that 
is marked inline, then someone is going to come up with a case where 
they really need the inline where you didn't let them have it.  Then 
there will ensue a bunch of flags for controlling the inline limits and 
you're back to the programmer deciding when things should be inlined, 
but through a clumsier interface.  Or worse yet, they'll start using 
macros to get around the limits.



[...]
> This is effectively expressing the rule: "Small functions should be
> inlined into larger ones.  Larger functions should not be inlined into
> small ones".


   This rule is not true in general.  Just one example off the top of my 
head would be a case where you define a general inline function for 
performing some algorithm where some of the arguments are constants and 
you then define other 'real' functions that effectively pass 
configuration parameters (expecting the optimizer to treat them as 
constants and toss out different dead code in each case).


   A silly little example might be:

static inline void generalCase(enum type t, enum operation op, ...)
{
     if (t == type1 || t == type3) {
	if (op == op1)
		block1;
	else
		block2;
     } else if (t == type2 && op == op1) {
	block3;
     }
	....
}


void t1op1(...)
{
	generalCase(type1, op1, ...);
}

void t2op2(...)
{
	generalCase(type2, op2, ...);
}


   With this approach, you can often avoid needless duplication of code 
in the general case and can 'instantiate' the general case in each 
specific context and should be able to expect the compiler to blow away 
cases that can't be executed based on the inputs.

   Not only can make your code simpler, but you might have a couple 
common case that will perform better by having removed many of the 
branches from the general case.

   But, it is definitely the case, that the inlined function can be 
bigger than the function it is getting inlined into (which could just be 
a call to the inline!)


-tim


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]