X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fdwarf2out.c;h=84a5fe72db937aec2087f099e735a6e02d5dad10;hb=5632bff570a3489804e448af25abf1db374c6762;hp=f9304e54327870ce0edb7f0b2381d36d1e485013;hpb=333ae3dccad1aca112dbefe7e014653d232fe18c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index f9304e54327..84a5fe72db9 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1,6 +1,7 @@ /* Output Dwarf2 format symbol table information from GCC. Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by Gary Funck (gary@intrepid.com). Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). Extensively modified by Jason Merrill (jason@cygnus.com). @@ -224,6 +225,8 @@ static GTY(()) section *debug_line_section; static GTY(()) section *debug_loc_section; static GTY(()) section *debug_pubnames_section; static GTY(()) section *debug_pubtypes_section; +static GTY(()) section *debug_dcall_section; +static GTY(()) section *debug_vcall_section; static GTY(()) section *debug_str_section; static GTY(()) section *debug_ranges_section; static GTY(()) section *debug_frame_section; @@ -468,8 +471,6 @@ static void output_cfi (dw_cfi_ref, dw_fde_ref, int); static void output_cfi_directive (dw_cfi_ref); static void output_call_frame_info (int); static void dwarf2out_note_section_used (void); -static void dwarf2out_stack_adjust (rtx, bool); -static void dwarf2out_args_size_adjust (HOST_WIDE_INT, const char *); static void flush_queued_reg_saves (void); static bool clobbers_queued_reg_save (const_rtx); static void dwarf2out_frame_debug_expr (rtx, const char *); @@ -804,7 +805,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) /* Emit the state save. */ emit_cfa_remember = false; - cfi_remember = new_cfi (); + cfi_remember = new_cfi (); cfi_remember->dw_cfi_opc = DW_CFA_remember_state; add_fde_cfi (label, cfi_remember); } @@ -1042,7 +1043,7 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p) if (loc.reg == old_cfa.reg && !loc.indirect) { /* Construct a "DW_CFA_def_cfa_offset " instruction, indicating - the CFA register did not change but the offset did. The data + the CFA register did not change but the offset did. The data factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or in the assembler via the .cfi_def_cfa_offset directive. */ if (loc.offset < 0) @@ -1114,8 +1115,8 @@ reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT && sreg == INVALID_REGNUM) { cfi->dw_cfi_opc = DW_CFA_expression; - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = reg; - cfi->dw_cfi_oprnd1.dw_cfi_loc + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + cfi->dw_cfi_oprnd2.dw_cfi_loc = build_cfa_aligned_loc (offset, fde->stack_realignment); } else if (sreg == INVALID_REGNUM) @@ -1155,25 +1156,6 @@ dwarf2out_window_save (const char *label) add_fde_cfi (label, cfi); } -/* Add a CFI to update the running total of the size of arguments - pushed onto the stack. */ - -void -dwarf2out_args_size (const char *label, HOST_WIDE_INT size) -{ - dw_cfi_ref cfi; - - if (size == old_args_size) - return; - - old_args_size = size; - - cfi = new_cfi (); - cfi->dw_cfi_opc = DW_CFA_GNU_args_size; - cfi->dw_cfi_oprnd1.dw_cfi_offset = size; - add_fde_cfi (label, cfi); -} - /* Entry point for saving a register to the stack. REG is the GCC register number. LABEL and OFFSET are passed to reg_save. */ @@ -1524,13 +1506,58 @@ compute_barrier_args_size (void) VEC_free (rtx, heap, next); } +/* Add a CFI to update the running total of the size of arguments + pushed onto the stack. */ + +static void +dwarf2out_args_size (const char *label, HOST_WIDE_INT size) +{ + dw_cfi_ref cfi; + + if (size == old_args_size) + return; + + old_args_size = size; + + cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_GNU_args_size; + cfi->dw_cfi_oprnd1.dw_cfi_offset = size; + add_fde_cfi (label, cfi); +} + +/* Record a stack adjustment of OFFSET bytes. */ + +static void +dwarf2out_stack_adjust (HOST_WIDE_INT offset, const char *label) +{ + if (cfa.reg == STACK_POINTER_REGNUM) + cfa.offset += offset; + + if (cfa_store.reg == STACK_POINTER_REGNUM) + cfa_store.offset += offset; + + if (ACCUMULATE_OUTGOING_ARGS) + return; + +#ifndef STACK_GROWS_DOWNWARD + offset = -offset; +#endif + + args_size += offset; + if (args_size < 0) + args_size = 0; + + def_cfa_1 (label, &cfa); + if (flag_asynchronous_unwind_tables) + dwarf2out_args_size (label, args_size); +} /* Check INSN to see if it looks like a push or a stack adjustment, and - make a note of it if it does. EH uses this information to find out how - much extra space it needs to pop off the stack. */ + make a note of it if it does. EH uses this information to find out + how much extra space it needs to pop off the stack. */ static void -dwarf2out_stack_adjust (rtx insn, bool after_p) +dwarf2out_notice_stack_adjust (rtx insn, bool after_p) { HOST_WIDE_INT offset; const char *label; @@ -1614,31 +1641,7 @@ dwarf2out_stack_adjust (rtx insn, bool after_p) return; label = dwarf2out_cfi_label (false); - dwarf2out_args_size_adjust (offset, label); -} - -/* Adjust args_size based on stack adjustment OFFSET. */ - -static void -dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label) -{ - if (cfa.reg == STACK_POINTER_REGNUM) - cfa.offset += offset; - - if (cfa_store.reg == STACK_POINTER_REGNUM) - cfa_store.offset += offset; - -#ifndef STACK_GROWS_DOWNWARD - offset = -offset; -#endif - - args_size += offset; - if (args_size < 0) - args_size = 0; - - def_cfa_1 (label, &cfa); - if (flag_asynchronous_unwind_tables) - dwarf2out_args_size (label, args_size); + dwarf2out_stack_adjust (offset, label); } #endif @@ -1883,7 +1886,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label) addr = XEXP (set, 0); gcc_assert (MEM_P (addr)); addr = XEXP (addr, 0); - + /* As documented, only consider extremely simple addresses. */ switch (GET_CODE (addr)) { @@ -2157,15 +2160,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label) && cfa.indirect == 0 && cfa.reg != HARD_FRAME_POINTER_REGNUM effects: Use DW_CFA_def_cfa_expression to define cfa - cfa.reg == fde->drap_reg - - Rule 20: - (set reg fde->drap_reg) - constraints: fde->vdrap_reg == INVALID_REGNUM - effects: fde->vdrap_reg = reg. - (set mem fde->drap_reg) - constraints: fde->drap_reg_saved == 1 - effects: none. */ + cfa.reg == fde->drap_reg */ static void dwarf2out_frame_debug_expr (rtx expr, const char *label) @@ -2216,7 +2211,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0); if (offset != 0) - dwarf2out_args_size_adjust (offset, label); + dwarf2out_stack_adjust (offset, label); } } return; @@ -2236,24 +2231,6 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) fde = current_fde (); - if (REG_P (src) - && fde - && fde->drap_reg == REGNO (src) - && (fde->drap_reg_saved - || REG_P (dest))) - { - /* Rule 20 */ - /* If we are saving dynamic realign argument pointer to a - register, the destination is virtual dynamic realign - argument pointer. It may be used to access argument. */ - if (REG_P (dest)) - { - gcc_assert (fde->vdrap_reg == INVALID_REGNUM); - fde->vdrap_reg = REGNO (dest); - } - return; - } - switch (GET_CODE (dest)) { case REG: @@ -2709,10 +2686,13 @@ dwarf2out_frame_debug (rtx insn, bool after_p) if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)) flush_queued_reg_saves (); - if (! RTX_FRAME_RELATED_P (insn)) + if (!RTX_FRAME_RELATED_P (insn)) { + /* ??? This should be done unconditionally since stack adjustments + matter if the stack pointer is not the CFA register anymore but + is still used to save registers. */ if (!ACCUMULATE_OUTGOING_ARGS) - dwarf2out_stack_adjust (insn, after_p); + dwarf2out_notice_stack_adjust (insn, after_p); return; } @@ -2775,6 +2755,21 @@ dwarf2out_frame_debug (rtx insn, bool after_p) handled_one = true; break; + case REG_CFA_SET_VDRAP: + n = XEXP (note, 0); + if (REG_P (n)) + { + dw_fde_ref fde = current_fde (); + if (fde) + { + gcc_assert (fde->vdrap_reg == INVALID_REGNUM); + if (REG_P (n)) + fde->vdrap_reg = REGNO (n); + } + } + handled_one = true; + break; + default: break; } @@ -2870,7 +2865,7 @@ dwarf2out_begin_epilogue (rtx insn) void dwarf2out_frame_debug_restore_state (void) { - dw_cfi_ref cfi = new_cfi (); + dw_cfi_ref cfi = new_cfi (); const char *label = dwarf2out_cfi_label (false); cfi->dw_cfi_opc = DW_CFA_restore_state; @@ -2916,6 +2911,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) case DW_CFA_same_value: case DW_CFA_def_cfa_register: case DW_CFA_register: + case DW_CFA_expression: return dw_cfi_oprnd_reg_num; case DW_CFA_def_cfa_offset: @@ -2924,7 +2920,6 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) return dw_cfi_oprnd_offset; case DW_CFA_def_cfa_expression: - case DW_CFA_expression: return dw_cfi_oprnd_loc; default: @@ -2951,6 +2946,9 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi) case DW_CFA_register: return dw_cfi_oprnd_reg_num; + case DW_CFA_expression: + return dw_cfi_oprnd_loc; + default: return dw_cfi_oprnd_unused; } @@ -5198,10 +5196,14 @@ output_cfa_loc (dw_cfi_ref cfi) unsigned long size; if (cfi->dw_cfi_opc == DW_CFA_expression) - dw2_asm_output_data (1, cfi->dw_cfi_oprnd2.dw_cfi_reg_num, NULL); + { + dw2_asm_output_data (1, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL); + loc = cfi->dw_cfi_oprnd2.dw_cfi_loc; + } + else + loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; /* Output the size of the block. */ - loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; size = size_of_locs (loc); dw2_asm_output_data_uleb128 (size, NULL); @@ -5218,10 +5220,14 @@ output_cfa_loc_raw (dw_cfi_ref cfi) unsigned long size; if (cfi->dw_cfi_opc == DW_CFA_expression) - fprintf (asm_out_file, "0x%x,", cfi->dw_cfi_oprnd2.dw_cfi_reg_num); + { + fprintf (asm_out_file, "0x%x,", cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + loc = cfi->dw_cfi_oprnd2.dw_cfi_loc; + } + else + loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; /* Output the size of the block. */ - loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; size = size_of_locs (loc); dw2_asm_output_data_uleb128_raw (size); fputc (',', asm_out_file); @@ -5399,10 +5405,12 @@ static int output_indirect_string (void **, void *); static void dwarf2out_init (const char *); static void dwarf2out_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_start_source_file (unsigned, const char *); static void dwarf2out_end_source_file (unsigned); +static void dwarf2out_function_decl (tree); static void dwarf2out_begin_block (unsigned, unsigned); static void dwarf2out_end_block (unsigned, unsigned); static bool dwarf2out_ignore_block (const_tree); @@ -5413,6 +5421,10 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, dw_die_ref); static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx); +static void dwarf2out_direct_call (tree); +static void dwarf2out_virtual_call_token (tree, int); +static void dwarf2out_copy_call_info (rtx, rtx); +static void dwarf2out_virtual_call (int); static void dwarf2out_begin_function (tree); static void dwarf2out_set_name (tree, tree); @@ -5422,6 +5434,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { dwarf2out_init, dwarf2out_finish, + dwarf2out_assembly_start, dwarf2out_define, dwarf2out_undef, dwarf2out_start_source_file, @@ -5435,7 +5448,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = dwarf2out_end_epilogue, dwarf2out_begin_function, debug_nothing_int, /* end_function */ - dwarf2out_decl, /* function_decl */ + dwarf2out_function_decl, /* function_decl */ dwarf2out_global_decl, dwarf2out_type_decl, /* type_decl */ dwarf2out_imported_module_or_decl, @@ -5448,6 +5461,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_int, /* handle_pch */ dwarf2out_var_location, dwarf2out_switch_text_section, + dwarf2out_direct_call, + dwarf2out_virtual_call_token, + dwarf2out_copy_call_info, + dwarf2out_virtual_call, dwarf2out_set_name, 1 /* start_end_main_source_file */ }; @@ -5715,7 +5732,6 @@ DEF_VEC_ALLOC_O(die_arg_entry,gc); struct GTY ((chain_next ("%h.next"))) var_loc_node { rtx GTY (()) var_loc_note; const char * GTY (()) label; - const char * GTY (()) section_label; struct var_loc_node * GTY (()) next; }; @@ -5828,6 +5844,45 @@ static GTY(()) bool have_location_lists; /* Unique label counter. */ static GTY(()) unsigned int loclabel_num; +/* Unique label counter for point-of-call tables. */ +static GTY(()) unsigned int poc_label_num; + +/* The direct call table structure. */ + +typedef struct GTY(()) dcall_struct { + unsigned int poc_label_num; + tree poc_decl; + dw_die_ref targ_die; +} +dcall_entry; + +DEF_VEC_O(dcall_entry); +DEF_VEC_ALLOC_O(dcall_entry, gc); + +/* The virtual call table structure. */ + +typedef struct GTY(()) vcall_struct { + unsigned int poc_label_num; + unsigned int vtable_slot; +} +vcall_entry; + +DEF_VEC_O(vcall_entry); +DEF_VEC_ALLOC_O(vcall_entry, gc); + +/* Pointers to the direct and virtual call tables. */ +static GTY (()) VEC (dcall_entry, gc) * dcall_table = NULL; +static GTY (()) VEC (vcall_entry, gc) * vcall_table = NULL; + +/* A hash table to map INSN_UIDs to vtable slot indexes. */ + +struct GTY (()) vcall_insn { + int insn_uid; + unsigned int vtable_slot; +}; + +static GTY ((param_is (struct vcall_insn))) htab_t vcall_insn_table; + #ifdef DWARF2_DEBUGGING_INFO /* Record whether the function being analyzed contains inlined functions. */ static int current_function_has_inlines; @@ -5929,7 +5984,7 @@ static hashval_t decl_loc_table_hash (const void *); static int decl_loc_table_eq (const void *, const void *); static var_loc_list *lookup_decl_loc (const_tree); static void equate_decl_number_to_die (tree, dw_die_ref); -static void add_var_loc_to_decl (tree, struct var_loc_node *); +static struct var_loc_node *add_var_loc_to_decl (tree, rtx); static void print_spaces (FILE *); static void print_die (dw_die_ref, FILE *); static void print_dwarf_line_table (FILE *); @@ -6008,7 +6063,8 @@ static void add_arange (tree, dw_die_ref); static void output_aranges (void); static unsigned int add_ranges_num (int); static unsigned int add_ranges (const_tree); -static unsigned int add_ranges_by_labels (const char *, const char *); +static void add_ranges_by_labels (dw_die_ref, const char *, const char *, + bool *); static void output_ranges (void); static void output_line_info (void); static void output_file_names (void); @@ -6123,10 +6179,7 @@ static void gen_generic_params_dies (tree); static void splice_child_die (dw_die_ref, dw_die_ref); static int file_info_cmp (const void *, const void *); static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, - const char *, const char *, unsigned); -static void add_loc_descr_to_loc_list (dw_loc_list_ref *, dw_loc_descr_ref, - const char *, const char *, - const char *); + const char *, const char *); static void output_loc_list (dw_loc_list_ref); static char *gen_internal_sym (const char *); @@ -6165,6 +6218,12 @@ static void gen_remaining_tmpl_value_param_die_attribute (void); #ifndef DEBUG_PUBTYPES_SECTION #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" #endif +#ifndef DEBUG_DCALL_SECTION +#define DEBUG_DCALL_SECTION ".debug_dcall" +#endif +#ifndef DEBUG_VCALL_SECTION +#define DEBUG_VCALL_SECTION ".debug_vcall" +#endif #ifndef DEBUG_STR_SECTION #define DEBUG_STR_SECTION ".debug_str" #endif @@ -6425,6 +6484,10 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_shared_type"; case DW_TAG_type_unit: return "DW_TAG_type_unit"; + case DW_TAG_rvalue_reference_type: + return "DW_TAG_rvalue_reference_type"; + case DW_TAG_template_alias: + return "DW_TAG_template_alias"; case DW_TAG_GNU_template_parameter_pack: return "DW_TAG_GNU_template_parameter_pack"; case DW_TAG_GNU_formal_parameter_pack: @@ -6609,6 +6672,16 @@ dwarf_attr_name (unsigned int attr) case DW_AT_signature: return "DW_AT_signature"; + case DW_AT_main_subprogram: + return "DW_AT_main_subprogram"; + case DW_AT_data_bit_offset: + return "DW_AT_data_bit_offset"; + case DW_AT_const_expr: + return "DW_AT_const_expr"; + case DW_AT_enum_class: + return "DW_AT_enum_class"; + case DW_AT_linkage_name: + return "DW_AT_linkage_name"; case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; @@ -6647,6 +6720,22 @@ dwarf_attr_name (unsigned int attr) return "DW_AT_body_end"; case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; + case DW_AT_GNU_guarded_by: + return "DW_AT_GNU_guarded_by"; + case DW_AT_GNU_pt_guarded_by: + return "DW_AT_GNU_pt_guarded_by"; + case DW_AT_GNU_guarded: + return "DW_AT_GNU_guarded"; + case DW_AT_GNU_pt_guarded: + return "DW_AT_GNU_pt_guarded"; + case DW_AT_GNU_locks_excluded: + return "DW_AT_GNU_locks_excluded"; + case DW_AT_GNU_exclusive_locks_required: + return "DW_AT_GNU_exclusive_locks_required"; + case DW_AT_GNU_shared_locks_required: + return "DW_AT_GNU_shared_locks_required"; + case DW_AT_GNU_odr_signature: + return "DW_AT_GNU_odr_signature"; case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; @@ -6707,6 +6796,14 @@ dwarf_form_name (unsigned int form) return "DW_FORM_ref_udata"; case DW_FORM_indirect: return "DW_FORM_indirect"; + case DW_FORM_sec_offset: + return "DW_FORM_sec_offset"; + case DW_FORM_exprloc: + return "DW_FORM_exprloc"; + case DW_FORM_flag_present: + return "DW_FORM_flag_present"; + case DW_FORM_ref_sig8: + return "DW_FORM_ref_sig8"; default: return "DW_FORM_"; } @@ -7116,6 +7213,13 @@ AT_loc_list (dw_attr_ref a) return a->dw_attr_val.v.val_loc_list; } +static inline dw_loc_list_ref * +AT_loc_list_ptr (dw_attr_ref a) +{ + gcc_assert (a && AT_class (a) == dw_val_class_loc_list); + return &a->dw_attr_val.v.val_loc_list; +} + /* Add an address constant attribute value to a DIE. */ static inline void @@ -7659,12 +7763,13 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die) /* Add a variable location node to the linked list for DECL. */ -static void -add_var_loc_to_decl (tree decl, struct var_loc_node *loc) +static struct var_loc_node * +add_var_loc_to_decl (tree decl, rtx loc_note) { unsigned int decl_id = DECL_UID (decl); var_loc_list *temp; void **slot; + struct var_loc_node *loc = NULL; slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT); if (*slot == NULL) @@ -7682,25 +7787,27 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc) and either both or neither of the locations is uninitialized, we have nothing to do. */ if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note), - NOTE_VAR_LOCATION_LOC (loc->var_loc_note))) + NOTE_VAR_LOCATION_LOC (loc_note))) || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note) - != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)) + != NOTE_VAR_LOCATION_STATUS (loc_note)) && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note) == VAR_INIT_STATUS_UNINITIALIZED) - || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note) + || (NOTE_VAR_LOCATION_STATUS (loc_note) == VAR_INIT_STATUS_UNINITIALIZED)))) { /* Add LOC to the end of list and update LAST. */ + loc = GGC_CNEW (struct var_loc_node); temp->last->next = loc; temp->last = loc; } } - /* Do not add empty location to the beginning of the list. */ - else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX) + else { + loc = GGC_CNEW (struct var_loc_node); temp->first = loc; temp->last = loc; } + return loc; } /* Keep track of the number of spaces used to indent the @@ -9512,7 +9619,7 @@ htab_decl_del (void *what) free (entry); } -/* Copy DIE and its ancestors, up to, but not including, the compile unit +/* Copy DIE and its ancestors, up to, but not including, the compile unit or type unit entry, to a new tree. Adds the new tree to UNIT and returns a pointer to the copy of DIE. If DECL_TABLE is provided, it is used to check if the ancestor has already been copied into UNIT. */ @@ -10204,12 +10311,11 @@ output_die_symbol (dw_die_ref die) } /* Return a new location list, given the begin and end range, and the - expression. gensym tells us whether to generate a new internal symbol for - this location list node, which is done for the head of the list only. */ + expression. */ static inline dw_loc_list_ref new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, - const char *section, unsigned int gensym) + const char *section) { dw_loc_list_ref retlist = GGC_CNEW (dw_loc_list_node); @@ -10217,27 +10323,18 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, retlist->end = end; retlist->expr = expr; retlist->section = section; - if (gensym) - retlist->ll_symbol = gen_internal_sym ("LLST"); return retlist; } -/* Add a location description expression to a location list. */ +/* Generate a new internal symbol for this location list node, if it + hasn't got one yet. */ static inline void -add_loc_descr_to_loc_list (dw_loc_list_ref *list_head, dw_loc_descr_ref descr, - const char *begin, const char *end, - const char *section) +gen_llsym (dw_loc_list_ref list) { - dw_loc_list_ref *d; - - /* Find the end of the chain. */ - for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next) - ; - - /* Add a new location list node to the list. */ - *d = new_loc_list (descr, begin, end, section, 0); + gcc_assert (!list->ll_symbol); + list->ll_symbol = gen_internal_sym ("LLST"); } /* Output the location list given to us. */ @@ -10299,7 +10396,7 @@ output_signature (const char *sig, const char *name) int i; for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) - dw2_asm_output_data (1, sig[i], "%s", name); + dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name); } /* Output the DIE and its attributes. Called recursively to generate @@ -10520,7 +10617,7 @@ output_die (dw_die_ref die) for (i = 0; i < 8; i++) dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i], - "%s", name); + i == 0 ? "%s" : NULL, name); break; } @@ -10688,7 +10785,11 @@ static void add_pubname (tree decl, dw_die_ref die) { if (TREE_PUBLIC (decl)) - add_pubname_string (dwarf2_name (decl, 1), die); + { + const char *name = dwarf2_name (decl, 1); + if (name) + add_pubname_string (name, die); + } } /* Add a new entry to .debug_pubtypes if appropriate. */ @@ -10718,7 +10819,11 @@ add_pubtype (tree decl, dw_die_ref die) } } else - e.name = xstrdup (dwarf2_name (decl, 1)); + { + e.name = dwarf2_name (decl, 1); + if (e.name) + e.name = xstrdup (e.name); + } /* If we don't have a name for the type, there's no point in adding it to the table. */ @@ -10922,10 +11027,12 @@ add_ranges (const_tree block) /* Add a new entry to .debug_ranges corresponding to a pair of labels. */ -static unsigned int -add_ranges_by_labels (const char *begin, const char *end) +static void +add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end, + bool *added) { unsigned int in_use = ranges_by_label_in_use; + unsigned int offset; if (in_use == ranges_by_label_allocated) { @@ -10942,7 +11049,12 @@ add_ranges_by_labels (const char *begin, const char *end) ranges_by_label[in_use].end = end; ranges_by_label_in_use = in_use + 1; - return add_ranges_num (-(int)in_use - 1); + offset = add_ranges_num (-(int)in_use - 1); + if (!*added) + { + add_AT_range_list (die, DW_AT_ranges, offset); + *added = true; + } } static void @@ -11160,7 +11272,6 @@ output_file_names (void) int ndirs; int idx_offset; int i; - int idx; if (!last_emitted_file) { @@ -11287,7 +11398,6 @@ output_file_names (void) } /* Emit the directory name table. */ - idx = 1; idx_offset = dirs[0].length > 0 ? 1 : 0; for (i = 1 - idx_offset; i < ndirs; i++) dw2_asm_output_nstring (dirs[i].path, @@ -11684,6 +11794,129 @@ output_line_info (void) /* Output the marker for the end of the line number info. */ ASM_OUTPUT_LABEL (asm_out_file, l2); } + +/* Return the size of the .debug_dcall table for the compilation unit. */ + +static unsigned long +size_of_dcall_table (void) +{ + unsigned long size; + unsigned int i; + dcall_entry *p; + tree last_poc_decl = NULL; + + /* Header: version + debug info section pointer + pointer size. */ + size = 2 + DWARF_OFFSET_SIZE + 1; + + /* Each entry: code label + DIE offset. */ + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++) + { + gcc_assert (p->targ_die != NULL); + /* Insert a "from" entry when the point-of-call DIE offset changes. */ + if (p->poc_decl != last_poc_decl) + { + dw_die_ref poc_die = lookup_decl_die (p->poc_decl); + gcc_assert (poc_die); + last_poc_decl = p->poc_decl; + if (poc_die) + size += (DWARF_OFFSET_SIZE + + size_of_uleb128 (poc_die->die_offset)); + } + size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->targ_die->die_offset); + } + + return size; +} + +/* Output the direct call table used to disambiguate PC values when + identical function have been merged. */ + +static void +output_dcall_table (void) +{ + unsigned i; + unsigned long dcall_length = size_of_dcall_table (); + dcall_entry *p; + char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; + tree last_poc_decl = NULL; + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, dcall_length, + "Length of Direct Call Table"); + dw2_asm_output_data (2, 4, "Version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++) + { + /* Insert a "from" entry when the point-of-call DIE offset changes. */ + if (p->poc_decl != last_poc_decl) + { + dw_die_ref poc_die = lookup_decl_die (p->poc_decl); + last_poc_decl = p->poc_decl; + if (poc_die) + { + dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "New caller"); + dw2_asm_output_data_uleb128 (poc_die->die_offset, + "Caller DIE offset"); + } + } + ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); + dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); + dw2_asm_output_data_uleb128 (p->targ_die->die_offset, + "Callee DIE offset"); + } +} + +/* Return the size of the .debug_vcall table for the compilation unit. */ + +static unsigned long +size_of_vcall_table (void) +{ + unsigned long size; + unsigned int i; + vcall_entry *p; + + /* Header: version + pointer size. */ + size = 2 + 1; + + /* Each entry: code label + vtable slot index. */ + for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++) + size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->vtable_slot); + + return size; +} + +/* Output the virtual call table used to disambiguate PC values when + identical function have been merged. */ + +static void +output_vcall_table (void) +{ + unsigned i; + unsigned long vcall_length = size_of_vcall_table (); + vcall_entry *p; + char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, vcall_length, + "Length of Virtual Call Table"); + dw2_asm_output_data (2, 4, "Version number"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++) + { + ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); + dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); + dw2_asm_output_data_uleb128 (p->vtable_slot, "Vtable slot"); + } +} /* Given a pointer to a tree node for some base type, return a pointer to a DIE that describes the given type. @@ -11934,6 +12167,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, add_AT_unsigned (mod_type_die, DW_AT_byte_size, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type))) + add_AT_unsigned (mod_type_die, DW_AT_address_class, + TYPE_ADDR_SPACE (item_type)); } else if (code == REFERENCE_TYPE) { @@ -11941,6 +12177,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, add_AT_unsigned (mod_type_die, DW_AT_byte_size, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type))) + add_AT_unsigned (mod_type_die, DW_AT_address_class, + TYPE_ADDR_SPACE (item_type)); } else if (code == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE @@ -12143,7 +12382,8 @@ generic_parameter_die (tree parm, tree arg, /* The DW_AT_GNU_template_name attribute of the DIE must be set to the name of the argument. */ name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1); - add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); + if (name) + add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); } if (TREE_CODE (parm) == PARM_DECL) @@ -12177,13 +12417,10 @@ template_parameter_pack_die (tree parm_pack, dw_die_ref die; int j; - gcc_assert (parent_die - && parm_pack - && DECL_NAME (parm_pack)); + gcc_assert (parent_die && parm_pack); die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack); - add_AT_string (die, DW_AT_name, IDENTIFIER_POINTER (DECL_NAME (parm_pack))); - + add_name_and_src_coords_attributes (die, parm_pack); for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++) generic_parameter_die (parm_pack, TREE_VEC_ELT (parm_pack_args, j), @@ -12499,13 +12736,17 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset, return new_loc_descr (DW_OP_fbreg, offset, 0); } } - else if (fde - && fde->drap_reg != INVALID_REGNUM + else if (!optimize + && fde && (fde->drap_reg == REGNO (reg) || fde->vdrap_reg == REGNO (reg))) { /* Use cfa+offset to represent the location of arguments passed - on stack when drap is used to align stack. */ + on the stack when drap is used to align stack. + Only do this when not optimizing, for optimized code var-tracking + is supposed to track where the arguments live and the register + used as vdrap or drap in some spot might be used for something + else in other part of the routine. */ return new_loc_descr (DW_OP_fbreg, offset, 0); } @@ -12589,6 +12830,22 @@ const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED) { rtx rtl = *rtlp; + if (GET_CODE (rtl) == UNSPEC) + { + /* If delegitimize_address couldn't do anything with the UNSPEC, assume + we can't express it in the debug info. */ +#ifdef ENABLE_CHECKING + inform (current_function_decl + ? DECL_SOURCE_LOCATION (current_function_decl) + : UNKNOWN_LOCATION, + "non-delegitimized UNSPEC %d found in variable location", + XINT (rtl, 1)); +#endif + expansion_failed (NULL_TREE, rtl, + "UNSPEC hasn't been delegitimized.\n"); + return 1; + } + if (GET_CODE (rtl) != SYMBOL_REF) return 0; @@ -12683,10 +12940,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case POST_INC: case POST_DEC: case POST_MODIFY: - /* POST_INC and POST_DEC can be handled just like a SUBREG. So we - just fall into the SUBREG code. */ - - /* ... fall through ... */ + return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized); case SUBREG: /* The case of a subreg may arise when we have a local (register) @@ -12694,9 +12948,13 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - rtl = XEXP (rtl, 0); + if (!subreg_lowpart_p (rtl)) + break; + rtl = SUBREG_REG (rtl); if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE) break; + if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT) + break; mem_loc_result = mem_loc_descriptor (rtl, mode, initialized); break; @@ -12757,7 +13015,25 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (mem_loc_result == NULL) mem_loc_result = tls_mem_loc_descriptor (rtl); if (mem_loc_result != 0) - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); + { + if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE) + { + expansion_failed (NULL_TREE, rtl, "DWARF address size mismatch"); + return 0; + } + else if (GET_MODE_SIZE (GET_MODE (rtl)) == DWARF2_ADDR_SIZE) + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); + else + add_loc_descr (&mem_loc_result, + new_loc_descr (DW_OP_deref_size, + GET_MODE_SIZE (GET_MODE (rtl)), 0)); + } + else + { + rtx new_rtl = avoid_constant_pool_reference (rtl); + if (new_rtl != rtl) + return mem_loc_descriptor (new_rtl, mode, initialized); + } break; case LO_SUM: @@ -12771,34 +13047,6 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, pool. */ case CONST: case SYMBOL_REF: - /* Alternatively, the symbol in the constant pool might be referenced - by a different symbol. */ - if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl)) - { - bool marked; - rtx tmp = get_pool_constant_mark (rtl, &marked); - - if (GET_CODE (tmp) == SYMBOL_REF) - { - rtl = tmp; - if (CONSTANT_POOL_ADDRESS_P (tmp)) - get_pool_constant_mark (tmp, &marked); - else - marked = true; - } - - /* If all references to this pool constant were optimized away, - it was not output and thus we can't represent it. - FIXME: might try to use DW_OP_const_value here, though - DW_OP_piece complicates it. */ - if (!marked) - { - expansion_failed (NULL_TREE, rtl, - "Constant was removed from constant pool.\n"); - return 0; - } - } - if (GET_CODE (rtl) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE) { @@ -12896,7 +13144,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, op = DW_OP_div; goto do_binop; - case MOD: + case UMOD: op = DW_OP_mod; goto do_binop; @@ -12938,6 +13186,24 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); break; + case MOD: + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + VAR_INIT_STATUS_INITIALIZED); + + if (op0 == 0 || op1 == 0) + break; + + mem_loc_result = op0; + add_loc_descr (&mem_loc_result, op1); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0)); + break; + case NOT: op = DW_OP_not; goto do_unop; @@ -12990,32 +13256,72 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_scompare; do_scompare: - if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT - || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE - || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1))) + if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE + || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE) break; + else + { + enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0)); - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, - VAR_INIT_STATUS_INITIALIZED); + if (op_mode == VOIDmode) + op_mode = GET_MODE (XEXP (rtl, 1)); + if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT) + break; - if (op0 == 0 || op1 == 0) - break; + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + VAR_INIT_STATUS_INITIALIZED); - if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE) - { - int shift = DWARF2_ADDR_SIZE - - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))); - shift *= BITS_PER_UNIT; - add_loc_descr (&op0, int_loc_descriptor (shift)); - add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0)); - if (CONST_INT_P (XEXP (rtl, 1))) - op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift); - else + if (op0 == 0 || op1 == 0) + break; + + if (op_mode != VOIDmode + && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE) { - add_loc_descr (&op1, int_loc_descriptor (shift)); - add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); + int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode); + shift *= BITS_PER_UNIT; + /* For eq/ne, if the operands are known to be zero-extended, + there is no need to do the fancy shifting up. */ + if (op == DW_OP_eq || op == DW_OP_ne) + { + dw_loc_descr_ref last0, last1; + for (last0 = op0; + last0->dw_loc_next != NULL; + last0 = last0->dw_loc_next) + ; + for (last1 = op1; + last1->dw_loc_next != NULL; + last1 = last1->dw_loc_next) + ; + /* deref_size zero extends, and for constants we can check + whether they are zero extended or not. */ + if (((last0->dw_loc_opc == DW_OP_deref_size + && last0->dw_loc_oprnd1.v.val_int + <= GET_MODE_SIZE (op_mode)) + || (CONST_INT_P (XEXP (rtl, 0)) + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0)) + == (INTVAL (XEXP (rtl, 0)) + & GET_MODE_MASK (op_mode)))) + && ((last1->dw_loc_opc == DW_OP_deref_size + && last1->dw_loc_oprnd1.v.val_int + <= GET_MODE_SIZE (op_mode)) + || (CONST_INT_P (XEXP (rtl, 1)) + && (unsigned HOST_WIDE_INT) + INTVAL (XEXP (rtl, 1)) + == (INTVAL (XEXP (rtl, 1)) + & GET_MODE_MASK (op_mode))))) + goto do_compare; + } + add_loc_descr (&op0, int_loc_descriptor (shift)); + add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0)); + if (CONST_INT_P (XEXP (rtl, 1))) + op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift); + else + { + add_loc_descr (&op1, int_loc_descriptor (shift)); + add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); + } } } @@ -13048,42 +13354,72 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_ucompare; do_ucompare: - if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT - || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE - || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1))) + if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE + || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE) break; + else + { + enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0)); - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, - VAR_INIT_STATUS_INITIALIZED); + if (op_mode == VOIDmode) + op_mode = GET_MODE (XEXP (rtl, 1)); + if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT) + break; - if (op0 == 0 || op1 == 0) - break; + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + VAR_INIT_STATUS_INITIALIZED); - if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE) - { - HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0))); - add_loc_descr (&op0, int_loc_descriptor (mask)); - add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0)); - if (CONST_INT_P (XEXP (rtl, 1))) - op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask); - else + if (op0 == 0 || op1 == 0) + break; + + if (op_mode != VOIDmode + && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE) { - add_loc_descr (&op1, int_loc_descriptor (mask)); - add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0)); + HOST_WIDE_INT mask = GET_MODE_MASK (op_mode); + dw_loc_descr_ref last0, last1; + for (last0 = op0; + last0->dw_loc_next != NULL; + last0 = last0->dw_loc_next) + ; + for (last1 = op1; + last1->dw_loc_next != NULL; + last1 = last1->dw_loc_next) + ; + if (CONST_INT_P (XEXP (rtl, 0))) + op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask); + /* deref_size zero extends, so no need to mask it again. */ + else if (last0->dw_loc_opc != DW_OP_deref_size + || last0->dw_loc_oprnd1.v.val_int + > GET_MODE_SIZE (op_mode)) + { + add_loc_descr (&op0, int_loc_descriptor (mask)); + add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0)); + } + if (CONST_INT_P (XEXP (rtl, 1))) + op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask); + /* deref_size zero extends, so no need to mask it again. */ + else if (last1->dw_loc_opc != DW_OP_deref_size + || last1->dw_loc_oprnd1.v.val_int + > GET_MODE_SIZE (op_mode)) + { + add_loc_descr (&op1, int_loc_descriptor (mask)); + add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0)); + } } - } - else - { - HOST_WIDE_INT bias = 1; - bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1); - add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0)); - if (CONST_INT_P (XEXP (rtl, 1))) - op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias - + INTVAL (XEXP (rtl, 1))); else - add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0)); + { + HOST_WIDE_INT bias = 1; + bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1); + add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0)); + if (CONST_INT_P (XEXP (rtl, 1))) + op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias + + INTVAL (XEXP (rtl, 1))); + else + add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, + bias, 0)); + } } goto do_compare; @@ -13181,12 +13517,19 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (BITS_BIG_ENDIAN) shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) - shift - size; - add_loc_descr (&mem_loc_result, - int_loc_descriptor (DWARF2_ADDR_SIZE - shift - size)); - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0)); - add_loc_descr (&mem_loc_result, - int_loc_descriptor (DWARF2_ADDR_SIZE - size)); - add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + if (shift + size != (int) DWARF2_ADDR_SIZE) + { + add_loc_descr (&mem_loc_result, + int_loc_descriptor (DWARF2_ADDR_SIZE + - shift - size)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0)); + } + if (size != (int) DWARF2_ADDR_SIZE) + { + add_loc_descr (&mem_loc_result, + int_loc_descriptor (DWARF2_ADDR_SIZE - size)); + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + } } break; @@ -13202,12 +13545,23 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case US_MULT: case SS_DIV: case US_DIV: + case SS_PLUS: + case US_PLUS: + case SS_MINUS: + case US_MINUS: + case SS_NEG: + case US_NEG: + case SS_ABS: + case SS_ASHIFT: + case US_ASHIFT: + case SS_TRUNCATE: + case US_TRUNCATE: case UDIV: - case UMOD: case UNORDERED: case ORDERED: case UNEQ: case UNGE: + case UNGT: case UNLE: case UNLT: case LTGT: @@ -13229,6 +13583,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case POPCOUNT: case PARITY: case ASM_OPERANDS: + case VEC_MERGE: + case VEC_SELECT: + case VEC_CONCAT: + case VEC_DUPLICATE: case UNSPEC: case HIGH: /* If delegitimize_address couldn't do anything with the UNSPEC, we @@ -13354,6 +13712,12 @@ loc_descriptor (rtx rtl, enum machine_mode mode, initialized); if (loc_result == NULL) loc_result = tls_mem_loc_descriptor (rtl); + if (loc_result == NULL) + { + rtx new_rtl = avoid_constant_pool_reference (rtl); + if (new_rtl != rtl) + loc_result = loc_descriptor (new_rtl, mode, initialized); + } break; case CONCAT: @@ -13367,10 +13731,12 @@ loc_descriptor (rtx rtl, enum machine_mode mode, case VAR_LOCATION: /* Single part. */ - if (GET_CODE (XEXP (rtl, 1)) != PARALLEL) + if (GET_CODE (PAT_VAR_LOCATION_LOC (rtl)) != PARALLEL) { - loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode, - initialized); + rtx loc = PAT_VAR_LOCATION_LOC (rtl); + if (GET_CODE (loc) == EXPR_LIST) + loc = XEXP (loc, 0); + loc_result = loc_descriptor (loc, mode, initialized); break; } @@ -13413,15 +13779,17 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; case CONST_DOUBLE: + if (mode == VOIDmode) + mode = GET_MODE (rtl); + if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict)) { + gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl)); + /* Note that a CONST_DOUBLE rtx could represent either an integer or a floating-point constant. A CONST_DOUBLE is used whenever the constant requires more than one word in order to be adequately represented. We output CONST_DOUBLEs as blocks. */ - if (GET_MODE (rtl) != VOIDmode) - mode = GET_MODE (rtl); - loc_result = new_loc_descr (DW_OP_implicit_value, GET_MODE_SIZE (mode), 0); if (SCALAR_FLOAT_MODE_P (mode)) @@ -13447,6 +13815,9 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; case CONST_VECTOR: + if (mode == VOIDmode) + mode = GET_MODE (rtl); + if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict)) { unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl)); @@ -13455,7 +13826,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, unsigned int i; unsigned char *p; - mode = GET_MODE (rtl); + gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl)); switch (GET_MODE_CLASS (mode)) { case MODE_VECTOR_INT: @@ -13537,10 +13908,10 @@ loc_descriptor (rtx rtl, enum machine_mode mode, if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE && (dwarf_version >= 4 || !dwarf_strict)) { - loc_result = new_loc_descr (DW_OP_implicit_value, - DWARF2_ADDR_SIZE, 0); - loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr; - loc_result->dw_loc_oprnd2.v.val_addr = rtl; + loc_result = new_loc_descr (DW_OP_addr, 0, 0); + loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; + loc_result->dw_loc_oprnd1.v.val_addr = rtl; + add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); VEC_safe_push (rtx, gc, used_rtx_array, rtl); } break; @@ -13602,14 +13973,6 @@ decl_by_reference_p (tree decl) && DECL_BY_REFERENCE (decl)); } -/* Return single element location list containing loc descr REF. */ - -static dw_loc_list_ref -single_element_loc_list (dw_loc_descr_ref ref) -{ - return new_loc_list (ref, NULL, NULL, NULL, 0); -} - /* Helper function for dw_loc_list. Compute proper Dwarf location descriptor for VARLOC. */ @@ -13625,16 +13988,27 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address, { gcc_assert (GET_CODE (varloc) == VAR_LOCATION); /* Single part. */ - if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) + if (GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL) { - varloc = XEXP (XEXP (varloc, 1), 0); + varloc = PAT_VAR_LOCATION_LOC (varloc); + if (GET_CODE (varloc) == EXPR_LIST) + varloc = XEXP (varloc, 0); mode = GET_MODE (varloc); if (MEM_P (varloc)) { - varloc = XEXP (varloc, 0); - have_address = 1; + rtx addr = XEXP (varloc, 0); + descr = mem_loc_descriptor (addr, mode, initialized); + if (descr) + have_address = 1; + else + { + rtx x = avoid_constant_pool_reference (varloc); + if (x != varloc) + descr = mem_loc_descriptor (x, mode, initialized); + } } - descr = mem_loc_descriptor (varloc, mode, initialized); + else + descr = mem_loc_descriptor (varloc, mode, initialized); } else return 0; @@ -13691,20 +14065,21 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address, return descr; } -/* Return dwarf representation of location list representing for - LOC_LIST of DECL. WANT_ADDRESS has the same meaning as in - loc_list_from_tree function. */ +/* Return the dwarf representation of the location list LOC_LIST of + DECL. WANT_ADDRESS has the same meaning as in loc_list_from_tree + function. */ static dw_loc_list_ref -dw_loc_list (var_loc_list * loc_list, tree decl, int want_address) +dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) { const char *endname, *secname; - dw_loc_list_ref list; rtx varloc; enum var_init_status initialized; struct var_loc_node *node; dw_loc_descr_ref descr; char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; + dw_loc_list_ref list = NULL; + dw_loc_list_ref *listp = &list; /* Now that we know what section we are using for a base, actually construct the list of locations. @@ -13717,26 +14092,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, int want_address) This means we have to special case the last node, and generate a range of [last location start, end of function label]. */ - node = loc_list->first; secname = secname_for_decl (decl); - if (NOTE_VAR_LOCATION_LOC (node->var_loc_note)) - initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); - else - initialized = VAR_INIT_STATUS_INITIALIZED; - varloc = NOTE_VAR_LOCATION (node->var_loc_note); - descr = dw_loc_list_1 (decl, varloc, want_address, initialized); - - if (loc_list && loc_list->first != loc_list->last) - list = new_loc_list (descr, node->label, node->next->label, secname, 1); - else - return single_element_loc_list (descr); - node = node->next; - - if (!node) - return NULL; - - for (; node->next; node = node->next) + for (node = loc_list->first; node->next; node = node->next) if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) { /* The variable has a location between NODE->LABEL and @@ -13744,28 +14102,46 @@ dw_loc_list (var_loc_list * loc_list, tree decl, int want_address) initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note); descr = dw_loc_list_1 (decl, varloc, want_address, initialized); - add_loc_descr_to_loc_list (&list, descr, - node->label, node->next->label, secname); + if (descr) + { + *listp = new_loc_list (descr, node->label, node->next->label, + secname); + listp = &(*listp)->dw_loc_next; + } } /* If the variable has a location at the last label it keeps its location until the end of function. */ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) { - if (!current_function_decl) - endname = text_end_label; - else - { - ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, - current_function_funcdef_no); - endname = ggc_strdup (label_id); - } - initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note); descr = dw_loc_list_1 (decl, varloc, want_address, initialized); - add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname); + if (descr) + { + if (!current_function_decl) + endname = text_end_label; + else + { + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, + current_function_funcdef_no); + endname = ggc_strdup (label_id); + } + + *listp = new_loc_list (descr, node->label, endname, secname); + listp = &(*listp)->dw_loc_next; + } } + + /* Try to avoid the overhead of a location list emitting a location + expression instead, but only if we didn't have more than one + location entry in the first place. If some entries were not + representable, we don't want to pretend a single entry that was + applies to the entire scope in which the variable is + available. */ + if (list && loc_list->first->next) + gen_llsym (list); + return list; } @@ -13775,7 +14151,8 @@ dw_loc_list (var_loc_list * loc_list, tree decl, int want_address) static bool single_element_loc_list_p (dw_loc_list_ref list) { - return (!list->dw_loc_next && !list->begin && !list->end); + gcc_assert (!list->dw_loc_next || list->ll_symbol); + return !list->ll_symbol; } /* To each location in list LIST add loc descr REF. */ @@ -13809,7 +14186,7 @@ add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref) TODO: We handle only simple cases of RET or LIST having at most one element. General case would inolve sorting the lists in program order - and merging them that will need some additional work. + and merging them that will need some additional work. Adding that will improve quality of debug info especially for SRA-ed structures. */ @@ -14072,13 +14449,17 @@ loc_list_from_tree (tree loc, int want_address) case RESULT_DECL: case FUNCTION_DECL: { - rtx rtl = rtl_for_decl_location (loc); + rtx rtl; var_loc_list *loc_list = lookup_decl_loc (loc); - if (loc_list && loc_list->first - && (list_ret = dw_loc_list (loc_list, loc, want_address))) - have_address = want_address != 0; - else if (rtl == NULL_RTX) + if (loc_list && loc_list->first) + { + list_ret = dw_loc_list (loc_list, loc, want_address); + have_address = want_address != 0; + break; + } + rtl = rtl_for_decl_location (loc); + if (rtl == NULL_RTX) { expansion_failed (loc, NULL_RTX, "DECL has no RTL"); return 0; @@ -14193,7 +14574,7 @@ loc_list_from_tree (tree loc, int want_address) if (bytepos > 0) add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0)); else if (bytepos < 0) - loc_list_plus_const (list_ret, bytepos); + loc_list_plus_const (list_ret, bytepos); have_address = 1; break; @@ -14252,6 +14633,8 @@ loc_list_from_tree (tree loc, int want_address) case CEIL_DIV_EXPR: case ROUND_DIV_EXPR: case TRUNC_DIV_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (loc))) + return 0; op = DW_OP_div; goto do_binop; @@ -14263,8 +14646,25 @@ loc_list_from_tree (tree loc, int want_address) case CEIL_MOD_EXPR: case ROUND_MOD_EXPR: case TRUNC_MOD_EXPR: - op = DW_OP_mod; - goto do_binop; + if (TYPE_UNSIGNED (TREE_TYPE (loc))) + { + op = DW_OP_mod; + goto do_binop; + } + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0); + if (list_ret == 0 || list_ret1 == 0) + return 0; + + add_loc_list (&list_ret, list_ret1); + if (list_ret == 0) + return 0; + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0)); + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0)); + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_div, 0, 0)); + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_mul, 0, 0)); + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_minus, 0, 0)); + break; case MULT_EXPR: op = DW_OP_mul; @@ -14484,7 +14884,7 @@ loc_list_from_tree (tree loc, int want_address) add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0)); } if (ret) - list_ret = single_element_loc_list (ret); + list_ret = new_loc_list (ret, NULL, NULL, NULL); return list_ret; } @@ -14802,11 +15202,11 @@ add_data_member_location_attribute (dw_die_ref die, tree decl) else { enum dwarf_location_atom op; - + /* The DWARF2 standard says that we should assume that the structure address is already on the stack, so we can specify a structure field address by using DW_OP_plus_uconst. */ - + #ifdef MIPS_DEBUGGING_INFO /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator correctly. It works only if we leave the offset on the @@ -14815,7 +15215,7 @@ add_data_member_location_attribute (dw_die_ref die, tree decl) #else op = DW_OP_plus_uconst; #endif - + loc_descr = new_loc_descr (op, offset, 0); } } @@ -14986,10 +15386,20 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) return true; case CONST_STRING: - resolve_one_addr (&rtl, NULL); - add_AT_addr (die, DW_AT_const_value, rtl); - VEC_safe_push (rtx, gc, used_rtx_array, rtl); - return true; + if (dwarf_version >= 4 || !dwarf_strict) + { + dw_loc_descr_ref loc_result; + resolve_one_addr (&rtl, NULL); + rtl_addr: + loc_result = new_loc_descr (DW_OP_addr, 0, 0); + loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; + loc_result->dw_loc_oprnd1.v.val_addr = rtl; + add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); + add_AT_loc (die, DW_AT_location, loc_result); + VEC_safe_push (rtx, gc, used_rtx_array, rtl); + return true; + } + return false; case CONST: if (CONSTANT_P (XEXP (rtl, 0))) @@ -14999,9 +15409,9 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) if (!const_ok_for_output (rtl)) return false; case LABEL_REF: - add_AT_addr (die, DW_AT_const_value, rtl); - VEC_safe_push (rtx, gc, used_rtx_array, rtl); - return true; + if (dwarf_version >= 4 || !dwarf_strict) + goto rtl_addr; + return false; case PLUS: /* In cases where an inlined instance of an inline function is passed @@ -15368,6 +15778,24 @@ rtl_for_decl_location (tree decl) if (rtl) rtl = avoid_constant_pool_reference (rtl); + /* Try harder to get a rtl. If this symbol ends up not being emitted + in the current CU, resolve_addr will remove the expression referencing + it. */ + if (rtl == NULL_RTX + && TREE_CODE (decl) == VAR_DECL + && !DECL_EXTERNAL (decl) + && TREE_STATIC (decl) + && DECL_NAME (decl) + && !DECL_HARD_REGISTER (decl) + && DECL_MODE (decl) != VOIDmode) + { + rtl = make_decl_rtl_for_debug (decl); + if (!MEM_P (rtl) + || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF + || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl) + rtl = NULL_RTX; + } + return rtl; } @@ -15384,12 +15812,11 @@ fortran_common (tree decl, HOST_WIDE_INT *value) tree offset; int volatilep = 0, unsignedp = 0; - /* If the decl isn't a VAR_DECL, or if it isn't public or static, or if + /* If the decl isn't a VAR_DECL, or if it isn't static, or if it does not have a value (the offset into the common area), or if it is thread local (as opposed to global) then it isn't common, and shouldn't be handled as such. */ if (TREE_CODE (decl) != VAR_DECL - || !TREE_PUBLIC (decl) || !TREE_STATIC (decl) || !DECL_HAS_VALUE_EXPR_P (decl) || !is_fortran ()) @@ -15458,17 +15885,18 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, a constant value. That way we are better to use add_const_value_attribute rather than expanding constant value equivalent. */ loc_list = lookup_decl_loc (decl); - if (loc_list && loc_list->first && loc_list->first == loc_list->last) + if (loc_list + && loc_list->first + && loc_list->first == loc_list->last + && NOTE_VAR_LOCATION (loc_list->first->var_loc_note) + && NOTE_VAR_LOCATION_LOC (loc_list->first->var_loc_note)) { - enum var_init_status status; struct var_loc_node *node; node = loc_list->first; - status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); - rtl = NOTE_VAR_LOCATION (node->var_loc_note); - if (GET_CODE (rtl) == VAR_LOCATION - && GET_CODE (XEXP (rtl, 1)) != PARALLEL) - rtl = XEXP (XEXP (rtl, 1), 0); + rtl = NOTE_VAR_LOCATION_LOC (node->var_loc_note); + if (GET_CODE (rtl) == EXPR_LIST) + rtl = XEXP (rtl, 0); if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING) && add_const_value_attribute (die, rtl)) return true; @@ -15701,6 +16129,10 @@ tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl) else return false; + /* Don't add DW_AT_const_value if abstract origin already has one. */ + if (get_AT (var_die, DW_AT_const_value)) + return false; + return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl)); } @@ -15751,8 +16183,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section, - list == NULL); + start_label, last_label, section); list_tail = &(*list_tail)->dw_loc_next; last_cfa = next_cfa; @@ -15773,14 +16204,16 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section, - list == NULL); + start_label, last_label, section); list_tail = &(*list_tail)->dw_loc_next; start_label = last_label; } + *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset), - start_label, fde->dw_fde_end, section, - list == NULL); + start_label, fde->dw_fde_end, section); + + if (list && list->dw_loc_next) + gen_llsym (list); return list; } @@ -15867,6 +16300,8 @@ add_comp_dir_attribute (dw_die_ref die) static void add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound) { + int want_address = 2; + switch (TREE_CODE (bound)) { case ERROR_MARK: @@ -15916,7 +16351,6 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b case RESULT_DECL: { dw_die_ref decl_die = lookup_decl_die (bound); - dw_loc_list_ref loc; /* ??? Can this happen, or should the variable have been bound first? Probably it can, since I imagine that we try to create @@ -15924,14 +16358,13 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b the list, and won't have created a forward reference to a later parameter. */ if (decl_die != NULL) - add_AT_die_ref (subrange_die, bound_attr, decl_die); - else { - loc = loc_list_from_tree (bound, 0); - add_AT_location_description (subrange_die, bound_attr, loc); + add_AT_die_ref (subrange_die, bound_attr, decl_die); + break; } - break; + want_address = 0; } + /* FALLTHRU */ default: { @@ -15941,10 +16374,16 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b dw_die_ref ctx, decl_die; dw_loc_list_ref list; - list = loc_list_from_tree (bound, 2); + list = loc_list_from_tree (bound, want_address); if (list == NULL) break; + if (single_element_loc_list_p (list)) + { + add_AT_loc (subrange_die, bound_attr, list->expr); + break; + } + if (current_function_decl == 0) ctx = comp_unit_die; else @@ -15953,11 +16392,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b decl_die = new_die (DW_TAG_variable, ctx, bound); add_AT_flag (decl_die, DW_AT_artificial, 1); add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); - if (list->dw_loc_next) - add_AT_loc_list (decl_die, DW_AT_location, list); - else - add_AT_loc (decl_die, DW_AT_location, list->expr); - + add_AT_location_description (decl_die, DW_AT_location, list); add_AT_die_ref (subrange_die, bound_attr, decl_die); break; } @@ -16210,7 +16645,8 @@ add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl) 0)); /* GNU extension: Record what type this method came from originally. */ - if (debug_info_level > DINFO_LEVEL_TERSE) + if (debug_info_level > DINFO_LEVEL_TERSE + && DECL_CONTEXT (func_decl)) add_AT_die_ref (die, DW_AT_containing_type, lookup_type_die (DECL_CONTEXT (func_decl))); } @@ -16238,7 +16674,9 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl) decl_name = DECL_NAME (decl); if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) { - add_name_attribute (die, dwarf2_name (decl, 0)); + const char *name = dwarf2_name (decl, 0); + if (name) + add_name_attribute (die, name); if (! DECL_ARTIFICIAL (decl)) add_src_coords_attributes (die, decl); @@ -16626,7 +17064,7 @@ gen_array_type_die (tree type, dw_die_ref context_die) add_subscript_info (array_die, type, collapse_nested_arrays); /* Add representation of the type of the elements of this array type and - emit the corresponding DIE if we haven't done it already. */ + emit the corresponding DIE if we haven't done it already. */ element_type = TREE_TYPE (type); if (collapse_nested_arrays) while (TREE_CODE (element_type) == ARRAY_TYPE) @@ -16838,7 +17276,9 @@ retry_incomplete_types (void) int i; for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--) - gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die); + if (should_emit_struct_debug (VEC_index (tree, incomplete_types, i), + DINFO_USAGE_DIR_USE)) + gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die); } /* Determine what tag to use for a record type. */ @@ -16958,14 +17398,16 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p, dw_die_ref context_die) { tree node_or_origin = node ? node : origin; + tree ultimate_origin; dw_die_ref parm_die = new_die (DW_TAG_formal_parameter, context_die, node); switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin))) { case tcc_declaration: - if (!origin) - origin = decl_ultimate_origin (node); + ultimate_origin = decl_ultimate_origin (node_or_origin); + if (node || ultimate_origin) + origin = ultimate_origin; if (origin != NULL) add_abstract_origin_attribute (parm_die, origin); else @@ -17027,12 +17469,10 @@ gen_formal_parameter_pack_die (tree parm_pack, gcc_assert (parm_pack && lang_hooks.function_parameter_pack_p (parm_pack) - && DECL_NAME (parm_pack) && subr_die); parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack); - add_AT_string (parm_pack_die, DW_AT_name, - IDENTIFIER_POINTER (DECL_NAME (parm_pack))); + add_src_coords_attributes (parm_pack_die, parm_pack); for (arg = pack_arg; arg; arg = TREE_CHAIN (arg)) { @@ -17130,7 +17570,8 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die) /* If we're trying to avoid duplicate debug info, we may not have emitted the member decl for this function. Emit it now. */ - if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) + if (TYPE_STUB_DECL (type) + && TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) && ! lookup_decl_die (member)) { dw_die_ref type_die; @@ -17168,7 +17609,7 @@ dwarf2out_abstract_function (tree decl) dw_die_ref old_die; tree save_fn; tree context; - int was_abstract = DECL_ABSTRACT (decl); + int was_abstract; htab_t old_decl_loc_table; /* Make sure we have the actual abstract inline, not a clone. */ @@ -17200,6 +17641,7 @@ dwarf2out_abstract_function (tree decl) current_function_decl = decl; push_cfun (DECL_STRUCT_FUNCTION (decl)); + was_abstract = DECL_ABSTRACT (decl); set_decl_abstract_flags (decl, 1); dwarf2out_decl (decl); if (! was_abstract) @@ -17573,7 +18015,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) 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) { @@ -17682,42 +18124,22 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) HOST_WIDE_INT off; tree com_decl; tree decl_or_origin = decl ? decl : origin; + tree ultimate_origin; dw_die_ref var_die; dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL; dw_die_ref origin_die; int declaration = (DECL_EXTERNAL (decl_or_origin) - /* If DECL is COMDAT and has not actually been - emitted, we cannot take its address; there - might end up being no definition anywhere in - the program. For example, consider the C++ - test case: - - template - struct S { static const int i = 7; }; - - template - const int S::i; - - int f() { return S::i; } - - Here, S::i is not DECL_EXTERNAL, but no - definition is required, so the compiler will - not emit a definition. */ - || (TREE_CODE (decl_or_origin) == VAR_DECL - && DECL_COMDAT (decl_or_origin) - && !TREE_ASM_WRITTEN (decl_or_origin)) || class_or_namespace_scope_p (context_die)); - if (!origin) - origin = decl_ultimate_origin (decl); - + ultimate_origin = decl_ultimate_origin (decl_or_origin); + if (decl || ultimate_origin) + origin = ultimate_origin; com_decl = fortran_common (decl_or_origin, &off); /* Symbol in common gets emitted as a child of the common block, in the form of a data member. */ if (com_decl) { - tree field; dw_die_ref com_die; dw_loc_list_ref loc; die_node com_die_arg; @@ -17755,7 +18177,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) = htab_create_ggc (10, common_block_die_table_hash, common_block_die_table_eq, NULL); - field = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0); com_die_arg.decl_id = DECL_UID (com_decl); com_die_arg.die_parent = context_die; com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg); @@ -17819,8 +18240,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) and if we already emitted a DIE for it, don't emit a second DIE for it again. */ if (old_die - && declaration - && old_die->die_parent == context_die) + && declaration) return; /* For static data members, the declaration in the class is supposed @@ -18759,10 +19179,6 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die) { dw_die_ref die; tree decl_or_origin = decl ? decl : origin; - tree ultimate_origin = origin ? decl_ultimate_origin (origin) : NULL; - - if (ultimate_origin) - origin = ultimate_origin; if (TREE_CODE (decl_or_origin) == FUNCTION_DECL) die = lookup_decl_die (decl_or_origin); @@ -18845,7 +19261,7 @@ get_context_die (tree context) { /* Find die that represents this context. */ if (TYPE_P (context)) - return force_type_die (context); + return force_type_die (TYPE_MAIN_VARIANT (context)); else return force_decl_die (context); } @@ -18998,7 +19414,11 @@ gen_namespace_die (tree decl, dw_die_ref context_die) context_die, decl); /* For Fortran modules defined in different CU don't add src coords. */ if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl)) - add_name_attribute (namespace_die, dwarf2_name (decl, 0)); + { + const char *name = dwarf2_name (decl, 0); + if (name) + add_name_attribute (namespace_die, name); + } else add_name_and_src_coords_attributes (namespace_die, decl); if (DECL_EXTERNAL (decl)) @@ -19030,7 +19450,7 @@ static void gen_decl_die (tree decl, tree origin, dw_die_ref context_die) { tree decl_or_origin = decl ? decl : origin; - tree class_origin = NULL; + tree class_origin = NULL, ultimate_origin; if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin)) return; @@ -19076,7 +19496,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) /* If we're emitting a clone, emit info for the abstract instance. */ if (origin || DECL_ORIGIN (decl) != decl) - dwarf2out_abstract_function (origin ? origin : DECL_ABSTRACT_ORIGIN (decl)); + dwarf2out_abstract_function (origin + ? DECL_ORIGIN (origin) + : DECL_ABSTRACT_ORIGIN (decl)); /* 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. */ @@ -19175,9 +19597,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) complicated because of the possibility that the VAR_DECL really represents an inlined instance of a formal parameter for an inline function. */ - if (!origin) - origin = decl_ultimate_origin (decl); - if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL) + ultimate_origin = decl_ultimate_origin (decl_or_origin); + if (ultimate_origin != NULL_TREE + && TREE_CODE (ultimate_origin) == PARM_DECL) gen_formal_parameter_die (decl, origin, true /* Emit name attribute. */, context_die); @@ -19503,6 +19925,16 @@ dwarf2out_decl (tree decl) gen_decl_die (decl, NULL, context_die); } +/* Write the debugging output for DECL. */ + +static void +dwarf2out_function_decl (tree decl) +{ + dwarf2out_decl (decl); + + htab_empty (decl_loc_table); +} + /* Output a marker (i.e. a label) for the beginning of the generated code for a lexical block. */ @@ -19680,29 +20112,163 @@ gen_remaining_tmpl_value_param_die_attribute (void) /* Replace DW_AT_name for the decl with name. */ - + static void dwarf2out_set_name (tree decl, tree name) { dw_die_ref die; dw_attr_ref attr; + const char *dname; die = TYPE_SYMTAB_DIE (decl); if (!die) return; + dname = dwarf2_name (name, 0); + if (!dname) + return; + attr = get_AT (die, DW_AT_name); if (attr) { struct indirect_string_node *node; - node = find_AT_string (dwarf2_name (name, 0)); + node = find_AT_string (dname); /* replace the string. */ attr->dw_attr_val.v.val_str = node; } else - add_name_attribute (die, dwarf2_name (name, 0)); + add_name_attribute (die, dname); +} + +/* Called by the final INSN scan whenever we see a direct function call. + Make an entry into the direct call table, recording the point of call + and a reference to the target function's debug entry. */ + +static void +dwarf2out_direct_call (tree targ) +{ + dcall_entry e; + tree origin = decl_ultimate_origin (targ); + + /* If this is a clone, use the abstract origin as the target. */ + if (origin) + targ = origin; + + e.poc_label_num = poc_label_num++; + e.poc_decl = current_function_decl; + e.targ_die = force_decl_die (targ); + VEC_safe_push (dcall_entry, gc, dcall_table, &e); + + /* Drop a label at the return point to mark the point of call. */ + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); +} + +/* Returns a hash value for X (which really is a struct vcall_insn). */ + +static hashval_t +vcall_insn_table_hash (const void *x) +{ + return (hashval_t) ((const struct vcall_insn *) x)->insn_uid; +} + +/* Return nonzero if insn_uid of struct vcall_insn *X is the same as + insnd_uid of *Y. */ + +static int +vcall_insn_table_eq (const void *x, const void *y) +{ + return (((const struct vcall_insn *) x)->insn_uid + == ((const struct vcall_insn *) y)->insn_uid); +} + +/* Associate VTABLE_SLOT with INSN_UID in the VCALL_INSN_TABLE. */ + +static void +store_vcall_insn (unsigned int vtable_slot, int insn_uid) +{ + struct vcall_insn *item = GGC_NEW (struct vcall_insn); + struct vcall_insn **slot; + + gcc_assert (item); + item->insn_uid = insn_uid; + item->vtable_slot = vtable_slot; + slot = (struct vcall_insn **) + htab_find_slot_with_hash (vcall_insn_table, &item, + (hashval_t) insn_uid, INSERT); + *slot = item; +} + +/* Return the VTABLE_SLOT associated with INSN_UID. */ + +static unsigned int +lookup_vcall_insn (unsigned int insn_uid) +{ + struct vcall_insn item; + struct vcall_insn *p; + + item.insn_uid = insn_uid; + item.vtable_slot = 0; + p = (struct vcall_insn *) htab_find_with_hash (vcall_insn_table, + (void *) &item, + (hashval_t) insn_uid); + if (p == NULL) + return (unsigned int) -1; + return p->vtable_slot; +} + + +/* Called when lowering indirect calls to RTL. We make a note of INSN_UID + and the OBJ_TYPE_REF_TOKEN from ADDR. For C++ virtual calls, the token + is the vtable slot index that we will need to put in the virtual call + table later. */ + +static void +dwarf2out_virtual_call_token (tree addr, int insn_uid) +{ + if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF) + { + tree token = OBJ_TYPE_REF_TOKEN (addr); + if (TREE_CODE (token) == INTEGER_CST) + store_vcall_insn (TREE_INT_CST_LOW (token), insn_uid); + } +} + +/* Called when scheduling RTL, when a CALL_INSN is split. Copies the + OBJ_TYPE_REF_TOKEN previously associated with OLD_INSN and associates it + with NEW_INSN. */ + +static void +dwarf2out_copy_call_info (rtx old_insn, rtx new_insn) +{ + unsigned int vtable_slot = lookup_vcall_insn (INSN_UID (old_insn)); + + if (vtable_slot != (unsigned int) -1) + store_vcall_insn (vtable_slot, INSN_UID (new_insn)); +} + +/* Called by the final INSN scan whenever we see a virtual function call. + Make an entry into the virtual call table, recording the point of call + and the slot index of the vtable entry used to call the virtual member + function. The slot index was associated with the INSN_UID during the + lowering to RTL. */ + +static void +dwarf2out_virtual_call (int insn_uid) +{ + unsigned int vtable_slot = lookup_vcall_insn (insn_uid); + vcall_entry e; + + if (vtable_slot == (unsigned int) -1) + return; + + e.poc_label_num = poc_label_num++; + e.vtable_slot = vtable_slot; + VEC_safe_push (vcall_entry, gc, vcall_table, &e); + + /* Drop a label at the return point to mark the point of call. */ + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); } /* Called by the final INSN scan whenever we see a var location. We @@ -19729,7 +20295,11 @@ dwarf2out_var_location (rtx loc_note) if (next_real == NULL_RTX) return; - newloc = GGC_CNEW (struct var_loc_node); + decl = NOTE_VAR_LOCATION_DECL (loc_note); + newloc = add_var_loc_to_decl (decl, loc_note); + if (newloc == NULL) + return; + /* If there were no real insns between note we processed last time and this note, use the label we emitted last time. */ if (last_var_location_insn == NULL_RTX @@ -19740,8 +20310,7 @@ dwarf2out_var_location (rtx loc_note) ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num); loclabel_num++; last_label = ggc_strdup (loclabel); - if (!NOTE_DURING_CALL_P (loc_note)) - last_postcall_label = NULL; + last_postcall_label = NULL; } newloc->var_loc_note = loc_note; newloc->next = NULL; @@ -19758,15 +20327,8 @@ dwarf2out_var_location (rtx loc_note) newloc->label = last_postcall_label; } - if (cfun && in_cold_section_p) - newloc->section_label = crtl->subsections.cold_section_label; - else - newloc->section_label = text_section_label; - last_var_location_insn = next_real; last_in_cold_section_p = in_cold_section_p; - decl = NOTE_VAR_LOCATION_DECL (loc_note); - add_var_loc_to_decl (decl, newloc); } /* We need to reset the locations at the beginning of each @@ -19777,8 +20339,6 @@ dwarf2out_var_location (rtx loc_note) static void dwarf2out_begin_function (tree fun) { - htab_empty (decl_loc_table); - if (function_section (fun) != text_section) have_multiple_function_sections = true; @@ -19993,6 +20553,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) pubname_table = VEC_alloc (pubname_entry, gc, 32); pubtype_table = VEC_alloc (pubname_entry, gc, 32); + /* Allocate the table that maps insn UIDs to vtable slot indexes. */ + vcall_insn_table = htab_create_ggc (10, vcall_insn_table_hash, + vcall_insn_table_eq, NULL); + /* Generate the initial DIE for the .debug section. Note that the (string) value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE will (typically) be a relative pathname and that this pathname should be @@ -20021,6 +20585,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) SECTION_DEBUG, NULL); debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, SECTION_DEBUG, NULL); + debug_dcall_section = get_section (DEBUG_DCALL_SECTION, + SECTION_DEBUG, NULL); + debug_vcall_section = get_section (DEBUG_VCALL_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, @@ -20066,15 +20634,21 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label); } -#ifdef HAVE_GAS_CFI_SECTIONS_DIRECTIVE - if (dwarf2out_do_cfi_asm ()) +} + +/* Called before cgraph_optimize starts outputtting functions, variables + and toplevel asms into assembly. */ + +static void +dwarf2out_assembly_start (void) +{ + if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE && dwarf2out_do_cfi_asm ()) { #ifndef TARGET_UNWIND_INFO if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions)) #endif fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n"); } -#endif } /* A helper function for dwarf2out_finish called through @@ -20188,7 +20762,7 @@ prune_unused_types_mark (dw_die_ref die, int dokids) breaking out types into comdat sections, do this for all type definitions. */ if (die->die_tag == DW_TAG_array_type - || (dwarf_version >= 4 + || (dwarf_version >= 4 && is_type_die (die) && ! is_declaration_die (die))) FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1)); else @@ -20395,6 +20969,7 @@ prune_unused_types (void) limbo_die_node *node; comdat_type_node *ctnode; pubname_ref pub; + dcall_entry *dcall; #if ENABLE_ASSERT_CHECKING /* All the marks should already be clear. */ @@ -20425,6 +21000,10 @@ prune_unused_types (void) for (i = 0; i < arange_table_in_use; i++) prune_unused_types_mark (arange_table[i], 1); + /* Mark nodes referenced from the direct call table. */ + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, dcall); i++) + prune_unused_types_mark (dcall->targ_die, 1); + /* Get rid of nodes that aren't marked; and update the string counts. */ if (debug_str_hash && debug_str_hash_forced) htab_traverse (debug_str_hash, prune_indirect_string, NULL); @@ -20578,28 +21157,48 @@ resolve_addr (dw_die_ref die) { dw_die_ref c; dw_attr_ref a; - dw_loc_list_ref curr; + dw_loc_list_ref *curr; unsigned ix; for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) switch (AT_class (a)) { case dw_val_class_loc_list: - for (curr = AT_loc_list (a); curr != NULL; curr = curr->dw_loc_next) - if (!resolve_addr_in_expr (curr->expr)) - curr->expr = NULL; + curr = AT_loc_list_ptr (a); + while (*curr) + { + if (!resolve_addr_in_expr ((*curr)->expr)) + { + dw_loc_list_ref next = (*curr)->dw_loc_next; + if (next && (*curr)->ll_symbol) + { + gcc_assert (!next->ll_symbol); + next->ll_symbol = (*curr)->ll_symbol; + } + *curr = next; + } + else + curr = &(*curr)->dw_loc_next; + } + if (!AT_loc_list (a)) + { + remove_AT (die, a->dw_attr); + ix--; + } break; case dw_val_class_loc: if (!resolve_addr_in_expr (AT_loc (a))) - a->dw_attr_val.v.val_loc = NULL; + { + remove_AT (die, a->dw_attr); + ix--; + } break; case dw_val_class_addr: if (a->dw_attr == DW_AT_const_value && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL)) { - a->dw_attr = DW_AT_location; - a->dw_attr_val.val_class = dw_val_class_loc; - a->dw_attr_val.v.val_loc = NULL; + remove_AT (die, a->dw_attr); + ix--; } break; default: @@ -20780,6 +21379,7 @@ dwarf2out_finish (const char *filename) else { unsigned fde_idx = 0; + bool range_list_added = false; /* We need to give .debug_loc and .debug_ranges an appropriate "base address". Use zero so that these addresses become @@ -20789,12 +21389,12 @@ dwarf2out_finish (const char *filename) add_AT_addr (comp_unit_die, DW_AT_low_pc, const0_rtx); add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx); - add_AT_range_list (comp_unit_die, DW_AT_ranges, - add_ranges_by_labels (text_section_label, - text_end_label)); - if (flag_reorder_blocks_and_partition) - add_ranges_by_labels (cold_text_section_label, - cold_end_label); + if (text_section_used) + add_ranges_by_labels (comp_unit_die, text_section_label, + text_end_label, &range_list_added); + if (flag_reorder_blocks_and_partition && cold_text_section_used) + add_ranges_by_labels (comp_unit_die, cold_text_section_label, + cold_end_label, &range_list_added); for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++) { @@ -20803,18 +21403,23 @@ dwarf2out_finish (const char *filename) if (fde->dw_fde_switched_sections) { if (!fde->in_std_section) - add_ranges_by_labels (fde->dw_fde_hot_section_label, - fde->dw_fde_hot_section_end_label); + add_ranges_by_labels (comp_unit_die, + fde->dw_fde_hot_section_label, + fde->dw_fde_hot_section_end_label, + &range_list_added); if (!fde->cold_in_std_section) - add_ranges_by_labels (fde->dw_fde_unlikely_section_label, - fde->dw_fde_unlikely_section_end_label); + add_ranges_by_labels (comp_unit_die, + fde->dw_fde_unlikely_section_label, + fde->dw_fde_unlikely_section_end_label, + &range_list_added); } else if (!fde->in_std_section) - add_ranges_by_labels (fde->dw_fde_begin, - fde->dw_fde_end); + add_ranges_by_labels (comp_unit_die, fde->dw_fde_begin, + fde->dw_fde_end, &range_list_added); } - add_ranges (NULL); + if (range_list_added) + add_ranges (NULL); } /* Output location list section if necessary. */ @@ -20886,6 +21491,18 @@ dwarf2out_finish (const char *filename) output_pubnames (pubtype_table); } + /* Output direct and virtual call tables if necessary. */ + if (!VEC_empty (dcall_entry, dcall_table)) + { + switch_to_section (debug_dcall_section); + output_dcall_table (); + } + if (!VEC_empty (vcall_entry, vcall_table)) + { + switch_to_section (debug_vcall_section); + output_vcall_table (); + } + /* Output the address range information. We only put functions in the arange table, so don't write it out if we don't have any. */ if (fde_table_in_use) @@ -20933,6 +21550,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { 0, /* init */ 0, /* finish */ + 0, /* assembly_start */ 0, /* define */ 0, /* undef */ 0, /* start_source_file */ @@ -20956,6 +21574,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = 0, /* handle_pch */ 0, /* var_location */ 0, /* switch_text_section */ + 0, /* direct_call */ + 0, /* virtual_call_token */ + 0, /* copy_call_info */ + 0, /* virtual_call */ 0, /* set_name */ 0 /* start_end_main_source_file */ };