https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126348
Bug ID: 126348
Summary: [LTO] Split clone and direct children refer to
abstract DIEs from different CUs
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: debug
Assignee: unassigned at gcc dot gnu.org
Reporter: luolongjuna at gmail dot com
Target Milestone: ---
Created attachment 65110
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65110&action=edit
Reduced two-TU C++ LTO testcase
With full LTO, a concrete function clone created by IPA splitting can refer
to an abstract subprogram DIE from one input translation unit, while its
direct formal parameter and local variable refer to abstract DIEs from
another input translation unit.
This produces an internally inconsistent DWARF origin graph.
Observed with:
GCC 17.0.0 20260720 (experimental)
revision 5453f858146
target x86_64-pc-linux-gnu
The attached reduced testcase consists of two C++ translation units that
instantiate the same inline member function.
Build it with:
g++ -O2 -g -gdwarf-5 -dA --save-temps -flto \
-flto-partition=one -fno-ipa-icf \
dwarf-origin-1_0.C dwarf-origin-1_1.C -o test
The testcase causes IPA splitting to preserve two physical .part.0 clones,
one originating from each input translation unit.
In the generated DWARF, the first clone is internally consistent:
concrete DW_TAG_subprogram abstract_origin -> TU 0
direct DW_TAG_formal_parameter origin -> TU 0
direct DW_TAG_variable origin -> TU 0
The second clone is not:
concrete DW_TAG_subprogram abstract_origin -> TU 0
direct DW_TAG_formal_parameter origin -> TU 1
direct DW_TAG_variable origin -> TU 1
Thus, the concrete subprogram and its direct children do not refer to the
same abstract DIE tree.
The issue is not the presence of cross-CU references by itself. Cross-CU
references are valid. The issue is that the parent and direct child origins
within one concrete subprogram graph resolve to different input CUs.
Expected result:
For each concrete split clone, the subprogram origin and the origins of its
direct parameters and variables should refer to the same input TU's abstract
DIE tree.
The immediate cause appears to be that an IPA split clone has no early DIE of
its own. dwarf2out_die_ref_for_decl therefore fails to stream a TU-specific
external DIE reference for the clone when lookup_decl_die (decl) returns
NULL. During LTO merging, the function origin can then resolve to the
prevailing translation unit, while parameter and local-variable origins
retain their physical input-TU provenance.
Falling back to the function clone's ultimate abstract origin when the clone
has no early DIE preserves the correct input-TU external DIE reference.
A candidate fix and a g++.dg/lto regression test have been prepared. The
test checks that each concrete split clone and its direct children refer to
one consistent abstract DIE tree.
DejaGNU results on the same trunk revision:
unpatched: 4 PASS, 1 FAIL
patched: 5 PASS
The unpatched failure is specifically the TU 1 origin-closure check.
This is distinct from PR debug/44712 and PR debug/92983. Those reports
concern the DWARF representation and debugging semantics of partially
outlined or re-inlined functions within a translation unit. This report is
specific to full LTO and the loss of input-TU provenance: a concrete split
clone resolves to one input CU's abstract subprogram while its direct
children resolve to another input CU's abstract tree.