Ping.

https://inbox.sourceware.org/gcc-patches/[email protected]/

v2 removes the premature resolve_unique_section calls in
symtab-thunks.cc and ipa-strub.cc instead of clearing section names
after privatization. This lets cfgexpand resolve the GIMPLE wrappers'
implicit sections from the final assembler names.

I also tried your suggestion of omitting implicit section names in
lto_output_node. That needs exceptions for thunks and former thunks
that deliberately inherit a section. Aliases also need care, since
they have no body to pass through cfgexpand. Removing the early calls
is narrower, though it forgoes the potential streaming-size saving
you mentioned.

For functions that are not deliberately co-located, keeping one section
per function matches the documented -ffunction-sections behavior.
In this PR, the final lto_priv names already provide the disambiguation
discussed in Bugzilla comment #6. Does this direction look right to you?

Thanks,
Longjun

Longjun Luo <[email protected]> 于2026年8月21日周五 00:24写道:

> 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.
>
>         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;
> +}
> --
> 2.55.0
>

Reply via email to