debug info: partial noentry functions: infra This is the first patch of a set that addresses two different but somewhat related issues.
On the one hand, after partial inlining, the non-inlined function fragment is output in a way that debug info consumers can't distinguish from the entire function: debug info lists the entire function as abstract origin for the fragment, but nothing that indicates the fragment does not stand for the entire function. So, if a debugger is asked to set a breakpoint at the entry point of the function, it might very well set one at the entry point of the fragment, which is likely not where users expect to stop. On the other hand, OpenMP blocks are split out into artificial functions that do not indicate their executable code is part of another function. The artificial functions are nested within the original function, but that's hardly enough: ideally, debug info consumers should be able to tell that, if they stop within one of these functions, they're abstractly within the original function. This patch introduces a new DWARF attribute to indicate that a function is a partial copy of its abstract origin, specifically, that its entry point does not correspond to the entry point of the abstract origin. This attribute can then be used to mark the out-of-line portion of partial inlines, and OpenMP blocks split out into artificial functions. This patchset was regstrapped on x86_64-linux-gnu and i686-linux-gnu. Ok to install the first patch? (infrastructure) Ok to install the second patch? (function versioning) Ok to install the third patch? (OpenMP fragments) for include/ChangeLog * dwarf2.def (DW_AT_GNU_partial_noentry): New. for gcc/ChangeLog * tree-core.h (tree_function_decl): Drop unused tm_clone_flag. Add partial_copy_flag. * tree.h (DECL_FUNCTION_PARTIAL_COPY): New. * dwarf2out.c (checksum_attributes): Add at_partial_noentry. (collect_checksum_attributes): Set it. (die_checksum_ordered): Checksum it. (gen_subprogam_die): Keep the old die if it the partial copy flag matches the partial noentry attribute. Set the attribute as needed. --- gcc/dwarf2out.c | 11 ++++++++++- gcc/tree-core.h | 2 +- gcc/tree.h | 10 ++++++++++ include/dwarf2.def | 3 +++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 76a538f1ff97..db0bc12a1f46 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -6944,6 +6944,7 @@ struct checksum_attributes dw_attr_node *at_virtuality; dw_attr_node *at_visibility; dw_attr_node *at_vtable_elem_location; + dw_attr_node *at_partial_noentry; }; /* Collect the attributes that we will want to use for the checksum. */ @@ -7108,6 +7109,9 @@ collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die) case DW_AT_vtable_elem_location: attrs->at_vtable_elem_location = a; break; + case DW_AT_GNU_partial_noentry: + attrs->at_partial_noentry = a; + break; default: break; } @@ -7183,6 +7187,7 @@ die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark) CHECKSUM_ATTR (attrs.at_type); CHECKSUM_ATTR (attrs.at_friend); CHECKSUM_ATTR (attrs.at_alignment); + CHECKSUM_ATTR (attrs.at_partial_noentry); /* Checksum the child DIEs. */ c = die->die_child; @@ -21933,7 +21938,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (old_die && old_die->die_parent == NULL) add_child_die (context_die, old_die); - if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin)) + if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin) + && (DECL_FUNCTION_PARTIAL_COPY (decl) + == get_AT_flag (old_die, DW_AT_GNU_partial_noentry))) { /* If we have a DW_AT_abstract_origin we have a working cached version. */ @@ -21943,6 +21950,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) { subr_die = new_die (DW_TAG_subprogram, context_die, decl); add_abstract_origin_attribute (subr_die, origin); + if (DECL_FUNCTION_PARTIAL_COPY (decl)) + add_AT_flag (subr_die, DW_AT_GNU_partial_noentry, true); /* This is where the actual code for a cloned function is. Let's emit linkage name attribute for it. This helps debuggers to e.g, set breakpoints into diff --git a/gcc/tree-core.h b/gcc/tree-core.h index f74f1453de6d..507016db23e9 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1784,7 +1784,7 @@ struct GTY(()) tree_function_decl { unsigned pure_flag : 1; unsigned looping_const_or_pure_flag : 1; unsigned has_debug_args_flag : 1; - unsigned tm_clone_flag : 1; + unsigned partial_copy_flag : 1; unsigned versioned_function : 1; /* No bits left. */ }; diff --git a/gcc/tree.h b/gcc/tree.h index 39acffe52662..12c0b3835d9f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3002,6 +3002,16 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree); #define DECL_FUNCTION_VERSIONED(NODE)\ (FUNCTION_DECL_CHECK (NODE)->function_decl.versioned_function) +/* In FUNCTION_DECL, this is set if this function is only a partial + clone/version/copy of its DECL_ABSTRACT_ORIGIN. It should be used + for the non-inlined portion of a partial inline, for openmp blocks + turned into separate functions, and for any other cases in which we + clone only select parts of a function, presumably omitting its + entry point, that is presumed to remain in a separate, controlling + version of the function. */ +#define DECL_FUNCTION_PARTIAL_COPY(NODE) \ + (FUNCTION_DECL_CHECK (NODE)->function_decl.partial_copy_flag) + /* In FUNCTION_DECL, this is set if this function is a C++ constructor. Devirtualization machinery uses this knowledge for determing type of the object constructed. Also we assume that constructor address is not diff --git a/include/dwarf2.def b/include/dwarf2.def index 2a3b23fef873..f2dd9196b039 100644 --- a/include/dwarf2.def +++ b/include/dwarf2.def @@ -433,6 +433,9 @@ DW_AT (DW_AT_GNU_all_source_call_sites, 0x2118) DW_AT (DW_AT_GNU_macros, 0x2119) /* Attribute for C++ deleted special member functions (= delete;). */ DW_AT (DW_AT_GNU_deleted, 0x211a) +/* This flag indicates a partial copy of a function, whose entry point + does not correspond to that of the abstract origin. */ +DW_AT (DW_AT_GNU_partial_noentry, 0x211b) /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ DW_AT (DW_AT_GNU_dwo_name, 0x2130) DW_AT (DW_AT_GNU_dwo_id, 0x2131) debug info: partial noentry functions: partial inlines When we version a function without copying all of its blocks, particularly when we omit or modify the entry point, mark the function as a partial copy. This should enable debug info consumers to avoid setting a breakpoint in the partial copy when the user requests a breakpoint at the function's entry point. An alternate entry point is specified when versioning a function only as we inline part of it; the non-inlined portion is what goes in the new version. Such partial copies used to refer back to the entire function as their abstract origin. Without the partial copy marker, debug info consumers would set a breakpoint for the function at the inlined entry point, and also at the partial copy's entry point, although the latter is not the actual entry point for the function. for gcc/ChangeLog * tree-inline.c (tree_function_versioning): Mark a version as a partial copy when an alternate entry point is given, and when versioning a partial copy. --- gcc/tree-inline.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index d4aa5bed7398..df0f8cabccc1 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -5829,6 +5829,9 @@ tree_function_versioning (tree old_decl, tree new_decl, old_version_node->used_as_abstract_origin = true; DECL_FUNCTION_PERSONALITY (new_decl) = DECL_FUNCTION_PERSONALITY (old_decl); + DECL_FUNCTION_PARTIAL_COPY (new_decl) = new_entry + || DECL_FUNCTION_PARTIAL_COPY (old_decl); + /* Prepare the data structures for the tree copy. */ memset (&id, 0, sizeof (id)); debug info: partial noentry functions: omp split-out blocks We emit some OMP blocks as separate functions that are nested in, but not otherwise related with the function they were originally part of. This patch makes such newly-created artificial functions refer back to the original function as their abstract origin, but as partial copies, so that they're not mistaken as the whole function. This enables line numbers in the split-out block to still be recognized as part of the original function. It may, however, cause debug information consumers that do not support the partial copy attribute to mistake the nested functions as the whole function. for gcc/ChangeLog * omp-low.c (create_omp_child_function): Mark newly-created function as a partial copy of the original one. Mark the original function's cgraph node as used as abstract origin. --- gcc/omp-low.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 33e633cd627b..40166f9bfb3a 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1633,6 +1633,10 @@ create_omp_child_function (omp_context *ctx, bool task_copy) = DECL_FUNCTION_SPECIFIC_TARGET (current_function_decl); DECL_FUNCTION_VERSIONED (decl) = DECL_FUNCTION_VERSIONED (current_function_decl); + DECL_FUNCTION_PARTIAL_COPY (decl) = 1; + DECL_ABSTRACT_ORIGIN (decl) = DECL_ORIGIN (current_function_decl); + if (DECL_ORIGIN (current_function_decl) == current_function_decl) + cgraph_node::get_create (current_function_decl)->used_as_abstract_origin = true; if (omp_maybe_offloaded_ctx (ctx)) { -- Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/ You must be the change you wish to see in the world. -- Gandhi Be Free! -- http://FSFLA.org/ FSF Latin America board member Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer