On Thu, Jun 18, 2026 at 5:03 PM Eldar Osmanovic <[email protected]> wrote: > > From: Robert Suchanek <[email protected]> > > --param early-inlining-insns-cold=NUMBER > --param max-inline-insns-small-and-cold=NUMBER > > Analysis shows that the main difference between -O2 and -Os goes down to > inlining of cold or unlikely functions. The new parameters (defaulted to > 0) mean to disable these limitations with -Os. NUMBER could be set to > something like 4-32 to see the impact. > > The main reason that smaller functions are treated as cold or unlikely > is the function cgraph_maybe_hot_edge_p () always returning FALSE for > -Os.
Not sure if we want a knob like this, we might also want to distinguish between -Oz and -0s here and/or probably_never_executed_edge_p? Inlining already has too many knobs IMO. Also see below. > gcc/ > * ipa-inline.cc (want_early_inline_function_p): Check if the > growth is greater than param_early_inlining_insns_cold. > (want_inline_small_function_p): Check if the growth is greater > than param_max_inline_insns_small_and_cold. > * params.opt (early-inlining-insns-cold): New option. > (max-inline-insns-small-and-cold): Likewise. > > gcc/testsuite/ > * gcc.dg/inline-cold-1.c: New test. > * gcc.dg/inline-cold-2.c: New test. > * gcc.dg/ipa/inline-cold-1.c: New test. > * gcc.dg/ipa/inline-cold-2.c: New test. > > Cherry-picked c38d7e548cbb3defb141efb528cb356333e8eb7a > from https://github.com/MIPS/gcc > > Signed-off-by: Robert Suchanek <[email protected]> > Signed-off-by: Faraz Shahbazker <[email protected]> > Signed-off-by: Aleksandar Rakic <[email protected]> > Signed-off-by: Eldar Osmanovic <[email protected]> > --- > gcc/ipa-inline.cc | 4 +++- > gcc/params.opt | 8 ++++++++ > gcc/testsuite/gcc.dg/inline-cold-1.c | 21 +++++++++++++++++++++ > gcc/testsuite/gcc.dg/inline-cold-2.c | 21 +++++++++++++++++++++ > gcc/testsuite/gcc.dg/ipa/inline-cold-1.c | 21 +++++++++++++++++++++ > gcc/testsuite/gcc.dg/ipa/inline-cold-2.c | 21 +++++++++++++++++++++ > 6 files changed, 95 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.dg/inline-cold-1.c > create mode 100644 gcc/testsuite/gcc.dg/inline-cold-2.c > create mode 100644 gcc/testsuite/gcc.dg/ipa/inline-cold-1.c > create mode 100644 gcc/testsuite/gcc.dg/ipa/inline-cold-2.c > > diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc > index 5a7615666cc..928c2bb3f92 100644 > --- a/gcc/ipa-inline.cc > +++ b/gcc/ipa-inline.cc > @@ -819,7 +819,8 @@ want_early_inline_function_p (struct cgraph_edge *e) > > if (!want_inline || growth <= param_max_inline_insns_size) > ; > - else if (!e->maybe_hot_p ()) > + else if (!e->maybe_hot_p () > + && growth > param_early_inlining_insns_cold) But then you should diagnose when growth exceeds early_inlining_insns_cold (but not early_inlining_insns) and the edge maybe cold? > { > if (dump_enabled_p ()) > dump_printf_loc (MSG_MISSED_OPTIMIZATION, e->call_stmt, > @@ -1082,6 +1083,7 @@ want_inline_small_function_p (struct cgraph_edge *e, > bool report) > } > /* If call is cold, do not inline when function body would grow. */ > else if (!e->maybe_hot_p (callee_speedup (e)) > + && growth > param_max_inline_insns_small_and_cold > && (growth >= inline_insns_single (e->caller, false, false) > || growth_positive_p (callee, e, growth))) > { > diff --git a/gcc/params.opt b/gcc/params.opt > index 90f9943c8cb..f89b5b2dd5b 100644 > --- a/gcc/params.opt > +++ b/gcc/params.opt > @@ -150,6 +150,10 @@ Maximum size (in bytes) of objects tracked bytewise by > dead store elimination. > Common Joined UInteger Var(param_early_inlining_insns) Init(6) Optimization > Param > Maximal estimated growth of function body caused by early inlining of single > call. > > +-param=early-inlining-insns-cold= > +Common Joined UInteger Var(param_early_inlining_insns_cold) Init(0) > Optimization Param > +Maximal estimated growth of function body caused by early inlining of cold > call. > + > -param=file-cache-files= > Common Joined UInteger Var(param_file_cache_files) Init(16) Param > Maximum number of files in the file cache. > @@ -654,6 +658,10 @@ The maximum number of instructions when inlining for > size. > Common Joined UInteger Var(param_max_inline_insns_small) Optimization Param > The maximum number of instructions when automatically inlining small > functions. > > +-param=max-inline-insns-small-and-cold= > +Common Joined UInteger Var(param_max_inline_insns_small_and_cold) > Optimization Init(0) Param > +The maximum number of instructions in a small and cold function eligible for > inlining. > + > -param=max-inline-recursive-depth= > Common Joined UInteger Var(param_max_inline_recursive_depth) Optimization > Init(8) Param > The maximum depth of recursive inlining for inline functions. > diff --git a/gcc/testsuite/gcc.dg/inline-cold-1.c > b/gcc/testsuite/gcc.dg/inline-cold-1.c > new file mode 100644 > index 00000000000..d7752dc5ec6 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/inline-cold-1.c > @@ -0,0 +1,21 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Os -fdump-tree-einline-details" }*/ > + > +volatile int v; > + > +int > +foo (int x) > +{ > + v += x; > + v += 1; > + return v; > +} > + > +int > +main (int argc, char **argv) > +{ > + return foo(argc); > +} > + > +/* { dg-final { scan-tree-dump "will not early inline: > main/\[0-9\]*->foo/\[0-9\]*, call is cold and code would grow by" "einline" } > } */ > +/* { dg-final { scan-tree-dump-not "Inlining foo/\[0-9\]* into > main/\[0-9\]*" "einline" } } */ > diff --git a/gcc/testsuite/gcc.dg/inline-cold-2.c > b/gcc/testsuite/gcc.dg/inline-cold-2.c > new file mode 100644 > index 00000000000..3de8d18b9c2 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/inline-cold-2.c > @@ -0,0 +1,21 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Os -fdump-tree-einline-details --param > early-inlining-insns-cold=32" }*/ > + > +volatile int v; > + > +int > +foo (int x) > +{ > + v += x; > + v += 1; > + return v; > +} > + > +int > +main (int argc, char **argv) > +{ > + return foo(argc); > +} > + > +/* { dg-final { scan-tree-dump "Inlining foo/\[0-9]* into main/\[0-9]*" > "einline" } } */ > +/* { dg-final { scan-tree-dump-not "will not early inline: main/\[0-9]* -> > foo/\[0-9]*, call is cold and code would grow by" "einline" } } */ > diff --git a/gcc/testsuite/gcc.dg/ipa/inline-cold-1.c > b/gcc/testsuite/gcc.dg/ipa/inline-cold-1.c > new file mode 100644 > index 00000000000..27ad518e3bd > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/ipa/inline-cold-1.c > @@ -0,0 +1,21 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Os -fno-early-inlining -fno-partial-inlining -fno-ipa-cp > -fdump-ipa-inline-details" }*/ > + > +volatile int v; > + > +int > +foo (int x) > +{ > + v += x; > + v += 1; > + return v; > +} > + > +int > +main (int argc, char **argv) > +{ > + return foo(argc); > +} > + > +/* { dg-final { scan-ipa-dump "not inlinable: main/\[0-9\]* -> foo/\[0-9\]*, > call is unlikely and code size would grow" "inline" } } */ > +/* { dg-final { scan-ipa-dump-not "Inlined foo/\[0-9\]* into main/\[0-9\]*" > "inline" } } */ > diff --git a/gcc/testsuite/gcc.dg/ipa/inline-cold-2.c > b/gcc/testsuite/gcc.dg/ipa/inline-cold-2.c > new file mode 100644 > index 00000000000..6b1ed8bab1b > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/ipa/inline-cold-2.c > @@ -0,0 +1,21 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Os -fno-early-inlining -fno-partial-inlining -fno-ipa-cp > -fdump-ipa-inline-details --param max-inline-insns-small-and-cold=32" }*/ > + > +volatile int v; > + > +int > +foo (int x) > +{ > + v += x; > + v += 1; > + return v; > +} > + > +int > +main (int argc, char **argv) > +{ > + return foo(argc); > +} > + > +/* { dg-final { scan-ipa-dump "Inlined foo/\[0-9\]* into main/\[0-9\]*" > "inline" } } */ > +/* { dg-final { scan-ipa-dump-not "not inlinable: main/\[0-9\]* -> > foo/\[0-9\]*, call is unlikely and code size would grow" "inline" } } */ > -- > 2.43.0
