This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Updated LTO early debug patch
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Jan Hubicka <hubicka at ucw dot cz>
- Date: Mon, 31 Aug 2015 16:44:13 +0200 (CEST)
- Subject: [PATCH] Updated LTO early debug patch
- Authentication-results: sourceware.org; auth=none
So the state below now will pass LTO bootstrap (fingers crossing,
stage3 running) as well as regular bootstrap. Iff I didn't break
sth in the last minute. You need up-to-date trunk (watch out,
fortran seems to be broken) to pull the fixes for trunk LTO bootstrap.
Richard.
Index: trunk/gcc/dwarf2asm.c
===================================================================
*** trunk.orig/gcc/dwarf2asm.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/dwarf2asm.c 2015-08-31 16:03:09.786994930 +0200
*************** along with GCC; see the file COPYING3.
*** 33,38 ****
--- 33,40 ----
#include "dwarf2asm.h"
#include "dwarf2.h"
#include "tm_p.h"
+ #include "function.h"
+ #include "emit-rtl.h"
/* Output an unaligned integer with the given value and size. Prefer not
*************** dw2_asm_output_offset (int size, const c
*** 190,201 ****
va_start (ap, comment);
#ifdef ASM_OUTPUT_DWARF_OFFSET
! ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
#else
dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
#endif
if (flag_debug_asm && comment)
{
fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
vfprintf (asm_out_file, comment, ap);
--- 192,230 ----
va_start (ap, comment);
#ifdef ASM_OUTPUT_DWARF_OFFSET
! ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, 0, base);
#else
dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
#endif
if (flag_debug_asm && comment)
+ {
+ fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+ vfprintf (asm_out_file, comment, ap);
+ }
+ fputc ('\n', asm_out_file);
+
+ va_end (ap);
+ }
+
+ void
+ dw2_asm_output_offset (int size, const char *label, HOST_WIDE_INT offset,
+ section *base ATTRIBUTE_UNUSED,
+ const char *comment, ...)
+ {
+ va_list ap;
+
+ va_start (ap, comment);
+
+ #ifdef ASM_OUTPUT_DWARF_OFFSET
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, offset, base);
+ #else
+ dw2_assemble_integer (size, gen_rtx_PLUS (Pmode,
+ gen_rtx_SYMBOL_REF (Pmode, label),
+ gen_int_mode (offset, Pmode)));
+ #endif
+
+ if (flag_debug_asm && comment)
{
fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
vfprintf (asm_out_file, comment, ap);
Index: trunk/gcc/dwarf2asm.h
===================================================================
*** trunk.orig/gcc/dwarf2asm.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/dwarf2asm.h 2015-08-31 16:03:09.786994930 +0200
*************** extern void dw2_asm_output_offset (int,
*** 40,45 ****
--- 40,49 ----
const char *, ...)
ATTRIBUTE_NULL_PRINTF_4;
+ extern void dw2_asm_output_offset (int, const char *, HOST_WIDE_INT,
+ section *, const char *, ...)
+ ATTRIBUTE_NULL_PRINTF_5;
+
extern void dw2_asm_output_addr (int, const char *, const char *, ...)
ATTRIBUTE_NULL_PRINTF_3;
Index: trunk/gcc/dwarf2out.c
===================================================================
*** trunk.orig/gcc/dwarf2out.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/dwarf2out.c 2015-08-31 16:03:09.797995028 +0200
*************** along with GCC; see the file COPYING3.
*** 102,107 ****
--- 102,108 ----
#include "tree-dfa.h"
#include "gdb/gdb-index.h"
#include "rtl-iter.h"
+ #include "lto-section-names.h"
static void dwarf2out_source_line (unsigned int, const char *, int, bool);
static rtx_insn *last_var_location_insn;
*************** build_cfa_aligned_loc (dw_cfa_location *
*** 2419,2425 ****
static void dwarf2out_init (const char *);
static void dwarf2out_finish (const char *);
! static void dwarf2out_early_finish (void);
static void dwarf2out_assembly_start (void);
static void dwarf2out_define (unsigned int, const char *);
static void dwarf2out_undef (unsigned int, const char *);
--- 2420,2426 ----
static void dwarf2out_init (const char *);
static void dwarf2out_finish (const char *);
! static void dwarf2out_early_finish (const char *);
static void dwarf2out_assembly_start (void);
static void dwarf2out_define (unsigned int, const char *);
static void dwarf2out_undef (unsigned int, const char *);
*************** static void dwarf2out_begin_function (tr
*** 2441,2446 ****
--- 2442,2451 ----
static void dwarf2out_end_function (unsigned int);
static void dwarf2out_register_main_translation_unit (tree unit);
static void dwarf2out_set_name (tree, tree);
+ static void dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off);
+ static bool dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off);
/* The debug hooks structure. */
*************** const struct gcc_debug_hooks dwarf2_debu
*** 2475,2480 ****
--- 2480,2487 ----
dwarf2out_late_global_decl,
dwarf2out_type_decl, /* type_decl */
dwarf2out_imported_module_or_decl,
+ dwarf2out_die_ref_for_decl,
+ dwarf2out_register_external_die,
debug_nothing_tree, /* deferred_inline_function */
/* The DWARF 2 backend tries to reduce debugging bloat by not
emitting the abstract description of inline functions until
*************** const struct gcc_debug_hooks dwarf2_line
*** 2493,2499 ****
{
dwarf2out_init,
debug_nothing_charstar,
! debug_nothing_void,
debug_nothing_void,
debug_nothing_int_charstar,
debug_nothing_int_charstar,
--- 2500,2506 ----
{
dwarf2out_init,
debug_nothing_charstar,
! debug_nothing_charstar,
debug_nothing_void,
debug_nothing_int_charstar,
debug_nothing_int_charstar,
*************** const struct gcc_debug_hooks dwarf2_line
*** 2515,2520 ****
--- 2522,2529 ----
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
*************** typedef struct GTY((chain_circular ("%h.
*** 2650,2655 ****
--- 2659,2671 ----
/* Die is used and must not be pruned as unused. */
BOOL_BITFIELD die_perennial_p : 1;
BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+ /* For an external ref to die_symbol if die_offset contains an extra
+ offset to that symbol. */
+ BOOL_BITFIELD with_offset : 1;
+ /* Whether this DIE was removed from the DIE tree, for example via
+ prune_unused_types. We don't consider those present from the
+ DIE lookup routines. */
+ BOOL_BITFIELD removed : 1;
/* Lots of spare bits. */
}
die_node;
*************** remove_child_with_prev (dw_die_ref child
*** 4815,4820 ****
--- 4831,4837 ----
prev->die_sib = child->die_sib;
if (child->die_parent->die_child == child)
child->die_parent->die_child = prev;
+ child->die_sib = NULL;
}
/* Replace OLD_CHILD with NEW_CHILD. PREV must have the property that
*************** replace_child (dw_die_ref old_child, dw_
*** 4841,4846 ****
--- 4858,4864 ----
}
if (old_child->die_parent->die_child == old_child)
old_child->die_parent->die_child = new_child;
+ old_child->die_sib = NULL;
}
/* Move all children from OLD_PARENT to NEW_PARENT. */
*************** remove_child_TAG (dw_die_ref die, enum d
*** 4871,4879 ****
remove_child_with_prev (c, prev);
c->die_parent = NULL;
/* Might have removed every child. */
! if (c == c->die_sib)
return;
! c = c->die_sib;
}
} while (c != die->die_child);
}
--- 4889,4897 ----
remove_child_with_prev (c, prev);
c->die_parent = NULL;
/* Might have removed every child. */
! if (die->die_child == NULL)
return;
! c = prev->die_sib;
}
} while (c != die->die_child);
}
*************** new_die (enum dwarf_tag tag_value, dw_di
*** 5000,5006 ****
static inline dw_die_ref
lookup_type_die (tree type)
{
! return TYPE_SYMTAB_DIE (type);
}
/* Given a TYPE_DIE representing the type TYPE, if TYPE is an
--- 5018,5030 ----
static inline dw_die_ref
lookup_type_die (tree type)
{
! dw_die_ref die = TYPE_SYMTAB_DIE (type);
! if (die && die->removed)
! {
! TYPE_SYMTAB_DIE (type) = NULL;
! return NULL;
! }
! return die;
}
/* Given a TYPE_DIE representing the type TYPE, if TYPE is an
*************** decl_die_hasher::equal (die_node *x, tre
*** 5065,5071 ****
static inline dw_die_ref
lookup_decl_die (tree decl)
{
! return decl_die_table->find_with_hash (decl, DECL_UID (decl));
}
/* Returns a hash value for X (which really is a var_loc_list). */
--- 5089,5265 ----
static inline dw_die_ref
lookup_decl_die (tree decl)
{
! dw_die_ref *die = decl_die_table->find_slot_with_hash (decl, DECL_UID (decl),
! NO_INSERT);
! if (!die)
! return NULL;
! if ((*die)->removed)
! {
! decl_die_table->clear_slot (die);
! return NULL;
! }
! return *die;
! }
!
!
! /* For DECL which might have early dwarf output query a SYMBOL + OFFSET
! style reference. Return true if we found one refering to a DIE for
! DECL, otherwise return false. */
!
! static bool
! dwarf2out_die_ref_for_decl (tree decl, const char **sym,
! unsigned HOST_WIDE_INT *off)
! {
! dw_die_ref die;
!
! if (flag_wpa && !decl_die_table)
! return false;
!
! if (TREE_CODE (decl) == BLOCK)
! die = BLOCK_DIE (decl);
! else
! die = lookup_decl_die (decl);
! if (!die)
! return false;
!
! /* During WPA stage we currently use DIEs to store the
! decl <-> label + offset map. That's quite inefficient but it
! works for now. */
! if (flag_wpa)
! {
! dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
! if (!ref)
! {
! gcc_assert (die == comp_unit_die ());
! return false;
! }
! *off = ref->die_offset;
! *sym = ref->die_id.die_symbol;
! return true;
! }
!
! /* Similar to get_ref_die_offset_label, but using the "correct"
! label. */
! *off = die->die_offset;
! while (die->die_parent)
! die = die->die_parent;
! /* For the containing CU DIE we compute a die_symbol in
! compute_section_prefix. */
! gcc_assert (die->die_tag == DW_TAG_compile_unit
! && die->die_id.die_symbol != NULL);
! *sym = die->die_id.die_symbol;
! return true;
! }
!
! /* Add a reference of kind ATTR_KIND to a DIE at SYMBOL + OFFSET to DIE. */
!
! static void
! add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
! const char *symbol, HOST_WIDE_INT offset)
! {
! /* Create a fake DIE that contains the reference. Don't use
! new_die because we don't want to end up in the limbo list. */
! dw_die_ref ref = ggc_cleared_alloc<die_node> ();
! ref->die_tag = die->die_tag;
! ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
! ref->die_offset = offset;
! ref->with_offset = 1;
! add_AT_die_ref (die, attr_kind, ref);
! }
!
! /* Create a DIE for DECL if required and add a reference to a DIE
! at SYMBOL + OFFSET which contains attributes dumped early. */
!
! static void
! dwarf2out_register_external_die (tree decl, const char *sym,
! unsigned HOST_WIDE_INT off)
! {
! if (debug_info_level == DINFO_LEVEL_NONE)
! return;
!
! if (flag_wpa && !decl_die_table)
! decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
!
! dw_die_ref die
! = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
! gcc_assert (!die);
! if (!die)
! {
! tree ctx;
! dw_die_ref parent = NULL;
! /* Need to lookup a DIE for the decls context - the containing
! function or translation unit. */
! if (TREE_CODE (decl) == BLOCK)
! ctx = BLOCK_SUPERCONTEXT (decl);
! else
! ctx = DECL_CONTEXT (decl);
! while (ctx && TYPE_P (ctx))
! ctx = TYPE_CONTEXT (ctx);
! if (ctx)
! {
! if (TREE_CODE (ctx) == BLOCK)
! parent = BLOCK_DIE (ctx);
! else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
! /* Keep the 1:1 association during WPA. */
! && !flag_wpa)
! /* Otherwise all late annotations go to the main CU which
! imports the original CUs. */
! parent = comp_unit_die ();
! else
! parent = lookup_decl_die (ctx);
! }
! /* Create a DIE "stub". */
! switch (TREE_CODE (decl))
! {
! case TRANSLATION_UNIT_DECL:
! if (flag_wpa)
! {
! /* Keep the 1:1 association during WPA. */
! die = new_die (DW_TAG_compile_unit, NULL, decl);
! break;
! }
! {
! die = comp_unit_die ();
! dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
! add_AT_external_die_ref (import, DW_AT_import, sym, off);
! /* We re-target all CU decls to the LTRANS CU DIE, so no need
! to create a DIE for the original CUs. */
! return;
! }
! case NAMESPACE_DECL:
! /* ??? LANG issue - DW_TAG_module for fortran. Either look
! at the input language (if we have enough DECL_CONTEXT to follow)
! or use a bit in tree_decl_with_vis to record the distinction. */
! die = new_die (DW_TAG_namespace, parent, decl);
! break;
! case FUNCTION_DECL:
! die = new_die (DW_TAG_subprogram, parent, decl);
! break;
! case VAR_DECL:
! case RESULT_DECL:
! die = new_die (DW_TAG_variable, parent, decl);
! break;
! case PARM_DECL:
! die = new_die (DW_TAG_formal_parameter, parent, decl);
! break;
! case LABEL_DECL:
! die = new_die (DW_TAG_label, parent, decl);
! break;
! case BLOCK:
! die = new_die (DW_TAG_lexical_block, parent, decl);
! break;
! default:
! gcc_unreachable ();
! }
! // die->dumped_early = true;
! if (TREE_CODE (decl) == BLOCK)
! BLOCK_DIE (decl) = die;
! else
! equate_decl_number_to_die (decl, die);
! }
!
! /* Add a reference to the DIE providing early debug at $sym + off. */
! add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
}
/* Returns a hash value for X (which really is a var_loc_list). */
*************** print_dw_val (dw_val_node *val, bool rec
*** 5544,5550 ****
die->die_id.die_type_node->signature);
}
else if (die->die_id.die_symbol)
! fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
else
fprintf (outfile, "die -> %ld", die->die_offset);
fprintf (outfile, " (%p)", (void *) die);
--- 5738,5748 ----
die->die_id.die_type_node->signature);
}
else if (die->die_id.die_symbol)
! {
! fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
! if (die->with_offset)
! fprintf (outfile, " + %ld", die->die_offset);
! }
else
fprintf (outfile, "die -> %ld", die->die_offset);
fprintf (outfile, " (%p)", (void *) die);
*************** debug_dwarf (void)
*** 5717,5722 ****
--- 5915,5943 ----
print_die (comp_unit_die (), stderr);
}
+ DEBUG_FUNCTION void
+ verify_die (dw_die_ref die)
+ {
+ if (die->die_parent == NULL
+ && die->die_sib == NULL)
+ return;
+ dw_die_ref x = die;
+ do
+ {
+ x->die_mark = 1;
+ x = x->die_sib;
+ }
+ while (x && !x->die_mark);
+ gcc_assert (x == die);
+ x = die;
+ do
+ {
+ x->die_mark = 0;
+ x = x->die_sib;
+ }
+ while (x && x->die_mark);
+ }
+
#ifdef ENABLE_CHECKING
/* Sanity checks on DIEs. */
*************** static unsigned int comdat_symbol_number
*** 6774,6780 ****
children, and set comdat_symbol_id accordingly. */
static void
! compute_section_prefix (dw_die_ref unit_die)
{
const char *die_name = get_AT_string (unit_die, DW_AT_name);
const char *base = die_name ? lbasename (die_name) : "anonymous";
--- 6995,7001 ----
children, and set comdat_symbol_id accordingly. */
static void
! compute_section_prefix_1 (dw_die_ref unit_die, bool comdat_p)
{
const char *die_name = get_AT_string (unit_die, DW_AT_name);
const char *base = die_name ? lbasename (die_name) : "anonymous";
*************** compute_section_prefix (dw_die_ref unit_
*** 6793,6799 ****
unmark_all_dies (unit_die);
md5_finish_ctx (&ctx, checksum);
! sprintf (name, "%s.", base);
clean_symbol_name (name);
p = name + strlen (name);
--- 7014,7024 ----
unmark_all_dies (unit_die);
md5_finish_ctx (&ctx, checksum);
! /* ??? Now that we compute this for comp_unit_die () we have a
! DW_AT_name that might not start with a letter but with anything
! valid for filenames - clean_symbol_name doesn't fix that up.
! Thus unconditionally append 'g' for now (can we use isalpha?). */
! sprintf (name, "g%s.", base);
clean_symbol_name (name);
p = name + strlen (name);
*************** compute_section_prefix (dw_die_ref unit_
*** 6803,6809 ****
p += 2;
}
! comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
comdat_symbol_number = 0;
}
--- 7028,7042 ----
p += 2;
}
! unit_die->die_id.die_symbol = xstrdup (name);
! unit_die->comdat_type_p = comdat_p;
! }
!
! static void
! compute_section_prefix (dw_die_ref unit_die)
! {
! compute_section_prefix_1 (unit_die, true);
! comdat_symbol_id = unit_die->die_id.die_symbol;
comdat_symbol_number = 0;
}
*************** output_die (dw_die_ref die)
*** 8921,8927 ****
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
! if (! die->comdat_type_p && die->die_id.die_symbol)
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
--- 9154,9164 ----
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
! if (! die->comdat_type_p && die->die_id.die_symbol
! /* Don't output the symbol twice. For LTO we want the label
! on the section beginning, not on the actual DIE. */
! && (!flag_generate_lto
! || die->die_tag != DW_TAG_compile_unit))
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
*************** output_die (dw_die_ref die)
*** 9100,9107 ****
size = DWARF2_ADDR_SIZE;
else
size = DWARF_OFFSET_SIZE;
! dw2_asm_output_offset (size, sym, debug_info_section, "%s",
! name);
}
}
else
--- 9337,9358 ----
size = DWARF2_ADDR_SIZE;
else
size = DWARF_OFFSET_SIZE;
! /* ??? We cannot unconditionally output die_offset if
! non-zero - at least -feliminate-dwarf2-dups will
! create references to those DIEs via symbols. And we
! do not clear its DIE offset after outputting it
! (and the label refers to the actual DIEs, not the
! DWARF CU unit header which is when using label + offset
! would be the correct thing to do).
! ??? It could use the section name and go w/o a
! new symbol even?
! ??? This is the reason for the with_offset flag. */
! if (AT_ref (a)->with_offset)
! dw2_asm_output_offset (size, sym, AT_ref (a)->die_offset,
! debug_info_section, "%s", name);
! else
! dw2_asm_output_offset (size, sym, debug_info_section, "%s",
! name);
}
}
else
*************** output_comp_unit (dw_die_ref die, int ou
*** 9252,9258 ****
calc_die_sizes (die);
oldsym = die->die_id.die_symbol;
! if (oldsym)
{
tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
--- 9503,9509 ----
calc_die_sizes (die);
oldsym = die->die_id.die_symbol;
! if (oldsym && die->comdat_type_p)
{
tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
*************** output_comp_unit (dw_die_ref die, int ou
*** 9268,9273 ****
--- 9519,9549 ----
info_section_emitted = true;
}
+ /* For LTO cross unit DIE refs we want a symbol on the start of the
+ debuginfo section, not on the CU DIE.
+ ??? We could simply use the symbol output by output_die and account
+ for the extra offset produced by the CU heade (which has fixed size?). */
+ if (flag_generate_lto && oldsym)
+ {
+ /* ??? No way to get visibility assembled without a decl. */
+ tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (oldsym), char_type_node);
+ TREE_PUBLIC (decl) = true;
+ TREE_STATIC (decl) = true;
+ DECL_ARTIFICIAL (decl) = true;
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = true;
+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+ #ifdef ASM_WEAKEN_LABEL
+ /* We prefer a .weak because that handles duplicates from duplicate
+ archive members in a graceful way. */
+ ASM_WEAKEN_LABEL (asm_out_file, oldsym);
+ #else
+ targetm.asm_out.globalize_label (asm_out_file, oldsym);
+ #endif
+ ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+ }
+
/* Output debugging information. */
output_compilation_unit_header ();
output_die (die);
*************** add_location_or_const_value_attribute (d
*** 16160,16166 ****
if (TREE_CODE (decl) == ERROR_MARK)
return false;
! if (get_AT (die, attr))
return true;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
--- 16436,16448 ----
if (TREE_CODE (decl) == ERROR_MARK)
return false;
! if (get_AT (die, attr)
! /* If we genrated DW_AT_const_value early we're done.
! ??? We prefer a location to an DW_AT_const_value so remove
! a DW_AT_const_value added early in favor of a location.
! ??? Some locations end up as DW_AT_const_value anyway...
! (those generated via rtl_for_decl_location). */
! || get_AT (die, DW_AT_const_value))
return true;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
*************** tree_add_const_value_attribute (dw_die_r
*** 16393,16404 ****
init = t;
gcc_assert (!DECL_P (init));
! rtl = rtl_for_decl_init (init, type);
! if (rtl)
! return add_const_value_attribute (die, rtl);
/* If the host and target are sane, try harder. */
! else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
! && initializer_constant_valid_p (init, type))
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
if (size > 0 && (int) size == size)
--- 16675,16692 ----
init = t;
gcc_assert (!DECL_P (init));
! if (!early_dwarf)
! {
! /* For early dwarf we may not create references to possibly optimized
! out objects as with early LTO resolve_addr will _not_ fix this
! up late. */
! rtl = rtl_for_decl_init (init, type);
! if (rtl)
! return add_const_value_attribute (die, rtl);
! }
/* If the host and target are sane, try harder. */
! if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
! && initializer_constant_valid_p (init, type))
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
if (size > 0 && (int) size == size)
*************** add_scalar_info (dw_die_ref die, enum dw
*** 16779,16784 ****
--- 17067,17085 ----
if (decl != NULL_TREE)
{
dw_die_ref decl_die = lookup_decl_die (decl);
+ /* ??? Force a DIE for the decl - this is probably
+ artificially generated by gimplifying type sizes and thus
+ early debug wouldn't have created a DIE for it because
+ the decl is not associated with any block. */
+ /* ??? This doesn't work as type sizes are not always gimplified
+ like for
+ void fred () { int n = 10; double (*x)[n]; }
+ and thus we fail to clear DECL_IGNORED_P for those. But
+ we don't have debug-info for the above case anyway. */
+ if (! decl_die
+ && ! DECL_IGNORED_P (decl)
+ && DECL_ARTIFICIAL (decl))
+ decl_die = force_decl_die (decl);
/* ??? Can this happen, or should the variable have been bound
first? Probably it can, since I imagine that we try to create
*************** gen_formal_parameter_die (tree node, tre
*** 18038,18044 ****
thing. */
if (parm_die && parm_die->die_parent != context_die)
{
! if (!DECL_ABSTRACT_P (node))
{
/* This can happen when creating an inlined instance, in
which case we need to create a new DIE that will get
--- 18339,18347 ----
thing. */
if (parm_die && parm_die->die_parent != context_die)
{
! /* ??? The DIE parent is the "abstract" copy and the context_die
! is the specification "copy". */
! if (!DECL_ABSTRACT_P (node) && !in_lto_p)
{
/* This can happen when creating an inlined instance, in
which case we need to create a new DIE that will get
*************** gen_type_die_for_member (tree type, tree
*** 18307,18313 ****
/* Forward declare these functions, because they are mutually recursive
with their set_block_* pairing functions. */
static void set_decl_origin_self (tree);
- static void set_decl_abstract_flags (tree, vec<tree> &);
/* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
--- 18610,18615 ----
*************** set_decl_origin_self (tree decl)
*** 18380,18530 ****
}
}
! /* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
! and if it wasn't 1 before, push it to abstract_vec vector.
! For all local decls and all local sub-blocks (recursively) do it
! too. */
!
! static void
! set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
! {
! tree local_decl;
! tree subblock;
! unsigned int i;
!
! if (!BLOCK_ABSTRACT (stmt))
! {
! abstract_vec.safe_push (stmt);
! BLOCK_ABSTRACT (stmt) = 1;
! }
!
! for (local_decl = BLOCK_VARS (stmt);
! local_decl != NULL_TREE;
! local_decl = DECL_CHAIN (local_decl))
! if (! DECL_EXTERNAL (local_decl))
! set_decl_abstract_flags (local_decl, abstract_vec);
!
! for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
! {
! local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
! if ((TREE_CODE (local_decl) == VAR_DECL && !TREE_STATIC (local_decl))
! || TREE_CODE (local_decl) == PARM_DECL)
! set_decl_abstract_flags (local_decl, abstract_vec);
! }
!
! for (subblock = BLOCK_SUBBLOCKS (stmt);
! subblock != NULL_TREE;
! subblock = BLOCK_CHAIN (subblock))
! set_block_abstract_flags (subblock, abstract_vec);
! }
!
! /* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
! to 1 and if it wasn't 1 before, push to abstract_vec vector.
! In the case where the decl is a FUNCTION_DECL also set the abstract
! flags for all of the parameters, local vars, local
! blocks and sub-blocks (recursively). */
!
! static void
! set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
! {
! if (!DECL_ABSTRACT_P (decl))
! {
! abstract_vec.safe_push (decl);
! DECL_ABSTRACT_P (decl) = 1;
! }
!
! if (TREE_CODE (decl) == FUNCTION_DECL)
! {
! tree arg;
!
! for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
! if (!DECL_ABSTRACT_P (arg))
! {
! abstract_vec.safe_push (arg);
! DECL_ABSTRACT_P (arg) = 1;
! }
! if (DECL_INITIAL (decl) != NULL_TREE
! && DECL_INITIAL (decl) != error_mark_node)
! set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
! }
! }
!
! /* Generate the DWARF2 info for the "abstract" instance of a function which we
! may later generate inlined and/or out-of-line instances of.
!
! FIXME: In the early-dwarf world, this function, and most of the
! DECL_ABSTRACT code should be obsoleted. The early DIE _is_
! the abstract instance. All we would need to do is annotate
! the early DIE with the appropriate DW_AT_inline in late
! dwarf (perhaps in gen_inlined_subroutine_die).
!
! However, we can't do this yet, because LTO streaming of DIEs
! has not been implemented yet. */
static void
dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
- tree save_fn;
- tree context;
- hash_table<decl_loc_hasher> *old_decl_loc_table;
- hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
- int old_call_site_count, old_tail_call_site_count;
- struct call_arg_loc_node *old_call_arg_locations;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
old_die = lookup_decl_die (decl);
! if (old_die && get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
! /* We can be called while recursively when seeing block defining inlined subroutine
! DIE. Be sure to not clobber the outer location table nor use it or we would
! get locations in abstract instantces. */
! old_decl_loc_table = decl_loc_table;
! decl_loc_table = NULL;
! old_cached_dw_loc_list_table = cached_dw_loc_list_table;
! cached_dw_loc_list_table = NULL;
! old_call_arg_locations = call_arg_locations;
! call_arg_locations = NULL;
! old_call_site_count = call_site_count;
! call_site_count = -1;
! old_tail_call_site_count = tail_call_site_count;
! tail_call_site_count = -1;
! /* Be sure we've emitted the in-class declaration DIE (if any) first, so
! we don't get confused by DECL_ABSTRACT_P. */
! if (debug_info_level > DINFO_LEVEL_TERSE)
{
! context = decl_class_context (decl);
! if (context)
! gen_type_die_for_member
! (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
}
! /* Pretend we've just finished compiling this function. */
! save_fn = current_function_decl;
! current_function_decl = decl;
!
! auto_vec<tree, 64> abstract_vec;
! set_decl_abstract_flags (decl, abstract_vec);
! dwarf2out_decl (decl);
! unsigned int i;
! tree t;
! FOR_EACH_VEC_ELT (abstract_vec, i, t)
! if (TREE_CODE (t) == BLOCK)
! BLOCK_ABSTRACT (t) = 0;
! else
! DECL_ABSTRACT_P (t) = 0;
!
! current_function_decl = save_fn;
! decl_loc_table = old_decl_loc_table;
! cached_dw_loc_list_table = old_cached_dw_loc_list_table;
! call_arg_locations = old_call_arg_locations;
! call_site_count = old_call_site_count;
! tail_call_site_count = old_tail_call_site_count;
}
/* Helper function of premark_used_types() which gets called through
--- 18682,18740 ----
}
}
! /* Mark the early DIE for DECL as the abstract instance. */
static void
dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
+ if (DECL_IGNORED_P (decl))
+ return;
+
old_die = lookup_decl_die (decl);
! /* With early debug we always have an old DIE. */
! gcc_assert (old_die != NULL);
! if (get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
! #if 0
! /* For LTO we end up with a stub DIE here refering to the early
! dwarf. We can't put DW_AT_inline there (nor can we check if
! it is there) and we don't want to clone another "abstract"
! instance just to be able to do that.
! So simply do nothing(?).
! ??? We have to fix code refering to the abstract instance
! to refer to the stub DIE (which becomes the concrete instance)
! to refer to the stub DIEs target. Otherwise we generate
! wrong debug. */
! if (in_lto_p)
! return;
! #endif
! /* Go ahead and put DW_AT_inline on the DIE. */
! if (DECL_DECLARED_INLINE_P (decl))
{
! if (cgraph_function_possibly_inlined_p (decl))
! add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_inlined);
! else
! add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
! }
! else
! {
! if (cgraph_function_possibly_inlined_p (decl))
! add_AT_unsigned (old_die, DW_AT_inline, DW_INL_inlined);
! else
! add_AT_unsigned (old_die, DW_AT_inline, DW_INL_not_inlined);
}
! if (DECL_DECLARED_INLINE_P (decl)
! && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
! add_AT_flag (old_die, DW_AT_artificial, 1);
}
/* Helper function of premark_used_types() which gets called through
*************** gen_subprogram_die (tree decl, dw_die_re
*** 18747,18753 ****
--- 18957,18972 ----
if (old_die && old_die->die_parent == NULL)
add_child_die (context_die, old_die);
+ #if 1
+ dw_die_ref c;
+ if (old_die
+ && (c = get_AT_ref (old_die, DW_AT_abstract_origin))
+ /* ??? In LTO all origin DIEs still refer to the early
+ debug copy. Detect that. */
+ && get_AT (c, DW_AT_inline))
+ #else
if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+ #endif
{
/* If we have a DW_AT_abstract_origin we have a working
cached version. */
*************** gen_subprogram_die (tree decl, dw_die_re
*** 18771,18776 ****
--- 18990,18998 ----
{
/* A declaration that has been previously dumped needs no
additional information. */
+ /* ??? In LTO an existing DIE always means an early generated DIE.
+ We should really refactor the entry points to dwarf generation
+ so we have the separate stages completely separated. */
if (declaration)
return;
*************** gen_subprogram_die (tree decl, dw_die_re
*** 19211,19219 ****
tree outer_scope = DECL_INITIAL (decl);
if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
{
- int call_site_note_count = 0;
- int tail_call_site_note_count = 0;
-
/* Emit a DW_TAG_variable DIE for a named return value. */
if (DECL_NAME (DECL_RESULT (decl)))
gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
--- 19433,19438 ----
*************** gen_subprogram_die (tree decl, dw_die_re
*** 19222,19376 ****
DIEs for the locals. The second time, we fill in the
location info. */
decls_for_scope (outer_scope, subr_die);
-
- if (call_arg_locations && !dwarf_strict)
- {
- struct call_arg_loc_node *ca_loc;
- for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
- {
- dw_die_ref die = NULL;
- rtx tloc = NULL_RTX, tlocc = NULL_RTX;
- rtx arg, next_arg;
-
- for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
- arg; arg = next_arg)
- {
- dw_loc_descr_ref reg, val;
- machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
- dw_die_ref cdie, tdie = NULL;
-
- next_arg = XEXP (arg, 1);
- if (REG_P (XEXP (XEXP (arg, 0), 0))
- && next_arg
- && MEM_P (XEXP (XEXP (next_arg, 0), 0))
- && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
- && REGNO (XEXP (XEXP (arg, 0), 0))
- == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
- next_arg = XEXP (next_arg, 1);
- if (mode == VOIDmode)
- {
- mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
- if (mode == VOIDmode)
- mode = GET_MODE (XEXP (arg, 0));
- }
- if (mode == VOIDmode || mode == BLKmode)
- continue;
- if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
- {
- gcc_assert (ca_loc->symbol_ref == NULL_RTX);
- tloc = XEXP (XEXP (arg, 0), 1);
- continue;
- }
- else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
- && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
- {
- gcc_assert (ca_loc->symbol_ref == NULL_RTX);
- tlocc = XEXP (XEXP (arg, 0), 1);
- continue;
- }
- reg = NULL;
- if (REG_P (XEXP (XEXP (arg, 0), 0)))
- reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
- VAR_INIT_STATUS_INITIALIZED);
- else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
- {
- rtx mem = XEXP (XEXP (arg, 0), 0);
- reg = mem_loc_descriptor (XEXP (mem, 0),
- get_address_mode (mem),
- GET_MODE (mem),
- VAR_INIT_STATUS_INITIALIZED);
- }
- else if (GET_CODE (XEXP (XEXP (arg, 0), 0))
- == DEBUG_PARAMETER_REF)
- {
- tree tdecl
- = DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
- tdie = lookup_decl_die (tdecl);
- if (tdie == NULL)
- continue;
- }
- else
- continue;
- if (reg == NULL
- && GET_CODE (XEXP (XEXP (arg, 0), 0))
- != DEBUG_PARAMETER_REF)
- continue;
- val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
- VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (val == NULL)
- continue;
- if (die == NULL)
- die = gen_call_site_die (decl, subr_die, ca_loc);
- cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
- NULL_TREE);
- if (reg != NULL)
- add_AT_loc (cdie, DW_AT_location, reg);
- else if (tdie != NULL)
- add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
- add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
- if (next_arg != XEXP (arg, 1))
- {
- mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
- if (mode == VOIDmode)
- mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0));
- val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
- 0), 1),
- mode, VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (val != NULL)
- add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
- }
- }
- if (die == NULL
- && (ca_loc->symbol_ref || tloc))
- die = gen_call_site_die (decl, subr_die, ca_loc);
- if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
- {
- dw_loc_descr_ref tval = NULL;
-
- if (tloc != NULL_RTX)
- tval = mem_loc_descriptor (tloc,
- GET_MODE (tloc) == VOIDmode
- ? Pmode : GET_MODE (tloc),
- VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tval)
- add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
- else if (tlocc != NULL_RTX)
- {
- tval = mem_loc_descriptor (tlocc,
- GET_MODE (tlocc) == VOIDmode
- ? Pmode : GET_MODE (tlocc),
- VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tval)
- add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
- tval);
- }
- }
- if (die != NULL)
- {
- call_site_note_count++;
- if (ca_loc->tail_call_p)
- tail_call_site_note_count++;
- }
- }
- }
- call_arg_locations = NULL;
- call_arg_loc_last = NULL;
- if (tail_call_site_count >= 0
- && tail_call_site_count == tail_call_site_note_count
- && !dwarf_strict)
- {
- if (call_site_count >= 0
- && call_site_count == call_site_note_count)
- add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
- else
- add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
- }
- call_site_count = -1;
- tail_call_site_count = -1;
}
}
--- 19441,19446 ----
*************** gen_variable_die (tree decl, tree origin
*** 19669,19675 ****
&& (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
{
if (early_dwarf)
! add_pubname (decl_or_origin, var_die);
else
add_location_or_const_value_attribute (var_die, decl_or_origin,
decl == NULL, DW_AT_location);
--- 19739,19764 ----
&& (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
{
if (early_dwarf)
! {
! add_pubname (decl_or_origin, var_die);
! /* We use the early dwarf of a function as abstract instance,
! so make sure to add DW_AT_const_value attributes to it. */
! /* ??? This can end up adding a 4MB DW_AT_const_value even
! if we later output the initializer into .data. Now such
! a DW_AT_const_value is wasteful even for optimized out
! decls, so the following is fine but we really have to limit
! the size of DW_AT_const_values we output (a DW_AT_constant_value
! might be even smaller than the DW_OP_addr we generate to
! point to the in-memory location). */
! int sz;
! if (DECL_INITIAL (decl_or_origin)
! && (sz = int_size_in_bytes
! (TREE_TYPE (DECL_INITIAL (decl_or_origin)))) != -1
! /* So for now allow DW_AT_const_value of size less or equal to
! that what is required for the reference to emitted data. */
! && sz <= (PTR_SIZE + 2))
! tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
! }
else
add_location_or_const_value_attribute (var_die, decl_or_origin,
decl == NULL, DW_AT_location);
*************** gen_lexical_block_die (tree stmt, dw_die
*** 19905,19910 ****
--- 19994,20013 ----
{
/* If this is an inlined instance, create a new lexical die for
anything below to attach DW_AT_abstract_origin to. */
+ /* ??? Between early and late dwarf we get confused here
+ by set_block_origin_self () called by dwarf2out_function_decl
+ via gen_decl_die
+
+ If we're emitting an out-of-line copy of an inline function,
+ emit info for the abstract instance and set up to refer to it.
+
+ which ends up calling dwarf2out_abstract_function (late)
+ and then set_decl_origin_self. This should have been discovered
+ early already. Or rather we do have the abstract instance
+ output early already, no need to do that again. So
+ dwarf2out_abstract_function should take the early output
+ DIEs and create a duplicate that just refers back to the
+ "abstract" early instance? */
if (old_die)
{
stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
*************** gen_block_die (tree stmt, dw_die_ref con
*** 21008,21013 ****
--- 21111,21141 ----
decls_for_scope (stmt, context_die);
}
+ static tree
+ process_vla_type (tree *tp, int *walk_subtrees, void *ctx)
+ {
+ /* ??? walk_type_fields doesn't walk TYPE_SIZE and friends and
+ while it walks TYPE_DOMAIN for arrays it doesn't walk
+ TYPE_MIN/MAX_VALUE. Just special-case the ARRAY_TYPE domain
+ type case here for now. */
+ if (TREE_CODE (*tp) == INTEGER_TYPE)
+ {
+ if (TREE_CODE (TYPE_MIN_VALUE (*tp)) == VAR_DECL
+ && DECL_ARTIFICIAL (TYPE_MIN_VALUE (*tp))
+ && !DECL_IGNORED_P (TYPE_MIN_VALUE (*tp)))
+ gen_decl_die (TYPE_MIN_VALUE (*tp), NULL_TREE, (dw_die_ref) ctx);
+ if (TREE_CODE (TYPE_MAX_VALUE (*tp)) == VAR_DECL
+ && DECL_ARTIFICIAL (TYPE_MAX_VALUE (*tp))
+ && !DECL_IGNORED_P (TYPE_MAX_VALUE (*tp)))
+ gen_decl_die (TYPE_MAX_VALUE (*tp), NULL_TREE, (dw_die_ref) ctx);
+ }
+
+ if (!TYPE_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+ }
+
/* Process variable DECL (or variable with origin ORIGIN) within
block STMT and add it to CONTEXT_DIE. */
static void
*************** process_scope_var (tree stmt, tree decl,
*** 21020,21026 ****
die = lookup_decl_die (decl_or_origin);
else if (TREE_CODE (decl_or_origin) == TYPE_DECL
&& TYPE_DECL_IS_STUB (decl_or_origin))
! die = lookup_type_die (TREE_TYPE (decl_or_origin));
else
die = NULL;
--- 21148,21171 ----
die = lookup_decl_die (decl_or_origin);
else if (TREE_CODE (decl_or_origin) == TYPE_DECL
&& TYPE_DECL_IS_STUB (decl_or_origin))
! {
! /* ??? Ada has those in BLOCK scope but with types that have
! the a scope of other types (that's already odd). OTOH for
! these decls process_scope_var isn't the correct place to
! generate a DIE for the type (we won't generate one for the
! decl). Instead it looks like we may have this code only
! to eventually set the context of a limbo type DIE already
! created?! */
! /* ??? Note the issue is we try to re-create the DIE late
! if it was optimized as unused early (this BLOCK reference
! does not count as "use"). So refactoring dwarf2out_function_decl
! more to only include late parts should "fix" this as well
! (we'd simply never call gen_decl_die there but only its
! annotation part for existing dies). */
! die = lookup_type_die (TREE_TYPE (decl_or_origin));
! if (!die)
! return;
! }
else
die = NULL;
*************** process_scope_var (tree stmt, tree decl,
*** 21033,21039 ****
stmt, context_die);
}
else
! gen_decl_die (decl, origin, context_die);
}
/* Generate all of the decls declared within a given scope and (recursively)
--- 21178,21222 ----
stmt, context_die);
}
else
! {
! if (decl && DECL_P (decl))
! die = lookup_decl_die (decl);
!
! if (in_lto_p
! && die && die->die_parent != context_die)
! {
! /* ??? For non-LTO operation we do not want to get here via
! dwarf2out_abstract_function / set_decl_origin_self which
! ends up modifying the tree rep in some odd way instead
! of just playing with the DIEs. */
! /* We associate vars with their DECL_CONTEXT first which misses
! their BLOCK association. Move them. */
! gcc_assert (die->die_parent != NULL);
! /* ??? Moving is expensive. Better fix DECL_CONTEXT? */
! dw_die_ref prev = die->die_parent->die_child;
! while (prev->die_sib != die)
! prev = prev->die_sib;
! remove_child_with_prev (die, prev);
! add_child_die (context_die, die);
! }
!
! if (in_lto_p && decl
! && TREE_CODE (decl) == VAR_DECL
! && variably_modified_type_p (TREE_TYPE (decl),
! cfun ? cfun->decl : NULL_TREE))
! {
! /* We need to add location attributes to decls refered to
! from the decls type but we don't have DIEs for the type
! itself materialized. The decls are also not part of the
! functions BLOCK tree (because they are artificial). */
! walk_tree (&TREE_TYPE (decl), process_vla_type, NULL, NULL);
! }
!
! /* ??? The following gets stray type DIEs created even for decls
! that were created early. */
!
! gen_decl_die (decl, origin, context_die);
! }
}
/* Generate all of the decls declared within a given scope and (recursively)
*************** gen_decl_die (tree decl, tree origin, dw
*** 21436,21441 ****
--- 21619,21627 ----
/* If we're emitting an out-of-line copy of an inline function,
emit info for the abstract instance and set up to refer to it. */
+ /* ??? We have output an abstract instance early already and
+ could just re-use that. This is how LTO treats all functions
+ for example. */
else if (cgraph_function_possibly_inlined_p (decl)
&& ! DECL_ABSTRACT_P (decl)
&& ! class_or_namespace_scope_p (context_die)
*************** gen_decl_die (tree decl, tree origin, dw
*** 21449,21455 ****
}
/* Otherwise we're emitting the primary DIE for this decl. */
! else if (debug_info_level > DINFO_LEVEL_TERSE)
{
/* Before we describe the FUNCTION_DECL itself, make sure that we
have its containing type. */
--- 21635,21645 ----
}
/* Otherwise we're emitting the primary DIE for this decl. */
! else if (debug_info_level > DINFO_LEVEL_TERSE
! /* Do not generate stray type DIEs in late LTO dumping. */
! && !early_dwarf) /*(decl
! && lookup_decl_die (decl)))
! // && lookup_decl_die (decl)->dumped_early))*/
{
/* Before we describe the FUNCTION_DECL itself, make sure that we
have its containing type. */
*************** gen_decl_die (tree decl, tree origin, dw
*** 21516,21521 ****
--- 21706,21717 ----
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
+ {
+ /* ??? Avoid generating stray type DIEs during late LTO dwarf dumping.
+ All types have been dumped early. */
+ dw_die_ref die = decl ? lookup_decl_die (decl) : NULL;
+ if (!die) // || !die->dumped_early)
+ {
/* Output any DIEs that are needed to specify the type of this data
object. */
if (decl_by_reference_p (decl_or_origin))
*************** gen_decl_die (tree decl, tree origin, dw
*** 21527,21532 ****
--- 21723,21730 ----
class_origin = decl_class_context (decl_or_origin);
if (class_origin != NULL_TREE)
gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+ }
+ }
/* And its containing namespace. */
context_die = declare_in_namespace (decl_or_origin, context_die);
*************** dwarf2out_early_global_decl (tree decl)
*** 21624,21629 ****
--- 21822,21837 ----
if (!DECL_STRUCT_FUNCTION (decl))
goto early_decl_exit;
+ /* Emit an abstract origin of a function first. This happens
+ with C++ constructor clones for example and makes
+ dwarf2out_abstract_function happy which requires the early
+ DIE of the abstract instance to be present. */
+ if (DECL_ABSTRACT_ORIGIN (decl))
+ {
+ current_function_decl = DECL_ABSTRACT_ORIGIN (decl);
+ dwarf2out_decl (DECL_ABSTRACT_ORIGIN (decl));
+ }
+
current_function_decl = decl;
}
dwarf2out_decl (decl);
*************** dwarf2out_early_global_decl (tree decl)
*** 21640,21653 ****
static void
dwarf2out_late_global_decl (tree decl)
{
! /* Output any global decls we missed or fill-in any location
! information we were unable to determine on the first pass.
!
! Skip over functions because they were handled by the
! debug_hooks->function_decl() call in rest_of_handle_final. */
! if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
&& !POINTER_BOUNDS_P (decl))
! dwarf2out_decl (decl);
}
/* Output debug information for type decl DECL. Called from toplev.c
--- 21848,21863 ----
static void
dwarf2out_late_global_decl (tree decl)
{
! /* Fill-in any location information we were unable to determine
! on the first pass. */
! if (TREE_CODE (decl) == VAR_DECL
&& !POINTER_BOUNDS_P (decl))
! {
! dw_die_ref die = lookup_decl_die (decl);
! if (die)
! add_location_or_const_value_attribute (die, decl, false,
! DW_AT_location);
! }
}
/* Output debug information for type decl DECL. Called from toplev.c
*************** dwarf2out_decl (tree decl)
*** 21962,21992 ****
static void
dwarf2out_function_decl (tree decl)
{
! dwarf2out_decl (decl);
! call_arg_locations = NULL;
! call_arg_loc_last = NULL;
! call_site_count = -1;
! tail_call_site_count = -1;
! decl_loc_table->empty ();
! cached_dw_loc_list_table->empty ();
! }
! /* Output a marker (i.e. a label) for the beginning of the generated code for
! a lexical block. */
! static void
! dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
! unsigned int blocknum)
! {
! switch_to_section (current_function_section ());
! ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
! }
! /* Output a marker (i.e. a label) for the end of the generated code for a
! lexical block. */
! static void
! dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
switch_to_section (current_function_section ());
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
--- 22172,22769 ----
static void
dwarf2out_function_decl (tree decl)
{
! dw_die_ref context_die = comp_unit_die ();
! /* If we're a nested function, initially use a parent of NULL; if we're
! a plain function, this will be fixed up in decls_for_scope. If
! we're a method, it will be ignored, since we already have a DIE. */
! if (decl_function_context (decl)
! /* But if we're in terse mode, we don't care about scope. */
! && debug_info_level > DINFO_LEVEL_TERSE)
! context_die = NULL;
! if (DECL_IGNORED_P (decl))
! return;
! /* ??? Use the early die and check for DW_AT_inline. */
! bool inlined_instance_p = false;
! if (DECL_ORIGIN (decl) == decl
! && cgraph_function_possibly_inlined_p (decl))
! {
! set_decl_origin_self (decl);
! inlined_instance_p = true;
! }
! /* ??? context_die shouldn't really matter, if then take it from
! the early DIE. */
! #if 0
! gen_subprogram_die (decl, context_die);
!
! #else
! /* The following is gen_subprogram_die refactored so it only contains
! the "late" phase.
! ??? Well, mostly. */
!
! dw_die_ref old_die = lookup_decl_die (decl);
!
! /* An inlined instance, tag a new DIE with DW_AT_abstract_origin. */
! dw_die_ref subr_die;
! if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
! {
! /* Fixup die_parent for the abstract instance of a nested
! inline function. */
! /* ??? necessary? */
! if (old_die && old_die->die_parent == NULL)
! add_child_die (context_die, old_die);
!
! if (! inlined_instance_p && old_die)
! {
! /* If we have a DW_AT_abstract_origin we have a working
! cached version. */
! subr_die = old_die;
! }
! else
! {
! subr_die = new_die (DW_TAG_subprogram, context_die, decl);
! add_abstract_origin_attribute (subr_die, DECL_ORIGIN (decl));
! /* 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
! constructors/destructors when the user asks "break
! K::K". */
! add_linkage_name (subr_die, decl);
! }
! }
! else
! {
! /* ??? Prune the following bits. */
! /* If the definition comes from the same place as the declaration,
! maybe use the old DIE. We always want the DIE for this function
! that has the *_pc attributes to be under comp_unit_die so the
! debugger can find it. We also need to do this for abstract
! instances of inlines, since the spec requires the out-of-line copy
! to have the same parent. For local class methods, this doesn't
! apply; we just use the old DIE. */
! expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
! struct dwarf_file_data * file_index = lookup_filename (s.file);
! if ((is_cu_die (old_die->die_parent)
! /* This condition fixes the inconsistency/ICE with the
! following Fortran test (or some derivative thereof) while
! building libgfortran:
!
! module some_m
! contains
! logical function funky (FLAG)
! funky = .true.
! end function
! end module
! */
! || (old_die->die_parent
! && old_die->die_parent->die_tag == DW_TAG_module)
! || context_die == NULL)
! && ((DECL_ARTIFICIAL (decl) || in_lto_p)
! || (get_AT_file (old_die, DW_AT_decl_file) == file_index
! && (get_AT_unsigned (old_die, DW_AT_decl_line)
! == (unsigned) s.line))))
! {
! subr_die = old_die;
!
! /* Clear out the declaration attribute, but leave the
! parameters so they can be augmented with location
! information later. Unless this was a declaration, in
! which case, wipe out the nameless parameters and recreate
! them further down. */
! if (remove_AT (subr_die, DW_AT_declaration))
! {
!
! remove_AT (subr_die, DW_AT_object_pointer);
! remove_child_TAG (subr_die, DW_TAG_formal_parameter);
! }
! }
! /* Make a specification pointing to the previously built
! declaration. */
! else
! {
! subr_die = new_die (DW_TAG_subprogram, context_die, decl);
! add_AT_specification (subr_die, old_die);
! add_pubname (decl, subr_die);
! if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
! add_AT_file (subr_die, DW_AT_decl_file, file_index);
! if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
! add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
!
! /* If the prototype had an 'auto' or 'decltype(auto)' return type,
! emit the real type on the definition die. */
! if (is_cxx() && debug_info_level > DINFO_LEVEL_TERSE)
! {
! dw_die_ref die = get_AT_ref (old_die, DW_AT_type);
! if (die == auto_die || die == decltype_auto_die)
! add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
! TYPE_UNQUALIFIED, context_die);
! }
! }
! }
!
! /* Unless we have an existing non-declaration DIE, equate the new
! DIE. */
! /* ??? The is_declaration_die check doesn't work in_lto_p.
! We rather always want to equate if we generated a new DIE(?!). */
! if (!old_die || is_declaration_die (old_die))
! equate_decl_number_to_die (decl, subr_die);
!
! /* For non DECL_EXTERNALs, if range information is available, fill
! the DIE with it. */
! {
! HOST_WIDE_INT cfa_fb_offset;
!
! struct function *fun = DECL_STRUCT_FUNCTION (decl);
!
! if (!flag_reorder_blocks_and_partition)
! {
! dw_fde_ref fde = fun->fde;
! if (fde->dw_fde_begin)
! {
! /* We have already generated the labels. */
! add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
! fde->dw_fde_end, false);
! }
! else
! {
! /* Create start/end labels and add the range. */
! char label_id_low[MAX_ARTIFICIAL_LABEL_BYTES];
! char label_id_high[MAX_ARTIFICIAL_LABEL_BYTES];
! ASM_GENERATE_INTERNAL_LABEL (label_id_low, FUNC_BEGIN_LABEL,
! current_function_funcdef_no);
! ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
! current_function_funcdef_no);
! add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
! false);
! }
!
! #if VMS_DEBUGGING_INFO
! /* HP OpenVMS Industry Standard 64: DWARF Extensions
! Section 2.3 Prologue and Epilogue Attributes:
! When a breakpoint is set on entry to a function, it is generally
! desirable for execution to be suspended, not on the very first
! instruction of the function, but rather at a point after the
! function's frame has been set up, after any language defined local
! declaration processing has been completed, and before execution of
! the first statement of the function begins. Debuggers generally
! cannot properly determine where this point is. Similarly for a
! breakpoint set on exit from a function. The prologue and epilogue
! attributes allow a compiler to communicate the location(s) to use. */
!
! {
! if (fde->dw_fde_vms_end_prologue)
! add_AT_vms_delta (subr_die, DW_AT_HP_prologue,
! fde->dw_fde_begin, fde->dw_fde_vms_end_prologue);
!
! if (fde->dw_fde_vms_begin_epilogue)
! add_AT_vms_delta (subr_die, DW_AT_HP_epilogue,
! fde->dw_fde_begin, fde->dw_fde_vms_begin_epilogue);
! }
! #endif
!
! }
! else
! {
! /* Generate pubnames entries for the split function code ranges. */
! dw_fde_ref fde = fun->fde;
!
! if (fde->dw_fde_second_begin)
! {
! if (dwarf_version >= 3 || !dwarf_strict)
! {
! /* We should use ranges for non-contiguous code section
! addresses. Use the actual code range for the initial
! section, since the HOT/COLD labels might precede an
! alignment offset. */
! bool range_list_added = false;
! add_ranges_by_labels (subr_die, fde->dw_fde_begin,
! fde->dw_fde_end, &range_list_added,
! false);
! add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
! fde->dw_fde_second_end,
! &range_list_added, false);
! if (range_list_added)
! add_ranges (NULL);
! }
! else
! {
! /* There is no real support in DW2 for this .. so we make
! a work-around. First, emit the pub name for the segment
! containing the function label. Then make and emit a
! simplified subprogram DIE for the second segment with the
! name pre-fixed by __hot/cold_sect_of_. We use the same
! linkage name for the second die so that gdb will find both
! sections when given "b foo". */
! const char *name = NULL;
! tree decl_name = DECL_NAME (decl);
! dw_die_ref seg_die;
!
! /* Do the 'primary' section. */
! add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
! fde->dw_fde_end, false);
!
! /* Build a minimal DIE for the secondary section. */
! seg_die = new_die (DW_TAG_subprogram,
! subr_die->die_parent, decl);
!
! if (TREE_PUBLIC (decl))
! add_AT_flag (seg_die, DW_AT_external, 1);
!
! if (decl_name != NULL
! && IDENTIFIER_POINTER (decl_name) != NULL)
! {
! name = dwarf2_name (decl, 1);
! if (! DECL_ARTIFICIAL (decl))
! add_src_coords_attributes (seg_die, decl);
!
! add_linkage_name (seg_die, decl);
! }
! gcc_assert (name != NULL);
! add_pure_or_virtual_attribute (seg_die, decl);
! if (DECL_ARTIFICIAL (decl))
! add_AT_flag (seg_die, DW_AT_artificial, 1);
!
! name = concat ("__second_sect_of_", name, NULL);
! add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
! fde->dw_fde_second_end, false);
! add_name_attribute (seg_die, name);
! if (want_pubnames ())
! add_pubname_string (name, seg_die);
! }
! }
! else
! add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
! false);
! }
!
! cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
!
! /* We define the "frame base" as the function's CFA. This is more
! convenient for several reasons: (1) It's stable across the prologue
! and epilogue, which makes it better than just a frame pointer,
! (2) With dwarf3, there exists a one-byte encoding that allows us
! to reference the .debug_frame data by proxy, but failing that,
! (3) We can at least reuse the code inspection and interpretation
! code that determines the CFA position at various points in the
! function. */
! if (dwarf_version >= 3 && targetm.debug_unwind_info () == UI_DWARF2)
! {
! dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0);
! add_AT_loc (subr_die, DW_AT_frame_base, op);
! }
! else
! {
! dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
! if (list->dw_loc_next)
! add_AT_loc_list (subr_die, DW_AT_frame_base, list);
! else
! add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
! }
!
! /* Compute a displacement from the "steady-state frame pointer" to
! the CFA. The former is what all stack slots and argument slots
! will reference in the rtl; the latter is what we've told the
! debugger about. We'll need to adjust all frame_base references
! by this displacement. */
! compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
!
! if (fun->static_chain_decl)
! add_AT_location_description
! (subr_die, DW_AT_static_link,
! loc_list_from_tree (fun->static_chain_decl, 2, NULL));
! }
!
! /* Now output descriptions of the arguments for this function. This gets
! (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
! for a FUNCTION_DECL doesn't indicate cases where there was a trailing
! `...' at the end of the formal parameter list. In order to find out if
! there was a trailing ellipsis or not, we must instead look at the type
! associated with the FUNCTION_DECL. This will be a node of type
! FUNCTION_TYPE. If the chain of type nodes hanging off of this
! FUNCTION_TYPE node ends with a void_type_node then there should *not* be
! an ellipsis at the end. */
!
! if (debug_info_level <= DINFO_LEVEL_TERSE)
! ;
! else
! {
! /* ??? Prune for late phase. */
! /* Generate DIEs to represent all known formal parameters. */
! tree parm = DECL_ARGUMENTS (decl);
! tree generic_decl = early_dwarf
! ? lang_hooks.decls.get_generic_function_decl (decl) : NULL;
! tree generic_decl_parm = generic_decl
! ? DECL_ARGUMENTS (generic_decl)
! : NULL;
!
! /* Now we want to walk the list of parameters of the function and
! emit their relevant DIEs.
!
! We consider the case of DECL being an instance of a generic function
! as well as it being a normal function.
!
! If DECL is an instance of a generic function we walk the
! parameters of the generic function declaration _and_ the parameters of
! DECL itself. This is useful because we want to emit specific DIEs for
! function parameter packs and those are declared as part of the
! generic function declaration. In that particular case,
! the parameter pack yields a DW_TAG_GNU_formal_parameter_pack DIE.
! That DIE has children DIEs representing the set of arguments
! of the pack. Note that the set of pack arguments can be empty.
! In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
! children DIE.
!
! Otherwise, we just consider the parameters of DECL. */
! while (generic_decl_parm || parm)
! {
! if (generic_decl_parm
! && lang_hooks.function_parameter_pack_p (generic_decl_parm))
! gen_formal_parameter_pack_die (generic_decl_parm,
! parm, subr_die,
! &parm);
! else if (parm && !POINTER_BOUNDS_P (parm))
! {
! dw_die_ref parm_die = gen_decl_die (parm, NULL, subr_die);
!
! if (parm == DECL_ARGUMENTS (decl)
! && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
! && parm_die
! && (dwarf_version >= 3 || !dwarf_strict))
! add_AT_die_ref (subr_die, DW_AT_object_pointer, parm_die);
!
! parm = DECL_CHAIN (parm);
! }
! else if (parm)
! parm = DECL_CHAIN (parm);
!
! if (generic_decl_parm)
! generic_decl_parm = DECL_CHAIN (generic_decl_parm);
! }
!
! /* Decide whether we need an unspecified_parameters DIE at the end.
! There are 2 more cases to do this for: 1) the ansi ... declaration -
! this is detectable when the end of the arg list is not a
! void_type_node 2) an unprototyped function declaration (not a
! definition). This just means that we have no info about the
! parameters at all. */
! if (prototype_p (TREE_TYPE (decl)))
! {
! /* This is the prototyped case, check for.... */
! if (stdarg_p (TREE_TYPE (decl)))
! gen_unspecified_parameters_die (decl, subr_die);
! }
! else if (DECL_INITIAL (decl) == NULL_TREE)
! gen_unspecified_parameters_die (decl, subr_die);
! }
!
! if (subr_die != old_die)
! /* Add the calling convention attribute if requested. */
! add_calling_convention_attribute (subr_die, decl);
!
! /* Output Dwarf info for all of the stuff within the body of the function
! (if it has one - it may be just a declaration).
!
! OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
! a function. This BLOCK actually represents the outermost binding contour
! for the function, i.e. the contour in which the function's formal
! parameters and labels get declared. Curiously, it appears that the front
! end doesn't actually put the PARM_DECL nodes for the current function onto
! the BLOCK_VARS list for this outer scope, but are strung off of the
! DECL_ARGUMENTS list for the function instead.
!
! The BLOCK_VARS list for the `outer_scope' does provide us with a list of
! the LABEL_DECL nodes for the function however, and we output DWARF info
! for those in decls_for_scope. Just within the `outer_scope' there will be
! a BLOCK node representing the function's outermost pair of curly braces,
! and any blocks used for the base and member initializers of a C++
! constructor function. */
! {
! /* ??? Prune this for late phase. */
! /* Emit a DW_TAG_variable DIE for a named return value. */
! if (DECL_NAME (DECL_RESULT (decl)))
! gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
!
! /* The first time through decls_for_scope we will generate the
! DIEs for the locals. The second time, we fill in the
! location info. */
! decls_for_scope (DECL_INITIAL (decl), subr_die);
! }
! #endif
!
! int call_site_note_count = 0;
! int tail_call_site_note_count = 0;
! if (call_arg_locations && !dwarf_strict)
! {
! struct call_arg_loc_node *ca_loc;
! for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
! {
! dw_die_ref die = NULL;
! rtx tloc = NULL_RTX, tlocc = NULL_RTX;
! rtx arg, next_arg;
!
! for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
! arg; arg = next_arg)
! {
! dw_loc_descr_ref reg, val;
! machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
! dw_die_ref cdie, tdie = NULL;
!
! next_arg = XEXP (arg, 1);
! if (REG_P (XEXP (XEXP (arg, 0), 0))
! && next_arg
! && MEM_P (XEXP (XEXP (next_arg, 0), 0))
! && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
! && REGNO (XEXP (XEXP (arg, 0), 0))
! == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
! next_arg = XEXP (next_arg, 1);
! if (mode == VOIDmode)
! {
! mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
! if (mode == VOIDmode)
! mode = GET_MODE (XEXP (arg, 0));
! }
! if (mode == VOIDmode || mode == BLKmode)
! continue;
! if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
! {
! gcc_assert (ca_loc->symbol_ref == NULL_RTX);
! tloc = XEXP (XEXP (arg, 0), 1);
! continue;
! }
! else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
! && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
! {
! gcc_assert (ca_loc->symbol_ref == NULL_RTX);
! tlocc = XEXP (XEXP (arg, 0), 1);
! continue;
! }
! reg = NULL;
! if (REG_P (XEXP (XEXP (arg, 0), 0)))
! reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
! VAR_INIT_STATUS_INITIALIZED);
! else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
! {
! rtx mem = XEXP (XEXP (arg, 0), 0);
! reg = mem_loc_descriptor (XEXP (mem, 0),
! get_address_mode (mem),
! GET_MODE (mem),
! VAR_INIT_STATUS_INITIALIZED);
! }
! else if (GET_CODE (XEXP (XEXP (arg, 0), 0))
! == DEBUG_PARAMETER_REF)
! {
! tree tdecl
! = DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
! tdie = lookup_decl_die (tdecl);
! if (tdie == NULL)
! continue;
! }
! else
! continue;
! if (reg == NULL
! && GET_CODE (XEXP (XEXP (arg, 0), 0))
! != DEBUG_PARAMETER_REF)
! continue;
! val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
! VOIDmode,
! VAR_INIT_STATUS_INITIALIZED);
! if (val == NULL)
! continue;
! if (die == NULL)
! die = gen_call_site_die (decl, subr_die, ca_loc);
! cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
! NULL_TREE);
! if (reg != NULL)
! add_AT_loc (cdie, DW_AT_location, reg);
! else if (tdie != NULL)
! add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
! add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
! if (next_arg != XEXP (arg, 1))
! {
! mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
! if (mode == VOIDmode)
! mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0));
! val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
! 0), 1),
! mode, VOIDmode,
! VAR_INIT_STATUS_INITIALIZED);
! if (val != NULL)
! add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
! }
! }
! if (die == NULL
! && (ca_loc->symbol_ref || tloc))
! die = gen_call_site_die (decl, subr_die, ca_loc);
! if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
! {
! dw_loc_descr_ref tval = NULL;
!
! if (tloc != NULL_RTX)
! tval = mem_loc_descriptor (tloc,
! GET_MODE (tloc) == VOIDmode
! ? Pmode : GET_MODE (tloc),
! VOIDmode,
! VAR_INIT_STATUS_INITIALIZED);
! if (tval)
! add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
! else if (tlocc != NULL_RTX)
! {
! tval = mem_loc_descriptor (tlocc,
! GET_MODE (tlocc) == VOIDmode
! ? Pmode : GET_MODE (tlocc),
! VOIDmode,
! VAR_INIT_STATUS_INITIALIZED);
! if (tval)
! add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
! tval);
! }
! }
! if (die != NULL)
! {
! call_site_note_count++;
! if (ca_loc->tail_call_p)
! tail_call_site_note_count++;
! }
! }
! }
! call_arg_locations = NULL;
! call_arg_loc_last = NULL;
! if (tail_call_site_count >= 0
! && tail_call_site_count == tail_call_site_note_count
! && !dwarf_strict)
! {
! if (call_site_count >= 0
! && call_site_count == call_site_note_count)
! add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
! else
! add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
! }
! call_site_count = -1;
! tail_call_site_count = -1;
!
! decl_loc_table->empty ();
! cached_dw_loc_list_table->empty ();
! }
!
! /* Output a marker (i.e. a label) for the beginning of the generated code for
! a lexical block. */
!
! static void
! dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
! unsigned int blocknum)
! {
! switch_to_section (current_function_section ());
! ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
! }
!
! /* Output a marker (i.e. a label) for the end of the generated code for a
! lexical block. */
!
! static void
! dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
switch_to_section (current_function_section ());
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
*************** append_entry_to_tmpl_value_parm_die_tabl
*** 22105,22110 ****
--- 22882,22889 ----
if (!die || !arg)
return;
+ gcc_assert (early_dwarf);
+
if (!tmpl_value_parm_die_table)
vec_alloc (tmpl_value_parm_die_table, 32);
*************** schedule_generic_params_dies_gen (tree t
*** 22134,22139 ****
--- 22913,22920 ----
if (!generic_type_p (t))
return;
+ gcc_assert (early_dwarf);
+
if (!generic_type_instances)
vec_alloc (generic_type_instances, 256);
*************** gen_remaining_tmpl_value_param_die_attri
*** 22149,22159 ****
{
if (tmpl_value_parm_die_table)
{
! unsigned i;
die_arg_entry *e;
FOR_EACH_VEC_ELT (*tmpl_value_parm_die_table, i, e)
! tree_add_const_value_attribute (e->die, e->arg);
}
}
--- 22930,22950 ----
{
if (tmpl_value_parm_die_table)
{
! unsigned i, j;
die_arg_entry *e;
+ /* We do this in two phases - first get the cases we can
+ handle during early-finish, preserving those we cannot
+ (containing symbolic constants where we don't yet know
+ whether we are going to output the referenced symbols).
+ For those we try again at late-finish. */
+ j = 0;
FOR_EACH_VEC_ELT (*tmpl_value_parm_die_table, i, e)
! {
! if (!tree_add_const_value_attribute (e->die, e->arg))
! (*tmpl_value_parm_die_table)[j++] = *e;
! }
! tmpl_value_parm_die_table->truncate (j);
}
}
*************** gen_scheduled_generic_parms_dies (void)
*** 22171,22179 ****
--- 22962,22976 ----
if (!generic_type_instances)
return;
+ /* We end up "recursing" into schedule_generic_params_dies_gen, so
+ pretend this generation is part of "early dwarf" as well. */
+ set_early_dwarf s;
+
FOR_EACH_VEC_ELT (*generic_type_instances, i, t)
if (COMPLETE_TYPE_P (t))
gen_generic_params_dies (t);
+
+ generic_type_instances = NULL;
}
*************** output_macinfo (void)
*** 23203,23276 ****
}
}
! /* Set up for Dwarf output at the start of compilation. */
! static void
! dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
{
! /* This option is currently broken, see (PR53118 and PR46102). */
! if (flag_eliminate_dwarf2_dups
! && strstr (lang_hooks.name, "C++"))
! {
! warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
! flag_eliminate_dwarf2_dups = 0;
! }
!
! /* Allocate the file_table. */
! file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
!
! #ifndef DWARF2_LINENO_DEBUGGING_INFO
! /* Allocate the decl_die_table. */
! decl_die_table = hash_table<decl_die_hasher>::create_ggc (10);
!
! /* Allocate the decl_loc_table. */
! decl_loc_table = hash_table<decl_loc_hasher>::create_ggc (10);
!
! /* Allocate the cached_dw_loc_list_table. */
! cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
!
! /* Allocate the initial hunk of the decl_scope_table. */
! vec_alloc (decl_scope_table, 256);
!
! /* Allocate the initial hunk of the abbrev_die_table. */
! abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
! (ABBREV_DIE_TABLE_INCREMENT);
! abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
! /* Zero-th entry is allocated, but unused. */
! abbrev_die_table_in_use = 1;
!
! /* Allocate the pubtypes and pubnames vectors. */
! vec_alloc (pubname_table, 32);
! vec_alloc (pubtype_table, 32);
! vec_alloc (incomplete_types, 64);
! vec_alloc (used_rtx_array, 32);
if (!dwarf_split_debug_info)
{
! debug_info_section = get_section (DEBUG_INFO_SECTION,
SECTION_DEBUG, NULL);
! debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
SECTION_DEBUG, NULL);
! debug_loc_section = get_section (DEBUG_LOC_SECTION,
SECTION_DEBUG, NULL);
}
else
{
! debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
! debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
! debug_addr_section = get_section (DEBUG_ADDR_SECTION,
SECTION_DEBUG, NULL);
! debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
SECTION_DEBUG, NULL);
! debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
SECTION_DEBUG, NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
! DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
/* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
the main .o, but the skeleton_line goes into the split off dwo. */
--- 24000,24069 ----
}
}
! /* Return NAME prefixed with PREFIX if non-NULL in a buffer that is
! valid until the next call to temp_prefixed_name. */
! static const char *
! temp_prefixed_name (const char *prefix, const char *name, const char *postfix)
{
! static char buffer[1024];
! if (!prefix && !postfix)
! return name;
! snprintf (buffer, 1024, "%s%s%s",
! prefix ? prefix : "", name, postfix ? postfix : "");
! return buffer;
! }
! /* Initialize the various sections and labels for dwarf output and prefix
! them with PREFIX if non-NULL. */
! static void
! init_sections_and_labels (const char *prefix, const char *postfix)
! {
! static unsigned generation = 0;
if (!dwarf_split_debug_info)
{
! debug_info_section = get_section (temp_prefixed_name
! (prefix, DEBUG_INFO_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_abbrev_section = get_section (temp_prefixed_name
! (prefix, DEBUG_ABBREV_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_loc_section = get_section (temp_prefixed_name
! (prefix, DEBUG_LOC_SECTION,
! postfix),
SECTION_DEBUG, NULL);
}
else
{
! debug_info_section = get_section (temp_prefixed_name
! (prefix, DEBUG_DWO_INFO_SECTION,
! postfix),
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
! debug_abbrev_section = get_section (temp_prefixed_name
! (prefix, DEBUG_DWO_ABBREV_SECTION,
! postfix),
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
! debug_addr_section = get_section (temp_prefixed_name
! (prefix, DEBUG_ADDR_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_skeleton_info_section = get_section (temp_prefixed_name
! (prefix, DEBUG_INFO_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_skeleton_abbrev_section = get_section (temp_prefixed_name
! (prefix,
! DEBUG_ABBREV_SECTION,
! postfix),
SECTION_DEBUG, NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
! DEBUG_SKELETON_ABBREV_SECTION_LABEL,
! generation);
/* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
the main .o, but the skeleton_line goes into the split off dwo. */
*************** dwarf2out_init (const char *filename ATT
*** 23278,23334 ****
= get_section (DEBUG_DWO_LINE_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
! DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
! DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
DEBUG_STR_DWO_SECTION_FLAGS, NULL);
}
! debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
SECTION_DEBUG, NULL);
! debug_macinfo_section = get_section (dwarf_strict
! ? DEBUG_MACINFO_SECTION
! : DEBUG_MACRO_SECTION,
DEBUG_MACRO_SECTION_FLAGS, NULL);
! debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
! debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
SECTION_DEBUG, NULL);
! debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
SECTION_DEBUG, NULL);
! debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
! debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
SECTION_DEBUG, NULL);
! debug_frame_section = get_section (DEBUG_FRAME_SECTION,
SECTION_DEBUG, NULL);
- ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
! DEBUG_ABBREV_SECTION_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
! COLD_TEXT_SECTION_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
!
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
! DEBUG_INFO_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
! DEBUG_LINE_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
! DEBUG_RANGES_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
! DEBUG_ADDR_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
dwarf_strict
? DEBUG_MACINFO_SECTION_LABEL
! : DEBUG_MACRO_SECTION_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
vec_alloc (macinfo_table, 64);
--- 24071,24193 ----
= get_section (DEBUG_DWO_LINE_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
! DEBUG_SKELETON_LINE_SECTION_LABEL,
! generation);
debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
! DEBUG_SKELETON_INFO_SECTION_LABEL,
! generation);
debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
DEBUG_STR_DWO_SECTION_FLAGS, NULL);
}
! debug_aranges_section = get_section (temp_prefixed_name
! (prefix, DEBUG_ARANGES_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_macinfo_section = get_section (temp_prefixed_name
! (prefix,
! dwarf_strict
! ? DEBUG_MACINFO_SECTION
! : DEBUG_MACRO_SECTION,
! postfix),
DEBUG_MACRO_SECTION_FLAGS, NULL);
! debug_line_section = get_section (temp_prefixed_name
! (prefix, DEBUG_LINE_SECTION, postfix),
SECTION_DEBUG, NULL);
! debug_pubnames_section = get_section (temp_prefixed_name
! (prefix, DEBUG_PUBNAMES_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_pubtypes_section = get_section (temp_prefixed_name
! (prefix, DEBUG_PUBTYPES_SECTION,
! postfix),
SECTION_DEBUG, NULL);
! debug_str_section = get_section (temp_prefixed_name
! (prefix, DEBUG_STR_SECTION, postfix),
DEBUG_STR_SECTION_FLAGS, NULL);
! debug_ranges_section = get_section (temp_prefixed_name
! (prefix, DEBUG_RANGES_SECTION, postfix),
SECTION_DEBUG, NULL);
! debug_frame_section = get_section (temp_prefixed_name
! (prefix, DEBUG_FRAME_SECTION, postfix),
SECTION_DEBUG, NULL);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
! DEBUG_ABBREV_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
! DEBUG_INFO_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
! DEBUG_LINE_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
! DEBUG_RANGES_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
! DEBUG_ADDR_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
dwarf_strict
? DEBUG_MACINFO_SECTION_LABEL
! : DEBUG_MACRO_SECTION_LABEL, generation);
! ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL,
! generation);
!
! ++generation;
! }
!
! /* Set up for Dwarf output at the start of compilation. */
!
! static void
! dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
! {
! /* This option is currently broken, see (PR53118 and PR46102). */
! if (flag_eliminate_dwarf2_dups
! && strstr (lang_hooks.name, "C++"))
! {
! warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
! flag_eliminate_dwarf2_dups = 0;
! }
!
! /* Allocate the file_table. */
! file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
!
! #ifndef DWARF2_LINENO_DEBUGGING_INFO
! /* Allocate the decl_die_table. */
! decl_die_table = hash_table<decl_die_hasher>::create_ggc (10);
!
! /* Allocate the decl_loc_table. */
! decl_loc_table = hash_table<decl_loc_hasher>::create_ggc (10);
!
! /* Allocate the cached_dw_loc_list_table. */
! cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
!
! /* Allocate the initial hunk of the decl_scope_table. */
! vec_alloc (decl_scope_table, 256);
!
! /* Allocate the initial hunk of the abbrev_die_table. */
! abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
! (ABBREV_DIE_TABLE_INCREMENT);
! abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
! /* Zero-th entry is allocated, but unused. */
! abbrev_die_table_in_use = 1;
!
! /* Allocate the pubtypes and pubnames vectors. */
! vec_alloc (pubname_table, 32);
! vec_alloc (pubtype_table, 32);
!
! vec_alloc (incomplete_types, 64);
!
! vec_alloc (used_rtx_array, 32);
!
! /* ??? Can't we defer this to dwarf2out_early_finish()? */
! init_sections_and_labels (NULL, NULL);
!
! ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
! COLD_TEXT_SECTION_LABEL, 0);
! ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
vec_alloc (macinfo_table, 64);
*************** prune_unused_types_update_strings (dw_di
*** 23784,23789 ****
--- 24643,24658 ----
}
}
+ /* Mark DIE and its children as removed. */
+
+ static void
+ mark_removed (dw_die_ref die)
+ {
+ dw_die_ref c;
+ die->removed = true;
+ FOR_EACH_CHILD (die, c, mark_removed (c));
+ }
+
/* Remove from the tree DIE any dies that aren't marked. */
static void
*************** prune_unused_types_prune (dw_die_ref die
*** 23799,23806 ****
c = die->die_child;
do {
! dw_die_ref prev = c;
! for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
if (c == die->die_child)
{
/* No marked children between 'prev' and the end of the list. */
--- 24668,24675 ----
c = die->die_child;
do {
! dw_die_ref prev = c, next;
! for (c = c->die_sib; ! c->die_mark; c = next)
if (c == die->die_child)
{
/* No marked children between 'prev' and the end of the list. */
*************** prune_unused_types_prune (dw_die_ref die
*** 23812,23819 ****
--- 24681,24696 ----
prev->die_sib = c->die_sib;
die->die_child = prev;
}
+ c->die_sib = NULL;
+ mark_removed (c);
return;
}
+ else
+ {
+ next = c->die_sib;
+ c->die_sib = NULL;
+ mark_removed (c);
+ }
if (c != prev->die_sib)
prev->die_sib = c;
*************** move_marked_base_types (void)
*** 24058,24065 ****
remove_child_with_prev (c, prev);
/* As base types got marked, there must be at least
one node other than DW_TAG_base_type. */
! gcc_assert (c != c->die_sib);
! c = c->die_sib;
}
}
while (c != die->die_child);
--- 24935,24942 ----
remove_child_with_prev (c, prev);
/* As base types got marked, there must be at least
one node other than DW_TAG_base_type. */
! gcc_assert (die->die_child != NULL);
! c = prev->die_sib;
}
}
while (c != die->die_child);
*************** optimize_location_lists (dw_die_ref die)
*** 25127,25171 ****
optimize_location_lists_1 (die, &htab);
}
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
static void
! dwarf2out_finish (const char *filename)
{
comdat_type_node *ctnode;
dw_die_ref main_comp_unit_die;
/* Flush out any latecomers to the limbo party. */
! dwarf2out_early_finish ();
! /* PCH might result in DW_AT_producer string being restored from the
! header compilation, so always fill it with empty string initially
! and overwrite only here. */
! dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
! producer_string = gen_producer_string ();
! producer->dw_attr_val.v.val_str->refcount--;
! producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
- gen_scheduled_generic_parms_dies ();
gen_remaining_tmpl_value_param_die_attribute ();
! /* Add the name for the main input file now. We delayed this from
! dwarf2out_init to avoid complications with PCH.
! For LTO produced units use a fixed artificial name to avoid
! leaking tempfile names into the dwarf. */
! if (!in_lto_p)
! add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
! else
! add_name_attribute (comp_unit_die (), "<artificial>");
! if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
! add_comp_dir_attribute (comp_unit_die ());
! else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
{
! bool p = false;
! file_table->traverse<bool *, file_table_relative_p> (&p);
! if (p)
! add_comp_dir_attribute (comp_unit_die ());
}
#if ENABLE_ASSERT_CHECKING
--- 26004,26195 ----
optimize_location_lists_1 (die, &htab);
}
+ /* Traverse the limbo die list, and add parent/child links. The only
+ dies without parents that should be here are concrete instances of
+ inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
+ For concrete instances, we can get the parent die from the abstract
+ instance. */
+
+ static void
+ flush_limbo_die_list (void)
+ {
+ limbo_die_node *node, *next_node;
+
+ for (node = limbo_die_list; node; node = next_node)
+ {
+ dw_die_ref die = node->die;
+ next_node = node->next;
+
+ if (die->die_parent == NULL)
+ {
+ dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+ if (origin && origin->die_parent)
+ add_child_die (origin->die_parent, die);
+ else if (is_cu_die (die))
+ ;
+ else if (seen_error ())
+ /* It's OK to be confused by errors in the input. */
+ add_child_die (comp_unit_die (), die);
+ else
+ {
+ /* In certain situations, the lexical block containing a
+ nested function can be optimized away, which results
+ in the nested function die being orphaned. Likewise
+ with the return type of that nested function. Force
+ this to be a child of the containing function.
+
+ It may happen that even the containing function got fully
+ inlined and optimized out. In that case we are lost and
+ assign the empty child. This should not be big issue as
+ the function is likely unreachable too. */
+ gcc_assert (node->created_for);
+
+ if (DECL_P (node->created_for))
+ origin = get_context_die (DECL_CONTEXT (node->created_for));
+ else if (TYPE_P (node->created_for))
+ origin = scope_die_for (node->created_for, comp_unit_die ());
+ else
+ origin = comp_unit_die ();
+
+ add_child_die (origin, die);
+ }
+ }
+ }
+
+ limbo_die_list = NULL;
+ }
+
+ /* Reset DIEs so we can output them again. */
+
+ static void
+ reset_dies (dw_die_ref die)
+ {
+ dw_die_ref c;
+
+ /* Remove stuff we re-generate. */
+ die->die_mark = 0;
+ die->die_offset = 0;
+ die->die_abbrev = 0;
+ remove_AT (die, DW_AT_sibling);
+
+ FOR_EACH_CHILD (die, c, reset_dies (c));
+ }
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
static void
! dwarf2out_finish (const char *)
{
comdat_type_node *ctnode;
dw_die_ref main_comp_unit_die;
/* Flush out any latecomers to the limbo party. */
! flush_limbo_die_list ();
! /* We shouldn't have any symbols with delayed asm names for
! DIEs generated after early finish. */
! gcc_assert (deferred_asm_name == NULL);
gen_remaining_tmpl_value_param_die_attribute ();
! if (flag_generate_lto)
! {
! gcc_assert (flag_fat_lto_objects);
!
! /* Switch back to regular section names and labels for the fat object
! part.
! ??? Do this in dwarf2out_finish ()? */
! init_sections_and_labels (NULL, NULL);
!
! /* ??? Prune stuff so that dwarf2out_finish runs successfully
! for the fat part of the object. */
! if (flag_fat_lto_objects)
! {
! reset_dies (comp_unit_die ());
! for (limbo_die_node *node = limbo_die_list; node; node = node->next)
! reset_dies (node->die);
! }
!
! /* Reset die CU symbol so we don't output it twice. */
! comp_unit_die ()->die_id.die_symbol = NULL;
! }
!
! /* Create parent - child relationship if we streamed in DIE reference
! stubs. */
! if (in_lto_p)
{
! bool changed;
! do
! {
! changed = false;
! for (limbo_die_node **node = &limbo_die_list;
! *node; )
! {
! if ((*node)->die->die_tag == DW_TAG_compile_unit)
! {
! if ((*node)->die == comp_unit_die ())
! *node = (*node)->next;
! else
! node = &(*node)->next;
! continue;
! }
!
! tree t = (*node)->created_for;
! tree context = NULL_TREE;
! if (DECL_P (t))
! context = DECL_CONTEXT (t);
! else if (TREE_CODE (t) == BLOCK)
! context = BLOCK_SUPERCONTEXT (t);
! /* ??? We don't output DIEs for wrapping scopes. Skip
! as many DIEs as needed. */
! if (context)
! while (TREE_CODE (context) == BLOCK
! && !BLOCK_DIE (context))
! context = BLOCK_SUPERCONTEXT (context);
! /* ??? We fail to re-parent BLOCK scope variables as
! dependent on frontend their DECL_CONTEXT is not the
! containing scope but the containing function. */
! if (context && DECL_P (context))
! {
! dw_die_ref ctx = lookup_decl_die (context);
! if (ctx)
! {
! add_child_die (ctx, (*node)->die);
! *node = (*node)->next;
! changed = true;
! continue;
! }
! }
! else if (context && TREE_CODE (context) == BLOCK)
! {
! dw_die_ref ctx = BLOCK_DIE (context);
! if (ctx)
! {
! add_child_die (ctx, (*node)->die);
! *node = (*node)->next;
! changed = true;
! continue;
! }
! }
! else if (!context)
! {
! /* ??? In some cases the C++ FE (at least) fails to
! set DECL_CONTEXT properly. Simply globalize stuff
! in this case. For example
! __dso_handle created via iostream line 74 col 25. */
! // gcc_assert ((*node)->die->dumped_early);
! add_child_die (comp_unit_die (), (*node)->die);
! *node = (*node)->next;
! changed = true;
! continue;
! }
!
! node = &(*node)->next;
! }
! }
! while (changed);
}
#if ENABLE_ASSERT_CHECKING
*************** dwarf2out_finish (const char *filename)
*** 25175,25217 ****
}
#endif
resolve_addr (comp_unit_die ());
move_marked_base_types ();
- /* Walk through the list of incomplete types again, trying once more to
- emit full debugging info for them. */
- retry_incomplete_types ();
-
- if (flag_eliminate_unused_debug_types)
- prune_unused_types ();
-
- /* Generate separate COMDAT sections for type DIEs. */
- if (use_debug_types)
- {
- break_out_comdat_types (comp_unit_die ());
-
- /* Each new type_unit DIE was added to the limbo die list when created.
- Since these have all been added to comdat_type_list, clear the
- limbo die list. */
- limbo_die_list = NULL;
-
- /* For each new comdat type unit, copy declarations for incomplete
- types to make the new unit self-contained (i.e., no direct
- references to the main compile unit). */
- for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
- copy_decls_for_unworthy_types (ctnode->root_die);
- copy_decls_for_unworthy_types (comp_unit_die ());
-
- /* In the process of copying declarations from one unit to another,
- we may have left some declarations behind that are no longer
- referenced. Prune them. */
- prune_unused_types ();
- }
-
- /* Generate separate CUs for each of the include files we've seen.
- They will go into limbo_die_list. */
- if (flag_eliminate_dwarf2_dups)
- break_out_includes (comp_unit_die ());
-
/* Traverse the DIE's and add sibling attributes to those DIE's that
have children. */
add_sibling_attributes (comp_unit_die ());
--- 26199,26210 ----
}
#endif
resolve_addr (comp_unit_die ());
+ /* ??? The following should be part of early dwarf but currently
+ base-types are marked in resolve_addr (taking advantage of
+ doing this only on the dwarf that remains after resolve_addr
+ which eventually prunes some DIEs). */
move_marked_base_types ();
/* Traverse the DIE's and add sibling attributes to those DIE's that
have children. */
add_sibling_attributes (comp_unit_die ());
*************** dwarf2out_finish (const char *filename)
*** 25481,25489 ****
has run. */
static void
! dwarf2out_early_finish (void)
{
! limbo_die_node *node, *next_node;
/* Add DW_AT_linkage_name for all deferred DIEs. */
for (node = deferred_asm_name; node; node = node->next)
--- 26474,26497 ----
has run. */
static void
! dwarf2out_early_finish (const char *filename)
{
! comdat_type_node *ctnode;
!
! /* Pick the first TRANSLATION_UNIT_DECL we didn't create a DIE for
! and equate it with our default CU DIE. LTO output needs to be
! able to lookup DIEs for translation unit decls. */
! unsigned i;
! tree decl;
! FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, decl)
! if (!lookup_decl_die (decl))
! {
! // A gcc_unreachable () should work here after the main CU
! // hook got added?
! equate_decl_number_to_die (decl, comp_unit_die ());
! }
!
! limbo_die_node *node;
/* Add DW_AT_linkage_name for all deferred DIEs. */
for (node = deferred_asm_name; node; node = node->next)
*************** dwarf2out_early_finish (void)
*** 25501,25557 ****
}
deferred_asm_name = NULL;
! /* Traverse the limbo die list, and add parent/child links. The only
! dies without parents that should be here are concrete instances of
! inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
! For concrete instances, we can get the parent die from the abstract
! instance.
!
! The point here is to flush out the limbo list so that it is empty
and we don't need to stream it for LTO. */
! for (node = limbo_die_list; node; node = next_node)
{
! dw_die_ref die = node->die;
! next_node = node->next;
! if (die->die_parent == NULL)
! {
! dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
! if (origin && origin->die_parent)
! add_child_die (origin->die_parent, die);
! else if (is_cu_die (die))
! ;
! else if (seen_error ())
! /* It's OK to be confused by errors in the input. */
! add_child_die (comp_unit_die (), die);
! else
! {
! /* In certain situations, the lexical block containing a
! nested function can be optimized away, which results
! in the nested function die being orphaned. Likewise
! with the return type of that nested function. Force
! this to be a child of the containing function.
! It may happen that even the containing function got fully
! inlined and optimized out. In that case we are lost and
! assign the empty child. This should not be big issue as
! the function is likely unreachable too. */
! gcc_assert (node->created_for);
! if (DECL_P (node->created_for))
! origin = get_context_die (DECL_CONTEXT (node->created_for));
! else if (TYPE_P (node->created_for))
! origin = scope_die_for (node->created_for, comp_unit_die ());
! else
! origin = comp_unit_die ();
! add_child_die (origin, die);
! }
! }
}
! limbo_die_list = NULL;
}
/* Reset all state within dwarf2out.c so that we can rerun the compiler
--- 26509,26718 ----
}
deferred_asm_name = NULL;
! /* The point here is to flush out the limbo list so that it is empty
and we don't need to stream it for LTO. */
! flush_limbo_die_list ();
!
! /* PCH might result in DW_AT_producer string being restored from the
! header compilation, so always fill it with empty string initially
! and overwrite only here. */
! dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
! producer_string = gen_producer_string ();
! producer->dw_attr_val.v.val_str->refcount--;
! producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
!
! gen_scheduled_generic_parms_dies ();
! gen_remaining_tmpl_value_param_die_attribute ();
!
! /* Add the name for the main input file now. We delayed this from
! dwarf2out_init to avoid complications with PCH.
! For LTO produced units use a fixed artificial name to avoid
! leaking tempfile names into the dwarf. */
! if (!in_lto_p)
! add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
! else
! add_name_attribute (comp_unit_die (), "<artificial>");
! if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
! add_comp_dir_attribute (comp_unit_die ());
! else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
{
! bool p = false;
! file_table->traverse<bool *, file_table_relative_p> (&p);
! if (p)
! add_comp_dir_attribute (comp_unit_die ());
! }
! /* Walk through the list of incomplete types again, trying once more to
! emit full debugging info for them. */
! retry_incomplete_types ();
! if (flag_eliminate_unused_debug_types)
! /* ??? Doing prune_unused_types early means we need to restrict
! pruning somewhat otherwise we for example run into late code
! generating DIEs refering to callee decl DIEs failing or using
! less efficient symbol references.
! One way to improve things is to use the early cgraph we have
! and mark DIEs of all symbols as used. */
! prune_unused_types ();
! /* FIXME debug-early: Prune DIEs for unused decls. */
! /* Generate separate COMDAT sections for type DIEs. */
! if (use_debug_types)
! {
! break_out_comdat_types (comp_unit_die ());
! /* Each new type_unit DIE was added to the limbo die list when created.
! Since these have all been added to comdat_type_list, clear the
! limbo die list. */
! limbo_die_list = NULL;
!
! /* For each new comdat type unit, copy declarations for incomplete
! types to make the new unit self-contained (i.e., no direct
! references to the main compile unit). */
! for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
! copy_decls_for_unworthy_types (ctnode->root_die);
! copy_decls_for_unworthy_types (comp_unit_die ());
!
! /* In the process of copying declarations from one unit to another,
! we may have left some declarations behind that are no longer
! referenced. Prune them. */
! prune_unused_types ();
}
! /* Generate separate CUs for each of the include files we've seen.
! They will go into limbo_die_list. */
! if (flag_eliminate_dwarf2_dups)
! break_out_includes (comp_unit_die ());
!
!
! /* Do not generate DWARF assembler now when not producing LTO bytecode.
! ??? The following code in principle handles split DWARF producing but
! it has some issues (and it's likely not desired). */
! if (!flag_generate_lto)
! return;
!
! /* Now as we are going to output for LTO switch sections and labels
! to the _gnu.lto prefixed variants. */
! char postfix[20];
! /* ??? The LTO input machinery doesn't like the ID directly after
! the prefix, but unless the linker scripting can handle a postfix
! and we can bear the ugliness of having both a prefix and a suffix... */
! sprintf (postfix, "." HOST_WIDE_INT_PRINT_HEX_PURE, get_random_seed (false));
! /* ??? Can't use .gnu.lto_ as prefix here as GAS sets 'E'xclude on
! those sections and that causes unrecoverable pain down the machinery.
! ??? Of course this means the sections stay in a FAT non-LTO link. */
! init_sections_and_labels (".gnu.debuglto_"/*section_name_prefix*/, postfix);
!
! /* ??? Duplicated from dwarf2out_finish. */
!
! /* Traverse the DIE's and add add sibling attributes to those DIE's
! that have children. */
! add_sibling_attributes (comp_unit_die ());
! for (node = limbo_die_list; node; node = node->next)
! add_sibling_attributes (node->die);
! for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
! add_sibling_attributes (ctnode->root_die);
!
! if (have_macinfo)
! add_AT_macptr (comp_unit_die (),
! dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
! macinfo_section_label);
!
! save_macinfo_strings ();
!
! /* Output all of the compilation units. We put the main one last so that
! the offsets are available to output_pubnames. */
! for (node = limbo_die_list; node; node = node->next)
! output_comp_unit (node->die, 0);
!
! hash_table<comdat_type_hasher> comdat_type_table (100);
! for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
! {
! comdat_type_node **slot = comdat_type_table.find_slot (ctnode, INSERT);
!
! /* Don't output duplicate types. */
! if (*slot != HTAB_EMPTY_ENTRY)
! continue;
!
! /* Add a pointer to the line table for the main compilation unit
! so that the debugger can make sense of DW_AT_decl_file
! attributes. */
! if (debug_info_level >= DINFO_LEVEL_TERSE)
! add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
! (!dwarf_split_debug_info
! ? debug_line_section_label
! : debug_skeleton_line_section_label));
!
! output_comdat_type_unit (ctnode);
! *slot = ctnode;
! }
!
! /* The AT_pubnames attribute needs to go in all skeleton dies, including
! both the main_cu and all skeleton TUs. Making this call unconditional
! would end up either adding a second copy of the AT_pubnames attribute, or
! requiring a special case in add_top_level_skeleton_die_attrs. */
! if (!dwarf_split_debug_info)
! add_AT_pubnames (comp_unit_die ());
!
! /* Stick a unique symbol to the main debuginfo section. */
! compute_section_prefix_1 (comp_unit_die (), false);
!
! /* Output the main compilation unit if non-empty or if .debug_macinfo
! or .debug_macro will be emitted. */
! output_comp_unit (comp_unit_die (), have_macinfo);
!
! /* Output the abbreviation table. */
! if (abbrev_die_table_in_use != 1)
! {
! switch_to_section (debug_abbrev_section);
! ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
! output_abbrev_section ();
! }
!
! /* Have to end the macro section. */
! if (have_macinfo)
! {
! switch_to_section (debug_macinfo_section);
! ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
! output_macinfo ();
! dw2_asm_output_data (1, 0, "End compilation unit");
! }
!
!
! /* If we emitted any indirect strings, output the string table too. */
! if (debug_str_hash || skeleton_debug_str_hash)
! output_indirect_strings ();
!
! #if 0
! /* ??? Not needed, copying full .symtab just works - though we
! need to avoid clashes with FAT object symbols of course. */
! /* Output a symbol mapping, section -> symbol for the LTO part. */
! char symsecname[256];
! sprintf (symsecname, ".gnu.debuglto_.debug_sym." HOST_WIDE_INT_PRINT_HEX_PURE,
! /*section_name_prefix,*/ get_random_seed (false));
! section *syms = get_section (symsecname, SECTION_DEBUG, NULL);
! switch_to_section (syms);
!
! char buf[1024];
! sprintf (buf, ".debug_info=%s", comp_unit_die ()->die_id.die_symbol);
! dw2_asm_output_nstring (buf, -1, NULL);
! #if 0
! /* ??? What about other created sections? What's their section name?
! That gets dropped in output_comp_unit () ... so add to .debug_sym
! in there? */
! for (node = limbo_die_list; node; node = node->next)
! {
! sprintf (buf, "??? = %s", comp_unit_die ()->die_id.die_symbol);
! dw2_asm_output_nstring (buf, -1, NULL);
! }
! #endif
! #endif
!
! /* Switch back to the text section. */
! switch_to_section (text_section);
!
! debug_str_hash = NULL; /* Contents are GCed. */
}
/* Reset all state within dwarf2out.c so that we can rerun the compiler
Index: trunk/gcc/gimplify.c
===================================================================
*** trunk.orig/gcc/gimplify.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/gimplify.c 2015-08-31 16:03:09.798995037 +0200
*************** gimplify_one_sizepos (tree *expr_p, gimp
*** 9149,9154 ****
--- 9149,9160 ----
*expr_p = unshare_expr (expr);
gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
+
+ /* The possibly generated temporary is interesting for debug information
+ to complete the VLA type sizes and bounds. Clear DECL_IGNORED_P. */
+ if (TREE_CODE (*expr_p) == VAR_DECL
+ && DECL_ARTIFICIAL (*expr_p))
+ DECL_IGNORED_P (*expr_p) = false;
}
/* Gimplify the body of statements of FNDECL and return a GIMPLE_BIND node
Index: trunk/gcc/lto-streamer-in.c
===================================================================
*** trunk.orig/gcc/lto-streamer-in.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-streamer-in.c 2015-08-31 16:03:09.798995037 +0200
*************** along with GCC; see the file COPYING3.
*** 58,63 ****
--- 58,64 ----
#include "target.h"
#include "gimple-streamer.h"
#include "cfgloop.h"
+ #include "debug.h"
struct freeing_string_slot_hasher : string_slot_hasher
*************** lto_input_variable_constructor (struct l
*** 1289,1294 ****
--- 1290,1297 ----
}
+ vec<dref_entry> dref_queue;
+
/* Read the physical representation of a tree node EXPR from
input block IB using the per-file context in DATA_IN. */
*************** lto_read_tree_1 (struct lto_input_block
*** 1309,1314 ****
--- 1312,1334 ----
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_register_external_die. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *str = streamer_read_string (data_in, ib);
+ if (str)
+ {
+ unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+ dref_entry e = { expr, str, off };
+ dref_queue.safe_push (e);
+ }
+ }
+
/* We should never try to instantiate an MD or NORMAL builtin here. */
if (TREE_CODE (expr) == FUNCTION_DECL)
gcc_assert (!streamer_handle_as_builtin_p (expr));
*************** lto_input_tree (struct lto_input_block *
*** 1470,1475 ****
--- 1490,1502 ----
{
unsigned len, entry_len;
lto_input_scc (ib, data_in, &len, &entry_len);
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
}
return lto_input_tree_1 (ib, data_in, tag, 0);
}
Index: trunk/gcc/lto-streamer-out.c
===================================================================
*** trunk.orig/gcc/lto-streamer-out.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-streamer-out.c 2015-08-31 16:03:09.799995046 +0200
*************** along with GCC; see the file COPYING3.
*** 54,59 ****
--- 54,60 ----
#include "cfgloop.h"
#include "builtins.h"
#include "gomp-constants.h"
+ #include "debug.h"
static void lto_write_tree (struct output_block*, tree, bool);
*************** lto_write_tree_1 (struct output_block *o
*** 377,382 ****
--- 378,403 ----
(ob->decl_state->symtab_node_encoder, expr);
stream_write_tree (ob, initial, ref_p);
}
+
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_die_ref_for_decl. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+ {
+ streamer_write_string (ob, ob->main_stream, sym, true);
+ streamer_write_uhwi (ob, off);
+ }
+ else
+ streamer_write_string (ob, ob->main_stream, NULL, true);
+ }
}
/* Write a physical representation of tree node EXPR to output block
*************** DFS::DFS_write_tree_body (struct output_
*** 750,755 ****
--- 771,777 ----
/* Do not follow DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
+ DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
*************** DFS::DFS_write_tree_body (struct output_
*** 864,874 ****
--- 886,900 ----
handle - those that represent inlined function scopes.
For the drop rest them on the floor instead of ICEing
in dwarf2out.c. */
+ #if 1
if (inlined_function_outer_scope_p (expr))
{
tree ultimate_origin = block_ultimate_origin (expr);
DFS_follow_tree_edge (ultimate_origin);
}
+ #else
+ DFS_follow_tree_edge (BLOCK_ABSTRACT_ORIGIN (expr));
+ #endif
/* Do not follow BLOCK_NONLOCALIZED_VARS. We cannot handle debug
information for early inlined BLOCKs so drop it on the floor instead
of ICEing in dwarf2out.c. */
Index: trunk/gcc/lto-streamer.h
===================================================================
*** trunk.orig/gcc/lto-streamer.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-streamer.h 2015-08-31 16:03:09.799995046 +0200
*************** DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ
*** 1220,1223 ****
--- 1220,1232 ----
DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
+ struct dref_entry {
+ tree decl;
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ };
+
+ extern vec<dref_entry> dref_queue;
+
+
#endif /* GCC_LTO_STREAMER_H */
Index: trunk/gcc/lto-wrapper.c
===================================================================
*** trunk.orig/gcc/lto-wrapper.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-wrapper.c 2015-08-31 16:03:09.800995055 +0200
*************** static char **output_names;
*** 70,75 ****
--- 70,77 ----
static char **offload_names;
static const char *offloadbegin, *offloadend;
static char *makefile;
+ static char *linker_script;
+ static char *debug_obj;
const char tool_name[] = "lto-wrapper";
*************** tool_cleanup (bool)
*** 86,91 ****
--- 88,97 ----
maybe_unlink (flto_out);
if (makefile)
maybe_unlink (makefile);
+ if (linker_script)
+ maybe_unlink (linker_script);
+ if (debug_obj)
+ maybe_unlink (debug_obj);
for (i = 0; i < nr; ++i)
{
maybe_unlink (input_names[i]);
*************** run_gcc (unsigned argc, char *argv[])
*** 894,901 ****
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
! unsigned lto_argc = 0, offload_argc = 0;
! char **lto_argv, **offload_argv;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
--- 900,907 ----
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
! unsigned lto_argc = 0, ltoobj_argc = 0, offload_argc = 0;
! char **lto_argv, **ltoobj_argv, **offload_argv;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
*************** run_gcc (unsigned argc, char *argv[])
*** 914,919 ****
--- 920,926 ----
/* Allocate arrays for input object files with LTO or offload IL,
and for possible preceding arguments. */
lto_argv = XNEWVEC (char *, argc);
+ ltoobj_argv = XNEWVEC (char *, argc);
offload_argv = XNEWVEC (char *, argc);
/* Look at saved options in the IL files. */
*************** run_gcc (unsigned argc, char *argv[])
*** 948,954 ****
collect_gcc))
{
have_lto = true;
! lto_argv[lto_argc++] = argv[i];
}
if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
--- 955,961 ----
collect_gcc))
{
have_lto = true;
! ltoobj_argv[ltoobj_argc++] = argv[i];
}
if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
*************** run_gcc (unsigned argc, char *argv[])
*** 1149,1168 ****
obstack_ptr_grow (&argv_obstack, "-fwpa");
}
! /* Append the input objects and possible preceding arguments. */
for (i = 0; i < lto_argc; ++i)
obstack_ptr_grow (&argv_obstack, lto_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
if (lto_mode == LTO_MODE_LTO)
{
printf ("%s\n", flto_out);
free (flto_out);
flto_out = NULL;
}
else
{
--- 1156,1260 ----
obstack_ptr_grow (&argv_obstack, "-fwpa");
}
! /* Append input arguments. */
for (i = 0; i < lto_argc; ++i)
obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+ /* Append the input objects. */
+ for (i = 0; i < ltoobj_argc; ++i)
+ obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
+ {
+ /* Produce an object with all debuginfo sections from the LTO input
+ objects. Write a linker script for this and do a partial link.
+ Eventually we can feed the linker with an output .o file that
+ is a linker script itself...(?) */
+ /* First generate the linker script. */
+ linker_script = make_temp_file ("script");
+ FILE *script = fopen (linker_script, "w");
+ char last_archive[1024];
+ last_archive[0] = '\0';
+ for (i = 0; i < ltoobj_argc; ++i)
+ {
+ char *p;
+ if ((p = strrchr (ltoobj_argv[i], '@')))
+ {
+ /* Add archives only once. */
+ if (strncmp (last_archive, ltoobj_argv[i], p - ltoobj_argv[i]) == 0
+ && last_archive[p - ltoobj_argv[i]] == '\0')
+ continue;
+ strncpy (last_archive, ltoobj_argv[i], p - ltoobj_argv[i]);
+ last_archive[p - ltoobj_argv[i]] = '\0';
+ fprintf (script, "INPUT(%s)\n", last_archive);
+ }
+ else
+ fprintf (script, "INPUT(%s)\n", ltoobj_argv[i]);
+ }
+ fprintf (script, "SECTIONS {\n");
+ fprintf (script,
+ " .debug_info 0 : { *(.gnu.debuglto_.debug_info*) }\n"
+ " .debug_abbrev 0 : { *(.gnu.debuglto_.debug_abbrev*) }\n"
+ " .debug_str 0 : { *(.gnu.debuglto_.debug_str*) }\n"
+ " .debug_pubnames 0 : { *(.gnu.debuglto_.debug_pubnames*) }\n"
+ " .debug_pubtypes 0 : { *(.gnu.debuglto_.debug_pubtypes*) }\n"
+ " .debug_macinfo 0 : { *(.gnu.debuglto_.debug_macro*) }\n"
+ /* The following is to workaround a bug in GOLD which has
+ the /DISCARD/ prevent it from creating the relocation
+ sections ultimatively causing it to crash. */
+ " .rela.debug_info : { *(.rela.debug_info) }\n"
+ " /DISCARD/ : { *(*) }\n");
+ fprintf (script, "}\n");
+ fclose (script);
+ }
+
+ {
+ /* For now invoke a partial link to gather the compile-time generated
+ debug-info into an input for the final link. */
+ obstack_ptr_grow (&argv_obstack, collect_gcc);
+ for (i = 1; i < decoded_options_count; ++i)
+ {
+ if (decoded_options[i].opt_index == OPT_B)
+ {
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ break;
+ }
+ }
+ /* ??? Using collect_gcc recurses because it passes -plugin to the
+ linker which in turn sees all inputs having LTO bytecode. So
+ pass -fno-use-linker-plugin. Probably still breaks with plugin
+ auto-loading?! */
+ obstack_ptr_grow (&argv_obstack, "-fno-use-linker-plugin");
+ obstack_ptr_grow (&argv_obstack, "-o");
+ debug_obj = make_temp_file ("debugobj");
+ obstack_ptr_grow (&argv_obstack, debug_obj);
+ obstack_ptr_grow (&argv_obstack, "-r");
+ obstack_ptr_grow (&argv_obstack, "-nostdlib");
+ obstack_ptr_grow (&argv_obstack, "-Wl,--whole-archive");
+ obstack_ptr_grow (&argv_obstack, "-Wl,-T");
+ obstack_ptr_grow (&argv_obstack, linker_script);
+ obstack_ptr_grow (&argv_obstack, NULL);
+ const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+ fork_execute (debug_link_argv[0],
+ CONST_CAST (char **, debug_link_argv), false);
+ }
+
if (lto_mode == LTO_MODE_LTO)
{
+ /* ??? We'd like to put the linker script creating debug_obj
+ here directly to avoid the extra I/O and to handle archives
+ more optimistically (drop unused members early debug). */
+ printf ("%s\n", debug_obj);
printf ("%s\n", flto_out);
free (flto_out);
flto_out = NULL;
+ free (debug_obj);
+ debug_obj = NULL;
+ free (linker_script);
+ linker_script = NULL;
}
else
{
*************** cont:
*** 1309,1314 ****
--- 1401,1414 ----
for (i = 0; i < nr; ++i)
maybe_unlink (input_names[i]);
}
+ /* ??? We'd like to put the linker script creating debug_obj
+ here directly to avoid the extra I/O and to handle archives
+ more optimistically (drop unused members early debug). */
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ free (linker_script);
+ linker_script = NULL;
for (i = 0; i < nr; ++i)
{
fputs (output_names[i], stdout);
Index: trunk/gcc/lto/lto.c
===================================================================
*** trunk.orig/gcc/lto/lto.c 2015-08-31 16:02:04.394412282 +0200
--- trunk/gcc/lto/lto.c 2015-08-31 16:03:09.800995055 +0200
*************** unify_scc (struct data_in *data_in, unsi
*** 1629,1634 ****
--- 1629,1637 ----
ggc_free (scc->entries[i]);
}
+ /* Drop DIE references. */
+ dref_queue.truncate (0);
+
break;
}
*************** lto_read_decls (struct lto_file_decl_dat
*** 1705,1711 ****
if (len == 1
&& (TREE_CODE (first) == IDENTIFIER_NODE
|| TREE_CODE (first) == INTEGER_CST
- || TREE_CODE (first) == TRANSLATION_UNIT_DECL
|| streamer_handle_as_builtin_p (first)))
continue;
--- 1708,1713 ----
*************** lto_read_decls (struct lto_file_decl_dat
*** 1745,1760 ****
if (TREE_CODE (t) == INTEGER_CST
&& !TREE_OVERFLOW (t))
cache_integer_cst (t);
- /* Register TYPE_DECLs with the debuginfo machinery. */
- if (!flag_wpa
- && TREE_CODE (t) == TYPE_DECL)
- {
- /* Dwarf2out needs location information.
- TODO: Moving this out of the streamer loop may noticealy
- improve ltrans linemap memory use. */
- data_in->location_cache.apply_location_cache ();
- debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
- }
if (!flag_ltrans)
{
/* Register variables and functions with the
--- 1747,1752 ----
*************** lto_read_decls (struct lto_file_decl_dat
*** 1770,1775 ****
--- 1762,1775 ----
vec_safe_push (tree_with_vars, t);
}
}
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
+
if (seen_type)
num_type_scc_trees += len;
}
Index: trunk/gcc/config/darwin.c
===================================================================
*** trunk.orig/gcc/config/darwin.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/config/darwin.c 2015-08-31 16:03:09.801995064 +0200
*************** static int darwin_dwarf_label_counter;
*** 2814,2820 ****
void
darwin_asm_output_dwarf_delta (FILE *file, int size,
! const char *lab1, const char *lab2)
{
int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
&& lab2[0] == '*' && lab2[1] == 'L');
--- 2814,2821 ----
void
darwin_asm_output_dwarf_delta (FILE *file, int size,
! const char *lab1, const char *lab2,
! HOST_WIDE_INT offset)
{
int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
&& lab2[0] == '*' && lab2[1] == 'L');
*************** darwin_asm_output_dwarf_delta (FILE *fil
*** 2828,2833 ****
--- 2829,2836 ----
assemble_name_raw (file, lab1);
fprintf (file, "-");
assemble_name_raw (file, lab2);
+ if (offset != 0)
+ fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
if (islocaldiff)
fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
}
*************** darwin_asm_output_dwarf_delta (FILE *fil
*** 2839,2845 ****
void
darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
! section *base)
{
char sname[64];
int namelen;
--- 2842,2848 ----
void
darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
! HOST_WIDE_INT offset, section *base)
{
char sname[64];
int namelen;
*************** darwin_asm_output_dwarf_offset (FILE *fi
*** 2850,2856 ****
namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
! darwin_asm_output_dwarf_delta (file, size, lab, sname);
}
/* Called from the within the TARGET_ASM_FILE_START for each target. */
--- 2853,2859 ----
namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
! darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
}
/* Called from the within the TARGET_ASM_FILE_START for each target. */
Index: trunk/gcc/config/darwin.h
===================================================================
*** trunk.orig/gcc/config/darwin.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/config/darwin.h 2015-08-31 16:03:09.801995064 +0200
*************** enum machopic_addr_class {
*** 826,835 ****
((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
#define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2) \
! darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2)
! #define ASM_OUTPUT_DWARF_OFFSET(FILE,SIZE,LABEL,BASE) \
! darwin_asm_output_dwarf_offset (FILE, SIZE, LABEL, BASE)
#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(ASM_OUT_FILE, ENCODING, SIZE, ADDR, DONE) \
if (ENCODING == ASM_PREFERRED_EH_DATA_FORMAT (2, 1)) { \
--- 826,835 ----
((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
#define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2) \
! darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2, 0)
! #define ASM_OUTPUT_DWARF_OFFSET(FILE,SIZE,LABEL,OFFSET,BASE) \
! darwin_asm_output_dwarf_offset (FILE, SIZE, LABEL, OFFSET, BASE)
#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(ASM_OUT_FILE, ENCODING, SIZE, ADDR, DONE) \
if (ENCODING == ASM_PREFERRED_EH_DATA_FORMAT (2, 1)) { \
Index: trunk/gcc/config/ia64/ia64.h
===================================================================
*** trunk.orig/gcc/config/ia64/ia64.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/config/ia64/ia64.h 2015-08-31 16:03:09.801995064 +0200
*************** do { \
*** 1583,1593 ****
/* Use section-relative relocations for debugging offsets. Unlike other
targets that fake this by putting the section VMA at 0, IA-64 has
proper relocations for them. */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, SECTION) \
do { \
fputs (integer_asm_op (SIZE, FALSE), FILE); \
fputs ("@secrel(", FILE); \
assemble_name (FILE, LABEL); \
fputc (')', FILE); \
} while (0)
--- 1583,1595 ----
/* Use section-relative relocations for debugging offsets. Unlike other
targets that fake this by putting the section VMA at 0, IA-64 has
proper relocations for them. */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, OFFSET, SECTION) \
do { \
fputs (integer_asm_op (SIZE, FALSE), FILE); \
fputs ("@secrel(", FILE); \
assemble_name (FILE, LABEL); \
+ if (offset != 0) \
+ fprintf (FILE, "+" HOST_WIDE_INT_PRINT_DEC, OFFSET); \
fputc (')', FILE); \
} while (0)
Index: trunk/gcc/doc/tm.texi.in
===================================================================
*** trunk.orig/gcc/doc/tm.texi.in 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/doc/tm.texi.in 2015-08-31 16:03:09.802995073 +0200
*************** between the two given labels in system d
*** 7020,7029 ****
slots on IA64 VMS, using an integer of the given size.
@end defmac
! @defmac ASM_OUTPUT_DWARF_OFFSET (@var{stream}, @var{size}, @var{label}, @var{section})
A C statement to issue assembly directives that create a
! section-relative reference to the given @var{label}, using an integer of the
! given @var{size}. The label is known to be defined in the given @var{section}.
@end defmac
@defmac ASM_OUTPUT_DWARF_PCREL (@var{stream}, @var{size}, @var{label})
--- 7020,7030 ----
slots on IA64 VMS, using an integer of the given size.
@end defmac
! @defmac ASM_OUTPUT_DWARF_OFFSET (@var{stream}, @var{size}, @var{label}, @var{offset}, @var{section})
A C statement to issue assembly directives that create a
! section-relative reference to the given @var{label} plus @var{offset}, using
! an integer of the given @var{size}. The label is known to be defined in the
! given @var{section}.
@end defmac
@defmac ASM_OUTPUT_DWARF_PCREL (@var{stream}, @var{size}, @var{label})
Index: trunk/gcc/tree-streamer-in.c
===================================================================
*** trunk.orig/gcc/tree-streamer-in.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/tree-streamer-in.c 2015-08-31 16:03:09.802995073 +0200
*************** lto_input_ts_decl_common_tree_pointers (
*** 706,711 ****
--- 706,712 ----
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
+ DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
*************** lto_input_ts_block_tree_pointers (struct
*** 918,923 ****
--- 919,927 ----
function scopes. For the rest them on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
+ if (BLOCK_ABSTRACT_ORIGIN (expr)
+ && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (expr)) == FUNCTION_DECL)
+ gcc_assert (!DECL_IS_BUILTIN (BLOCK_ABSTRACT_ORIGIN (expr)));
/* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information
for early inlined BLOCKs so drop it on the floor instead of ICEing in
dwarf2out.c. */
Index: trunk/gcc/tree-streamer-out.c
===================================================================
*** trunk.orig/gcc/tree-streamer-out.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/tree-streamer-out.c 2015-08-31 16:03:09.803995081 +0200
*************** write_ts_decl_common_tree_pointers (stru
*** 619,624 ****
--- 619,625 ----
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
+ stream_write_tree (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
*************** write_ts_block_tree_pointers (struct out
*** 800,812 ****
--- 801,818 ----
/* Stream BLOCK_ABSTRACT_ORIGIN for the limited cases we can handle - those
that represent inlined function scopes.
For the rest them on the floor instead of ICEing in dwarf2out.c. */
+ #if 1
if (inlined_function_outer_scope_p (expr))
{
tree ultimate_origin = block_ultimate_origin (expr);
stream_write_tree (ob, ultimate_origin, ref_p);
+ gcc_assert (!DECL_IS_BUILTIN (ultimate_origin));
}
else
stream_write_tree (ob, NULL_TREE, ref_p);
+ #else
+ stream_write_tree (ob, BLOCK_ABSTRACT_ORIGIN (expr), ref_p);
+ #endif
/* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information
for early inlined BLOCKs so drop it on the floor instead of ICEing in
dwarf2out.c. */
Index: trunk/gcc/config/darwin-protos.h
===================================================================
*** trunk.orig/gcc/config/darwin-protos.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/config/darwin-protos.h 2015-08-31 16:03:09.803995081 +0200
*************** extern void darwin_globalize_label (FILE
*** 91,99 ****
extern void darwin_assemble_visibility (tree, int);
extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
! const char *);
extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
! section *);
extern void darwin_asm_declare_object_name (FILE *, const char *, tree);
extern void darwin_asm_declare_constant_name (FILE *, const char *,
--- 91,99 ----
extern void darwin_assemble_visibility (tree, int);
extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
! const char *, HOST_WIDE_INT);
extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
! HOST_WIDE_INT, section *);
extern void darwin_asm_declare_object_name (FILE *, const char *, tree);
extern void darwin_asm_declare_constant_name (FILE *, const char *,
Index: trunk/gcc/config/i386/cygming.h
===================================================================
*** trunk.orig/gcc/config/i386/cygming.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/config/i386/cygming.h 2015-08-31 16:03:09.803995081 +0200
*************** along with GCC; see the file COPYING3.
*** 97,109 ****
/* Use section relative relocations for debugging offsets. Unlike
other targets that fake this by putting the section VMA at 0, PE
won't allow it. */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, SECTION) \
do { \
switch (SIZE) \
{ \
case 4: \
fputs ("\t.secrel32\t", FILE); \
assemble_name (FILE, LABEL); \
break; \
case 8: \
/* This is a hack. There is no 64-bit section relative \
--- 97,111 ----
/* Use section relative relocations for debugging offsets. Unlike
other targets that fake this by putting the section VMA at 0, PE
won't allow it. */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, OFFSET, SECTION) \
do { \
switch (SIZE) \
{ \
case 4: \
fputs ("\t.secrel32\t", FILE); \
assemble_name (FILE, LABEL); \
+ if (offset != 0) \
+ fprintf (FILE, "+" HOST_WIDE_INT_PRINT_DEC, offset) \
break; \
case 8: \
/* This is a hack. There is no 64-bit section relative \
*************** along with GCC; see the file COPYING3.
*** 113,118 ****
--- 115,122 ----
Fake the 64-bit offset by zero-extending it. */ \
fputs ("\t.secrel32\t", FILE); \
assemble_name (FILE, LABEL); \
+ if (offset != 0) \
+ fprintf (FILE, "+" HOST_WIDE_INT_PRINT_DEC, offset) \
fputs ("\n\t.long\t0", FILE); \
break; \
default: \
Index: trunk/gcc/cgraphunit.c
===================================================================
*** trunk.orig/gcc/cgraphunit.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/cgraphunit.c 2015-08-31 16:03:09.803995081 +0200
*************** analyze_functions (bool first_time)
*** 1135,1142 ****
at looking at optimized away DECLs, since
late_global_decl will subsequently be called from the
contents of the now pruned symbol table. */
if (!decl_function_context (node->decl))
! (*debug_hooks->late_global_decl) (node->decl);
node->remove ();
continue;
--- 1135,1157 ----
at looking at optimized away DECLs, since
late_global_decl will subsequently be called from the
contents of the now pruned symbol table. */
+ #if 0
if (!decl_function_context (node->decl))
! {
! /* ??? If we are about to generate LTO bytecode
! we can't have non-early DIEs because those may
! refer to decls we'll never output via
! loc_list_from_tree -> rtl_for_decl_location
! which via make_decl_rtl_for_debug relies on
! resolve_addr to remove referenes to not output
! symbols. Exactly what we do _not_ want here btw!
! We want the early path which only uses
! tree_add_const_value_attribute_for_decl. But
! we should have visited this decl early anyway.
! Thus do nothing now (or invent a new hook). */
! (*debug_hooks->late_global_decl) (node->decl);
! }
! #endif
node->remove ();
continue;
*************** symbol_table::finalize_compilation_unit
*** 2492,2498 ****
/* Clean up anything that needs cleaning up after initial debug
generation. */
! (*debug_hooks->early_finish) ();
}
/* Finally drive the pass manager. */
--- 2507,2513 ----
/* Clean up anything that needs cleaning up after initial debug
generation. */
! (*debug_hooks->early_finish) (main_input_filename);
}
/* Finally drive the pass manager. */
Index: trunk/gcc/dbxout.c
===================================================================
*** trunk.orig/gcc/dbxout.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/dbxout.c 2015-08-31 16:03:09.804995090 +0200
*************** const struct gcc_debug_hooks dbx_debug_h
*** 354,360 ****
{
dbxout_init,
dbxout_finish,
! debug_nothing_void,
debug_nothing_void,
debug_nothing_int_charstar,
debug_nothing_int_charstar,
--- 354,360 ----
{
dbxout_init,
dbxout_finish,
! debug_nothing_charstar,
debug_nothing_void,
debug_nothing_int_charstar,
debug_nothing_int_charstar,
*************** const struct gcc_debug_hooks dbx_debug_h
*** 380,385 ****
--- 380,387 ----
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
Index: trunk/gcc/debug.c
===================================================================
*** trunk.orig/gcc/debug.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/debug.c 2015-08-31 16:03:09.804995090 +0200
*************** const struct gcc_debug_hooks do_nothing_
*** 28,34 ****
{
debug_nothing_charstar,
debug_nothing_charstar,
! debug_nothing_void, /* early_finish */
debug_nothing_void,
debug_nothing_int_charstar,
debug_nothing_int_charstar,
--- 28,34 ----
{
debug_nothing_charstar,
debug_nothing_charstar,
! debug_nothing_charstar, /* early_finish */
debug_nothing_void,
debug_nothing_int_charstar,
debug_nothing_int_charstar,
*************** const struct gcc_debug_hooks do_nothing_
*** 50,55 ****
--- 50,57 ----
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
*************** debug_nothing_tree_int (tree decl ATTRIB
*** 139,141 ****
--- 141,156 ----
int local ATTRIBUTE_UNUSED)
{
}
+
+ bool
+ debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *)
+ {
+ return false;
+ }
+
+ void
+ debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT)
+ {
+ }
Index: trunk/gcc/debug.h
===================================================================
*** trunk.orig/gcc/debug.h 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/debug.h 2015-08-31 16:03:09.804995090 +0200
*************** struct gcc_debug_hooks
*** 31,37 ****
void (* finish) (const char *main_filename);
/* Run cleanups necessary after early debug generation. */
! void (* early_finish) (void);
/* Called from cgraph_optimize before starting to assemble
functions/variables/toplevel asms. */
--- 31,37 ----
void (* finish) (const char *main_filename);
/* Run cleanups necessary after early debug generation. */
! void (* early_finish) (const char *main_filename);
/* Called from cgraph_optimize before starting to assemble
functions/variables/toplevel asms. */
*************** struct gcc_debug_hooks
*** 146,151 ****
--- 146,159 ----
void (* imported_module_or_decl) (tree decl, tree name,
tree context, bool child);
+ /* Return true if a DIE for the tree is available and return a symbol
+ and offset that can be used to refer to it externally. */
+ bool (* die_ref_for_decl) (tree, const char **, unsigned HOST_WIDE_INT *);
+
+ /* Early debug information for the tree is available at symbol plus
+ offset externally. */
+ void (* register_external_die) (tree, const char *, unsigned HOST_WIDE_INT);
+
/* DECL is an inline function, whose body is present, but which is
not being output at this point. */
void (* deferred_inline_function) (tree decl);
*************** extern void debug_nothing_tree_tree_tree
*** 200,205 ****
--- 208,217 ----
extern bool debug_true_const_tree (const_tree);
extern void debug_nothing_rtx_insn (rtx_insn *);
extern void debug_nothing_rtx_code_label (rtx_code_label *);
+ extern bool debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *);
+ extern void debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT);
/* Hooks for various debug formats. */
extern const struct gcc_debug_hooks do_nothing_debug_hooks;
Index: trunk/gcc/passes.c
===================================================================
*** trunk.orig/gcc/passes.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/passes.c 2015-08-31 16:03:09.804995090 +0200
*************** rest_of_decl_compilation (tree decl,
*** 318,324 ****
&& !decl_function_context (decl)
&& !current_function_decl
&& DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION
! && !decl_type_context (decl)
/* Avoid confusing the debug information machinery when there are
errors. */
&& !seen_error ())
--- 318,332 ----
&& !decl_function_context (decl)
&& !current_function_decl
&& DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION
! && (!decl_type_context (decl)
! /* If we created a varpool node for the decl make sure to
! call early_global_decl. Otherwise we miss changes
! introduced by member definitions like
! struct A { static int staticdatamember; };
! int A::staticdatamember;
! and thus have incomplete early debug. */
! || (TREE_CODE (decl) == VAR_DECL
! && TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
/* Avoid confusing the debug information machinery when there are
errors. */
&& !seen_error ())
Index: trunk/gcc/cp/semantics.c
===================================================================
*** trunk.orig/gcc/cp/semantics.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/cp/semantics.c 2015-08-31 16:03:09.805995099 +0200
*************** finish_member_declaration (tree decl)
*** 2962,2976 ****
translation units which include the PCH file. */
void
! note_decl_for_pch (tree decl)
{
gcc_assert (pch_file);
/* There's a good chance that we'll have to mangle names at some
point, even if only for emission in debugging information. */
if (VAR_OR_FUNCTION_DECL_P (decl)
&& !processing_template_decl)
mangle_decl (decl);
}
/* Finish processing a complete template declaration. The PARMS are
--- 2962,2982 ----
translation units which include the PCH file. */
void
! note_decl_for_pch (tree)
{
gcc_assert (pch_file);
+ /* ??? This changes debug info with/without PCH as DW_AT_linkage_name
+ attributes are added at different times (early when with PCH
+ or late, via pending assembler names, when without PCH).
+ See g++.dg/pch/system-[12].C. */
+ #if 0
/* There's a good chance that we'll have to mangle names at some
point, even if only for emission in debugging information. */
if (VAR_OR_FUNCTION_DECL_P (decl)
&& !processing_template_decl)
mangle_decl (decl);
+ #endif
}
/* Finish processing a complete template declaration. The PARMS are
Index: trunk/gcc/testsuite/lib/lto.exp
===================================================================
*** trunk.orig/gcc/testsuite/lib/lto.exp 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/testsuite/lib/lto.exp 2015-08-31 16:03:09.806995108 +0200
*************** proc lto_prune_warns { text } {
*** 39,44 ****
--- 39,47 ----
regsub -all "(^|\n)\[ \t\]*\[\(\]file \[^\n\]* value=\[^\n\]*; file \[^\n\]* value=\[^\n\]*\[)\];" $text "" text
regsub -all "(^|\n)\[ \t\]*\[^\n\]* definition taken" $text "" text
+ # Temporary measure against early-debug ld complaints
+ regsub -all "(^|\n)\[^\n\]*: plugin needed to handle lto object\[^\n\]*" $text "" text
+
verbose "lto_prune_warns: exit: $text" 2
return $text
Index: trunk/gcc/testsuite/lib/prune.exp
===================================================================
*** trunk.orig/gcc/testsuite/lib/prune.exp 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/testsuite/lib/prune.exp 2015-08-31 16:03:09.806995108 +0200
*************** proc prune_gcc_output { text } {
*** 68,73 ****
--- 68,76 ----
# Ignore harmless warnings from Xcode 4.0.
regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text
+ # Temporary measure against early-debug ld complaints
+ regsub -all "(^|\n)\[^\n\]*: plugin needed to handle lto object\[^\n\]*" $text "" text
+
#send_user "After:$text\n"
return $text
Index: trunk/gcc/testsuite/lib/gcc-dg.exp
===================================================================
*** trunk.orig/gcc/testsuite/lib/gcc-dg.exp 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/testsuite/lib/gcc-dg.exp 2015-08-31 16:03:09.806995108 +0200
*************** proc gcc-dg-prune { system text } {
*** 346,351 ****
--- 346,354 ----
return "::unsupported::memory full"
}
+ # Temporary measure against early-debug ld complaints
+ regsub -all "(^|\n)\[^\n\]*: plugin needed to handle lto object\[^\n\]*" $text "" text
+
return $text
}
Index: trunk/gcc/lto-cgraph.c
===================================================================
*** trunk.orig/gcc/lto-cgraph.c 2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-cgraph.c 2015-08-31 16:03:09.806995108 +0200
*************** compute_ltrans_boundary (lto_symtab_enco
*** 895,908 ****
add_node_to (encoder, node, true);
lto_set_symtab_encoder_in_partition (encoder, node);
create_references (encoder, node);
- /* For proper debug info, we need to ship the origins, too. */
- if (DECL_ABSTRACT_ORIGIN (node->decl))
- {
- struct cgraph_node *origin_node
- = cgraph_node::get_create (DECL_ABSTRACT_ORIGIN (node->decl));
- origin_node->used_as_abstract_origin = true;
- add_node_to (encoder, origin_node, true);
- }
}
for (lsei = lsei_start_variable_in_partition (in_encoder);
!lsei_end_p (lsei); lsei_next_variable_in_partition (&lsei))
--- 895,900 ----
*************** compute_ltrans_boundary (lto_symtab_enco
*** 914,926 ****
lto_set_symtab_encoder_in_partition (encoder, vnode);
lto_set_symtab_encoder_encode_initializer (encoder, vnode);
create_references (encoder, vnode);
- /* For proper debug info, we need to ship the origins, too. */
- if (DECL_ABSTRACT_ORIGIN (vnode->decl))
- {
- varpool_node *origin_node
- = varpool_node::get (DECL_ABSTRACT_ORIGIN (vnode->decl));
- lto_set_symtab_encoder_in_partition (encoder, origin_node);
- }
}
/* Pickle in also the initializer of all referenced readonly variables
to help folding. Constant pool variables are not shared, so we must
--- 906,911 ----