[PATCH v3] debug: Preserve TU provenance for IPA split clones in LTO [PR debug/126348]
Longjun Luo <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
IPA split clones are created after early debug generation, so they have no early DIE of their own and the exact die_ref_for_decl lookup for such a clone fails during initial LTO streaming. Without a reference of its own, the clone's concrete DIE has to follow its origin declaration. WPA tree merging selects a prevailing origin, and the external DIE reference retained for it can name a different input TU, while the clone's parameters and local variables keep references to their physical input TU. The concrete subprogram DIE and its children then carry abstract origins from different TUs. Stream the early DIE reference of the clone's DECL_ORIGIN when an exact reference is unavailable. This has to happen during initial LTO streaming, before merging; afterwards the origin's reference no longer identifies the clone's physical TU. Do this at the streaming caller so that die_ref_for_decl keeps its exact-DECL lookup semantics, and restrict the fallback to cgraph_node::split_part clones. Add an LTO regression test that verifies that an address-bearing concrete split-function DIE and its direct children refer to the same physical input TU. Set max-inline-insns-auto explicitly to leave enough margin for target-dependent size estimates and ensure that the test exercises function splitting across targets. Bootstrapped and regression-tested on x86_64-pc-linux-gnu (C and C++ only), with no new failures. The new test fails without the patch and passes with it. The test was also cross-tested on arm-linux-gnueabihf. PR debug/126348 gcc/ChangeLog: * lto-streamer-out.cc (lto_write_tree_1): Use the abstract origin's DIE reference as a fallback when initially streaming an IPA split clone. gcc/testsuite/ChangeLog: * g++.dg/lto/pr126348.h: New test. * g++.dg/lto/pr126348_0.C: New test. * g++.dg/lto/pr126348_1.C: New test. * g++.dg/lto/pr126348_2.C: New test. Signed-off-by: Longjun Luo <[email protected]> --- Changes in v3: - Set max-inline-insns-auto explicitly in the regression test. Linaro's precommit CI reported the new test failing on arm-linux-gnueabihf. At -O2, x86_64 and ARM both use max-inline-insns-auto=15, giving the same COMDAT split-size limit of 25. The split tail is estimated at 21 on x86_64 and 26 on ARM, so ARM hits the size guard and does not create the second split part. - No change to the compiler implementation. The targeted x86_64 test has 6 expected passes. I also cross-tested with arm-linux-gnueabihf using the bot's ARM options (armv7-a, Thumb, hard float, and cortex-a9 tuning). With the compiler fix both scans pass; without it the second scan fails as intended. --- gcc/lto-streamer-out.cc | 31 +++++++++++++++++++++++++-- gcc/testsuite/g++.dg/lto/pr126348.h | 28 ++++++++++++++++++++++++ gcc/testsuite/g++.dg/lto/pr126348_0.C | 24 +++++++++++++++++++++ gcc/testsuite/g++.dg/lto/pr126348_1.C | 28 ++++++++++++++++++++++++ gcc/testsuite/g++.dg/lto/pr126348_2.C | 14 ++++++++++++ 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lto/pr126348.h create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_0.C create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_1.C create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_2.C diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index 7afc2673ea2..108945bb93d 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -726,8 +726,35 @@ lto_write_tree_1 (struct output_block *ob, tree expr, bool ref_p) { const char *sym; unsigned HOST_WIDE_INT off; - if (debug_info_level > DINFO_LEVEL_NONE - && debug_hooks->die_ref_for_decl (expr, &sym, &off)) + bool have_ref = false; + + if (debug_info_level > DINFO_LEVEL_NONE) + { + have_ref = debug_hooks->die_ref_for_decl (expr, &sym, &off); + + /* IPA split clones are created after early debug and have no + early DIE of their own. During initial LTO streaming, preserve + the physical input TU by using the clone's abstract origin. + This must happen before WPA tree merging can make the origin + refer to a prevailing declaration from another input TU. Keep + die_ref_for_decl's exact-DECL lookup contract intact and + restrict the fallback to the split clone that needs it. */ + if (!have_ref + && !in_lto_p + && TREE_CODE (expr) == FUNCTION_DECL) + { + cgraph_node *node = cgraph_node::get (expr); + if (node && node->split_part) + { + tree origin = DECL_ORIGIN (expr); + if (origin != expr) + have_ref + = debug_hooks->die_ref_for_decl (origin, &sym, &off); + } + } + } + + if (have_ref) { streamer_write_string (ob, ob->main_stream, sym, true); streamer_write_uhwi (ob, off); diff --git a/gcc/testsuite/g++.dg/lto/pr126348.h b/gcc/testsuite/g++.dg/lto/pr126348.h new file mode 100644 index 00000000000..eac6698064a --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr126348.h @@ -0,0 +1,28 @@ +struct Location +{ + const char *file; + const char *function; + int line; +}; + +extern void fail (int, const char *, const Location &) + __attribute__ ((noreturn, cold, noipa)); +extern void note (const char *, int) __attribute__ ((cold, noipa)); + +static const char source_file[] = __BASE_FILE__; + +struct Buffer +{ + int length; + + int printable_length () const + { + if (__builtin_expect (length < 1024, 1)) + return length; + const Location location = { source_file, __func__, __LINE__ }; + note (location.file, location.line); + note (location.function, length); + note (location.file, length + 1); + fail (3, "length < 1024", location); + } +}; diff --git a/gcc/testsuite/g++.dg/lto/pr126348_0.C b/gcc/testsuite/g++.dg/lto/pr126348_0.C new file mode 100644 index 00000000000..27e77b8082c --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr126348_0.C @@ -0,0 +1,24 @@ +/* PR debug/126348 */ +/* Verify that an out-of-line split function and its direct children retain + the same input TU provenance, and that the function has an address-bearing + late DIE. */ +/* { dg-lto-do link } */ +/* { dg-skip-if "No DWARF debug support" { hppa*-*-hpux* } } */ +/* { dg-skip-if "AIX DWARF5" { powerpc-ibm-aix* } } */ +/* { dg-lto-options { { -O2 -g -gdwarf-5 -dA -save-temps -flto -flto-partition=one -fno-ipa-icf --param=max-inline-insns-auto=100 } } } */ +/* { dg-final { scan-lto-assembler "DW_TAG_subprogram\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_AT_(?:low_pc|ranges)(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin" } } */ +/* { dg-final { scan-lto-assembler "DW_TAG_subprogram\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_AT_(?:low_pc|ranges)(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)(?:\[^\n\]*\n){1,6}\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin" } } */ + +#include "pr126348.h" + +__attribute__ ((noinline)) int +one (const Buffer &buffer) +{ + return buffer.printable_length (); +} + +__attribute__ ((noinline)) int +one_extra (const Buffer &buffer) +{ + return buffer.printable_length (); +} diff --git a/gcc/testsuite/g++.dg/lto/pr126348_1.C b/gcc/testsuite/g++.dg/lto/pr126348_1.C new file mode 100644 index 00000000000..bad1a25aa63 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr126348_1.C @@ -0,0 +1,28 @@ +#include "pr126348.h" + +__attribute__ ((noinline)) int one (const Buffer &); +__attribute__ ((noinline)) int one_extra (const Buffer &); + +void +fail (int, const char *, const Location &) +{ + __builtin_trap (); +} + +void +note (const char *, int) +{ + asm volatile ("" ::: "memory"); +} + +__attribute__ ((noinline)) int +two (const Buffer &buffer) +{ + return buffer.printable_length (); +} + +__attribute__ ((noinline)) int +two_extra (const Buffer &buffer) +{ + return buffer.printable_length (); +} diff --git a/gcc/testsuite/g++.dg/lto/pr126348_2.C b/gcc/testsuite/g++.dg/lto/pr126348_2.C new file mode 100644 index 00000000000..7a4015f3b49 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr126348_2.C @@ -0,0 +1,14 @@ +#include "pr126348.h" + +__attribute__ ((noinline)) int one (const Buffer &); +__attribute__ ((noinline)) int one_extra (const Buffer &); +__attribute__ ((noinline)) int two (const Buffer &); +__attribute__ ((noinline)) int two_extra (const Buffer &); + +int +main (int argc, char **) +{ + Buffer buffer = { argc }; + return one (buffer) + one_extra (buffer) + + two (buffer) + two_extra (buffer); +} -- 2.55.0