This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Inlining heuristics for C++
- To: Daniel Berlin <dan at cgsoftware dot com>
- Subject: Re: Inlining heuristics for C++
- From: "Timothy J. Wood" <tjw at omnigroup dot com>
- Date: Mon, 9 Jul 2001 20:05:17 -0700
- Cc: gcc at gcc dot gnu dot org
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