> This is OK for trunk if you don't hear otherwise from Honza until the
> end of this week.

Thanks, Richard. I haven't seen any further comments on V2, so I plan
to push it to trunk on Wednesday, September 16.

Longjun

Richard Biener <[email protected]> 于2026年9月8日周二 17:16写道:
>
> On Fri, 21 Aug 2026, Longjun Luo wrote:
>
> > Since r167795, cfgexpand has resolved a function's section before RTL
> > expansion.  r168624 added resolve_unique_section to the direct thunk
> > emission path, when thunks were still emitted directly as assembly.  When
> > r202592 added a GIMPLE thunk path, the call was retained in both paths.  The
> > direct assembler path still needs it, but the GIMPLE path later reaches
> > cfgexpand, so its call is redundant.
> >
> > It can also be too early.  IPA ICF can turn equivalent functions whose
> > addresses matter into GIMPLE wrappers during WPA, before LTO privatizes 
> > their
> > assembler names.  The early call records a section based on the old name,
> > and that stale section is streamed into LTRANS.  IPA strub has the same
> > problem in the GIMPLE wrapper code added in r14-6201.
> >
> > Remove the early calls for GIMPLE wrappers and let cfgexpand resolve their
> > sections from the final assembler names.  Keep the call for directly emitted
> > assembler thunks; during LTO output it is reached only after privatization.
> > Explicit and deliberately inherited section names remain unchanged.  This
> > fixes the stale name at its source instead of discarding an already-resolved
> > section only when LTO privatizes a symbol.
> >
> > Bootstrapped and regression-tested on x86_64-pc-linux-gnu (C and C++ only),
> > with no new failures.  Both new tests fail without the change and pass with
> > it.  The complete gcc.dg/lto and g++.dg/lto suites, the strub tests, and
> > g++.dg/other/pr47218* have no unexpected results.
>
> This is OK for trunk if you don't hear otherwise from Honza until the
> end of this week.
>
> Thanks,
> Richard.
>
> >       PR lto/126841
> >
> > gcc/ChangeLog:
> >
> >       * doc/invoke.texi (-ffunction-sections): Document implicit function
> >       section names under LTO.
> >       * ipa-strub.cc (pass_ipa_strub::execute): Let cfgexpand resolve the
> >       GIMPLE wrapper section.
> >       * symtab-thunks.cc (expand_thunk): Likewise for generic GIMPLE thunks.
> >       Clarify the direct-assembler case.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * gcc.dg/lto/pr126841-strub_0.c: New test.
> >       * gcc.dg/lto/pr126841-strub_1.c: New test.
> >       * gcc.dg/lto/pr126841_0.c: New test.
> >       * gcc.dg/lto/pr126841_1.c: New test.
> >       * gcc.dg/lto/pr126841_2.c: New test.
> >       * gcc.dg/lto/pr126841_3.c: New test.
> >
> > Signed-off-by: Longjun Luo <[email protected]>
> > ---
> > Changes in v2:
> > - Fix the premature section resolution at the GIMPLE-wrapper construction
> >   sites instead of changing LTO streaming.
> > - Cover the same issue in IPA strub with an independent regression test.
> > - Narrow the documentation to implicit function sections and retain the
> >   exception for deliberate co-location.
> >
> > I tried the suggested lto_output_node approach.  It needs exceptions for
> > thunks and former thunks that deliberately inherit a section.  Aliases are
> > another issue because they have no body of their own to pass through
> > cfgexpand.  Removing the premature calls is narrower: these GIMPLE wrappers
> > already pass through cfgexpand, while directly emitted assembler thunks
> > retain their output-time call.  This forgoes the possible reduction in
> > streaming size, but avoids changing established section relationships.
> >
> > For functions that are not deliberately co-located, keeping one section per
> > function matches the documented -ffunction-sections behavior.  Here the 
> > final
> > lto_priv names already provide the disambiguation discussed in comment #6;
> > resolving from the pre-privatization name instead silently puts distinct
> > functions in one section.
> >
> > I also compared explicit-section ICF and strub cases before and after the
> > change; their LTRANS assembly is unchanged.  The updated manual also builds
> > successfully with makeinfo.
> >
> >  gcc/doc/invoke.texi                         |  6 ++++++
> >  gcc/ipa-strub.cc                            |  4 ----
> >  gcc/symtab-thunks.cc                        |  7 ++-----
> >  gcc/testsuite/gcc.dg/lto/pr126841-strub_0.c | 21 ++++++++++++++++++++
> >  gcc/testsuite/gcc.dg/lto/pr126841-strub_1.c |  7 +++++++
> >  gcc/testsuite/gcc.dg/lto/pr126841_0.c       | 22 +++++++++++++++++++++
> >  gcc/testsuite/gcc.dg/lto/pr126841_1.c       |  7 +++++++
> >  gcc/testsuite/gcc.dg/lto/pr126841_2.c       |  7 +++++++
> >  gcc/testsuite/gcc.dg/lto/pr126841_3.c       |  5 +++++
> >  9 files changed, 77 insertions(+), 9 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841-strub_0.c
> >  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841-strub_1.c
> >  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_0.c
> >  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_1.c
> >  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_2.c
> >  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_3.c
> >
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 01925ecf30d..ed341e88f48 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -16927,6 +16927,12 @@ file if the target supports arbitrary sections.  
> > The name of the
> >  function or the name of the data item determines the section's name
> >  in the output file.
> >
> > +With link-time optimization, an implicitly generated function section name 
> > is
> > +derived from the final assembler name unless the compiler deliberately 
> > places
> > +related functions, such as a thunk and its target, in the same section.  
> > The
> > +final assembler name may include a compiler-generated suffix that 
> > distinguishes
> > +identically named internal-linkage items from different translation units.
> > +
> >  Use these options on systems where the linker can perform optimizations to
> >  improve locality of reference in the instruction space.  Most systems 
> > using the
> >  ELF object format have linkers with such optimizations.  On AIX, the linker
> > diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
> > index b0156fe46f6..118c4a08082 100644
> > --- a/gcc/ipa-strub.cc
> > +++ b/gcc/ipa-strub.cc
> > @@ -3124,10 +3124,6 @@ pass_ipa_strub::execute (function *)
> >
> >           current_function_decl = thunk_fndecl;
> >
> > -         /* Ensure thunks are emitted in their correct sections.  */
> > -         resolve_unique_section (thunk_fndecl, 0,
> > -                                 flag_function_sections);
> > -
> >           bitmap_obstack_initialize (NULL);
> >
> >           /* Build the return declaration for the function.  */
> > diff --git a/gcc/symtab-thunks.cc b/gcc/symtab-thunks.cc
> > index fb4ff87c988..e0a8d5e9357 100644
> > --- a/gcc/symtab-thunks.cc
> > +++ b/gcc/symtab-thunks.cc
> > @@ -363,7 +363,8 @@ expand_thunk (cgraph_node *node, bool output_asm_thunks,
> >
> >        current_function_decl = thunk_fndecl;
> >
> > -      /* Ensure thunks are emitted in their correct sections.  */
> > +      /* This thunk is emitted directly and bypasses cfgexpand, so resolve
> > +      its section here.  */
> >        resolve_unique_section (thunk_fndecl, 0,
> >                             flag_function_sections);
> >
> > @@ -432,10 +433,6 @@ expand_thunk (cgraph_node *node, bool 
> > output_asm_thunks,
> >
> >        current_function_decl = thunk_fndecl;
> >
> > -      /* Ensure thunks are emitted in their correct sections.  */
> > -      resolve_unique_section (thunk_fndecl, 0,
> > -                           flag_function_sections);
> > -
> >        bitmap_obstack_initialize (NULL);
> >
> >        if (info->virtual_offset_p)
> > diff --git a/gcc/testsuite/gcc.dg/lto/pr126841-strub_0.c 
> > b/gcc/testsuite/gcc.dg/lto/pr126841-strub_0.c
> > new file mode 100644
> > index 00000000000..bd8e628ade5
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lto/pr126841-strub_0.c
> > @@ -0,0 +1,21 @@
> > +/* { dg-lto-do link } */
> > +/* { dg-require-effective-target elf } */
> > +/* { dg-require-effective-target named_sections } */
> > +/* { dg-require-effective-target fpic } */
> > +/* { dg-require-effective-target shared } */
> > +/* { dg-require-effective-target strub } */
> > +/* { dg-require-linker-plugin "" } */
> > +/* { dg-lto-options { { -O2 -flto -fPIC -shared -ffunction-sections 
> > -save-temps -fstrub=all -fno-ipa-icf } } } */
> > +
> > +static int
> > +same_fn (int x)
> > +{
> > +  return x * 33 + 7;
> > +}
> > +
> > +int (*a_callback) (int) = same_fn;
> > +
> > +/* The strub wrappers must use sections derived from their privatized
> > +   assembler names.  */
> > +/* { dg-final { scan-lto-assembler {\.section[ 
> > \t]+\.text\.same_fn\.lto_priv\.0[, \t"]} } } */
> > +/* { dg-final { scan-lto-assembler {\.section[ 
> > \t]+\.text\.same_fn\.lto_priv\.1[, \t"]} } } */
> > diff --git a/gcc/testsuite/gcc.dg/lto/pr126841-strub_1.c 
> > b/gcc/testsuite/gcc.dg/lto/pr126841-strub_1.c
> > new file mode 100644
> > index 00000000000..39356acba71
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lto/pr126841-strub_1.c
> > @@ -0,0 +1,7 @@
> > +static int
> > +same_fn (int x)
> > +{
> > +  return x * 33 + 7;
> > +}
> > +
> > +int (*b_callback) (int) = same_fn;
> > diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_0.c 
> > b/gcc/testsuite/gcc.dg/lto/pr126841_0.c
> > new file mode 100644
> > index 00000000000..a0222d3336f
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lto/pr126841_0.c
> > @@ -0,0 +1,22 @@
> > +/* { dg-lto-do link } */
> > +/* { dg-require-effective-target elf } */
> > +/* { dg-require-effective-target named_sections } */
> > +/* { dg-require-effective-target fpic } */
> > +/* { dg-require-effective-target shared } */
> > +/* { dg-require-linker-plugin "" } */
> > +/* { dg-lto-options { { -O2 -flto -fPIC -shared -ffunction-sections 
> > -save-temps } } } */
> > +
> > +static int
> > +same_fn (int x)
> > +{
> > +  return x * 33 + 7;
> > +}
> > +
> > +int (*a_callback) (int) = same_fn;
> > +
> > +/* The exported function keeps the unsuffixed section, and each privatized
> > +   function must have its own section.  */
> > +/* { dg-final { scan-lto-assembler {\.section[ \t]+\.text\.same_fn[, \t"]} 
> > } } */
> > +/* { dg-final { scan-lto-assembler {\.section[ 
> > \t]+\.text\.same_fn\.lto_priv\.0[, \t"]} } } */
> > +/* { dg-final { scan-lto-assembler {\.section[ 
> > \t]+\.text\.same_fn\.lto_priv\.1[, \t"]} } } */
> > +/* { dg-final { scan-lto-assembler {\.section[ 
> > \t]+\.text\.same_fn\.lto_priv\.2[, \t"]} } } */
> > diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_1.c 
> > b/gcc/testsuite/gcc.dg/lto/pr126841_1.c
> > new file mode 100644
> > index 00000000000..39356acba71
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lto/pr126841_1.c
> > @@ -0,0 +1,7 @@
> > +static int
> > +same_fn (int x)
> > +{
> > +  return x * 33 + 7;
> > +}
> > +
> > +int (*b_callback) (int) = same_fn;
> > diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_2.c 
> > b/gcc/testsuite/gcc.dg/lto/pr126841_2.c
> > new file mode 100644
> > index 00000000000..369eb1836a6
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lto/pr126841_2.c
> > @@ -0,0 +1,7 @@
> > +static int
> > +same_fn (int x)
> > +{
> > +  return x * 33 + 7;
> > +}
> > +
> > +int (*c_callback) (int) = same_fn;
> > diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_3.c 
> > b/gcc/testsuite/gcc.dg/lto/pr126841_3.c
> > new file mode 100644
> > index 00000000000..567eb29cda0
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lto/pr126841_3.c
> > @@ -0,0 +1,5 @@
> > +int
> > +same_fn (int x)
> > +{
> > +  return x - 1;
> > +}
> >
>
> --
> Richard Biener <[email protected]>
> SUSE Software Solutions Germany GmbH,
> Frankenstrasse 146, 90461 Nuernberg, Germany;
> GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to