X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fdwarf2out.c;h=3e3cf316acbe6b4f0e7dd84268d05b53a905d36a;hb=f018d957a72d418d69c6d2d8bc80c9415666a9f6;hp=aad6ee7716a5d917b65d3ce7e0cefcfc8db29a1d;hpb=c9b44d2c764801aaca057e04c73edb0c1facf832;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index aad6ee7716a..3e3cf316acb 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -89,6 +89,8 @@ along with GCC; see the file COPYING3. If not see #include "hashtab.h" #include "cgraph.h" #include "input.h" +#include "gimple.h" +#include "tree-pass.h" #ifdef DWARF2_DEBUGGING_INFO static void dwarf2out_source_line (unsigned int, const char *, int, bool); @@ -163,7 +165,7 @@ dwarf2out_do_cfi_asm (void) #endif if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ()) return false; - if (saved_do_cfi_asm || !eh_personality_libfunc) + if (saved_do_cfi_asm) return true; if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE) return false; @@ -177,6 +179,16 @@ dwarf2out_do_cfi_asm (void) if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel) return false; + if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE) + { +#ifdef TARGET_UNWIND_INFO + return false; +#else + if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions)) + return false; +#endif + } + saved_do_cfi_asm = true; return true; } @@ -212,10 +224,16 @@ 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; +/* Personality decl of current unit. Used only when assembler does not support + personality CFI. */ +static GTY(()) rtx current_unit_personality; + /* How to start an assembler comment. */ #ifndef ASM_COMMENT_START #define ASM_COMMENT_START ";#" @@ -332,6 +350,12 @@ dw_fde_node; #define DWARF_OFFSET_SIZE 4 #endif +/* The size in bytes of a DWARF 4 type signature. */ + +#ifndef DWARF_TYPE_SIGNATURE_SIZE +#define DWARF_TYPE_SIGNATURE_SIZE 8 +#endif + /* According to the (draft) DWARF 3 specification, the initial length should either be 4 or 12 bytes. When it's 12 bytes, the first 4 bytes are 0xffffffff, followed by the length stored in the next 8 @@ -407,6 +431,10 @@ struct GTY(()) indirect_string_node { static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash; +/* True if the compilation unit has location entries that reference + debug strings. */ +static GTY(()) bool debug_str_hash_forced = false; + static GTY(()) int dw2_string_counter; static GTY(()) unsigned long dwarf2out_cfi_label_num; @@ -442,8 +470,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 *); @@ -778,7 +804,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); } @@ -1016,7 +1042,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) @@ -1129,25 +1155,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. */ @@ -1498,13 +1505,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; @@ -1588,31 +1640,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 @@ -1857,7 +1885,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)) { @@ -2190,7 +2218,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; @@ -2683,10 +2711,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; } @@ -2844,7 +2875,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; @@ -2992,6 +3023,23 @@ switch_to_eh_frame_section (bool back) } } +/* Switch [BACK] to the eh or debug frame table section, depending on + FOR_EH. */ + +static void +switch_to_frame_table_section (int for_eh, bool back) +{ + if (for_eh) + switch_to_eh_frame_section (back); + else + { + if (!debug_frame_section) + debug_frame_section = get_section (DEBUG_FRAME_SECTION, + SECTION_DEBUG, NULL); + switch_to_section (debug_frame_section); + } +} + /* Output a Call Frame Information opcode and its operand(s). */ static void @@ -3560,23 +3608,6 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, j += 2; } - -/* Switch [BACK] to the eh or debug frame table section, depending on - FOR_EH. */ -static void -switch_to_frame_table_section (int for_eh, bool back) -{ - if (for_eh) - switch_to_eh_frame_section (back); - else - { - if (!debug_frame_section) - debug_frame_section = get_section (DEBUG_FRAME_SECTION, - SECTION_DEBUG, NULL); - switch_to_section (debug_frame_section); - } -} - /* Output the call frame information used to record information that relates to calculating the frame pointer, and records the location of saved registers. */ @@ -3595,6 +3626,7 @@ output_call_frame_info (int for_eh) int per_encoding = DW_EH_PE_absptr; int lsda_encoding = DW_EH_PE_absptr; int return_reg; + rtx personality = NULL; int dw_cie_version; /* Don't emit a CIE if there won't be any FDEs. */ @@ -3680,6 +3712,8 @@ output_call_frame_info (int for_eh) augmentation[0] = 0; augmentation_size = 0; + + personality = current_unit_personality; if (for_eh) { char *p; @@ -3699,11 +3733,11 @@ output_call_frame_info (int for_eh) lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0); p = augmentation + 1; - if (eh_personality_libfunc) + if (personality) { *p++ = 'P'; augmentation_size += 1 + size_of_encoded_value (per_encoding); - assemble_external_libcall (eh_personality_libfunc); + assemble_external_libcall (personality); } if (any_lsda_needed) { @@ -3722,7 +3756,7 @@ output_call_frame_info (int for_eh) } /* Ug. Some platforms can't do unaligned dynamic relocations at all. */ - if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned) + if (personality && per_encoding == DW_EH_PE_aligned) { int offset = ( 4 /* Length */ + 4 /* CIE Id */ @@ -3756,12 +3790,12 @@ output_call_frame_info (int for_eh) if (augmentation[0]) { dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size"); - if (eh_personality_libfunc) + if (personality) { dw2_asm_output_data (1, per_encoding, "Personality (%s)", eh_data_format_name (per_encoding)); dw2_asm_output_encoded_addr_rtx (per_encoding, - eh_personality_libfunc, + personality, true, NULL); } @@ -3820,13 +3854,14 @@ dwarf2out_do_cfi_startproc (bool second) { int enc; rtx ref; + rtx personality = get_personality_function (current_function_decl); fprintf (asm_out_file, "\t.cfi_startproc\n"); - if (eh_personality_libfunc) + if (personality) { enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1); - ref = eh_personality_libfunc; + ref = personality; /* ??? The GAS support isn't entirely consistent. We have to handle indirect support ourselves, but PC-relative is done @@ -3965,6 +4000,20 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, if (dwarf2out_do_cfi_asm ()) dwarf2out_do_cfi_startproc (false); + else + { + rtx personality = get_personality_function (current_function_decl); + if (!current_unit_personality) + current_unit_personality = personality; + + /* We cannot keep a current personality per function as without CFI + asm at the point where we emit the CFI data there is no current + function anymore. */ + if (personality + && current_unit_personality != personality) + sorry ("Multiple EH personalities are supported only with assemblers " + "supporting .cfi.personality directive."); + } } /* Output a marker (i.e. a label) for the absolute end of the generated code @@ -4117,6 +4166,9 @@ DEF_VEC_ALLOC_O(deferred_locations,gc); static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list; +DEF_VEC_P(dw_die_ref); +DEF_VEC_ALLOC_P(dw_die_ref,heap); + /* Each DIE may have a series of attribute/value pairs. Values can take on several forms. The forms that are used in this implementation are listed below. */ @@ -4130,7 +4182,7 @@ enum dw_val_class dw_val_class_range_list, dw_val_class_const, dw_val_class_unsigned_const, - dw_val_class_long_long, + dw_val_class_const_double, dw_val_class_vec, dw_val_class_flag, dw_val_class_die_ref, @@ -4139,18 +4191,10 @@ enum dw_val_class dw_val_class_lineptr, dw_val_class_str, dw_val_class_macptr, - dw_val_class_file + dw_val_class_file, + dw_val_class_data8 }; -/* Describe a double word constant value. */ -/* ??? Every instance of long_long in the code really means CONST_DOUBLE. */ - -typedef struct GTY(()) dw_long_long_struct { - unsigned long hi; - unsigned long low; -} -dw_long_long_const; - /* Describe a floating point constant value, or a vector constant value. */ typedef struct GTY(()) dw_vec_struct { @@ -4173,7 +4217,7 @@ typedef struct GTY(()) dw_val_struct { dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc; HOST_WIDE_INT GTY ((default)) val_int; unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned; - dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long; + double_int GTY ((tag ("dw_val_class_const_double"))) val_double; dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec; struct dw_val_die_union { @@ -4185,6 +4229,7 @@ typedef struct GTY(()) dw_val_struct { char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id; unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag; struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file; + unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8]; } GTY ((desc ("%1.val_class"))) v; } @@ -4528,6 +4573,10 @@ dwarf_stack_op_name (unsigned int op) return "DW_OP_call4"; case DW_OP_call_ref: return "DW_OP_call_ref"; + case DW_OP_implicit_value: + return "DW_OP_implicit_value"; + case DW_OP_stack_value: + return "DW_OP_stack_value"; case DW_OP_form_tls_address: return "DW_OP_form_tls_address"; case DW_OP_call_frame_cfa: @@ -4634,6 +4683,18 @@ loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset) } } +#ifdef DWARF2_DEBUGGING_INFO +/* Add a constant OFFSET to a location list. */ + +static void +loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset) +{ + dw_loc_list_ref d; + for (d = list_head; d != NULL; d = d->dw_loc_next) + loc_descr_plus_const (&d->expr, offset); +} +#endif + /* Return the size of a location descriptor. */ static unsigned long @@ -4738,6 +4799,10 @@ size_of_loc_descr (dw_loc_descr_ref loc) case DW_OP_call_ref: size += DWARF2_ADDR_SIZE; break; + case DW_OP_implicit_value: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned) + + loc->dw_loc_oprnd1.v.val_unsigned; + break; default: break; } @@ -4773,6 +4838,10 @@ size_of_locs (dw_loc_descr_ref loc) return size; } +#ifdef DWARF2_DEBUGGING_INFO +static HOST_WIDE_INT extract_int (const unsigned char *, unsigned); +#endif + /* Output location description stack opcode's operands (if any). */ static void @@ -4794,7 +4863,7 @@ output_loc_operands (dw_loc_descr_ref loc) break; case DW_OP_const8u: case DW_OP_const8s: - gcc_assert (HOST_BITS_PER_LONG >= 64); + gcc_assert (HOST_BITS_PER_WIDE_INT >= 64); dw2_asm_output_data (8, val1->v.val_int, NULL); break; case DW_OP_skip: @@ -4808,6 +4877,60 @@ output_loc_operands (dw_loc_descr_ref loc) dw2_asm_output_data (2, offset, NULL); } break; + case DW_OP_implicit_value: + dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL); + switch (val2->val_class) + { + case dw_val_class_const: + dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL); + break; + case dw_val_class_vec: + { + unsigned int elt_size = val2->v.val_vec.elt_size; + unsigned int len = val2->v.val_vec.length; + unsigned int i; + unsigned char *p; + + if (elt_size > sizeof (HOST_WIDE_INT)) + { + elt_size /= 2; + len *= 2; + } + for (i = 0, p = val2->v.val_vec.array; + i < len; + i++, p += elt_size) + dw2_asm_output_data (elt_size, extract_int (p, elt_size), + "fp or vector constant word %u", i); + } + break; + case dw_val_class_const_double: + { + unsigned HOST_WIDE_INT first, second; + + if (WORDS_BIG_ENDIAN) + { + first = val2->v.val_double.high; + second = val2->v.val_double.low; + } + else + { + first = val2->v.val_double.low; + second = val2->v.val_double.high; + } + dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR, + first, NULL); + dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR, + second, NULL); + } + break; + case dw_val_class_addr: + gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE); + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL); + break; + default: + gcc_unreachable (); + } + break; #else case DW_OP_const2u: case DW_OP_const2s: @@ -4817,6 +4940,7 @@ output_loc_operands (dw_loc_descr_ref loc) case DW_OP_const8s: case DW_OP_skip: case DW_OP_bra: + case DW_OP_implicit_value: /* We currently don't make any attempt to make sure these are aligned properly like we do for the main unwind info, so don't support emitting things larger than a byte if we're @@ -4948,6 +5072,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc) switch (loc->dw_loc_opc) { case DW_OP_addr: + case DW_OP_implicit_value: /* We cannot output addresses in .cfi_escape, only bytes. */ gcc_unreachable (); @@ -4974,7 +5099,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc) case DW_OP_const8u: case DW_OP_const8s: - gcc_assert (HOST_BITS_PER_LONG >= 64); + gcc_assert (HOST_BITS_PER_WIDE_INT >= 64); fputc (',', asm_out_file); dw2_asm_output_data_raw (8, val1->v.val_int); break; @@ -5279,6 +5404,7 @@ 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 *); @@ -5293,6 +5419,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); @@ -5302,6 +5432,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { dwarf2out_init, dwarf2out_finish, + dwarf2out_assembly_start, dwarf2out_define, dwarf2out_undef, dwarf2out_start_source_file, @@ -5328,6 +5459,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 */ }; @@ -5355,6 +5490,7 @@ typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; typedef struct pubname_struct *pubname_ref; typedef struct dw_ranges_struct *dw_ranges_ref; typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref; +typedef struct comdat_type_struct *comdat_type_node_ref; /* Each entry in the line_info_table maintains the file and line number associated with the label generated for that @@ -5395,7 +5531,12 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc); typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct { enum dwarf_tag die_tag; - char *die_symbol; + union die_symbol_or_type_node + { + char * GTY ((tag ("0"))) die_symbol; + comdat_type_node_ref GTY ((tag ("1"))) die_type_node; + } + GTY ((desc ("dwarf_version >= 4"))) die_id; VEC(dw_attr_node,gc) * die_attr; dw_die_ref die_parent; dw_die_ref die_child; @@ -5441,6 +5582,16 @@ struct GTY(()) dw_ranges_by_label_struct { const char *end; }; +/* The comdat type node structure. */ +typedef struct GTY(()) comdat_type_struct +{ + dw_die_ref root_die; + dw_die_ref type_die; + char signature[DWARF_TYPE_SIGNATURE_SIZE]; + struct comdat_type_struct *next; +} +comdat_type_node; + /* The limbo die list structure. */ typedef struct GTY(()) limbo_die_struct { dw_die_ref die; @@ -5449,6 +5600,14 @@ typedef struct GTY(()) limbo_die_struct { } limbo_die_node; +typedef struct GTY(()) skeleton_chain_struct +{ + dw_die_ref old_die; + dw_die_ref new_die; + struct skeleton_chain_struct *parent; +} +skeleton_chain_node; + /* How to start an assembler comment. */ #ifndef ASM_COMMENT_START #define ASM_COMMENT_START ";#" @@ -5482,6 +5641,11 @@ limbo_die_node; #define DWARF_COMPILE_UNIT_HEADER_SIZE \ (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3) +/* Fixed size portion of the DWARF comdat type unit header. */ +#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \ + (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \ + + DWARF_OFFSET_SIZE) + /* Fixed size portion of public names info. */ #define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) @@ -5532,6 +5696,9 @@ static unsigned long next_die_offset; /* Record the root of the DIE's built for the current compilation unit. */ static GTY(()) dw_die_ref comp_unit_die; +/* A list of type DIEs that have been separated into comdat sections. */ +static GTY(()) comdat_type_node *comdat_type_list; + /* A list of DIEs with a NULL parent waiting to be relocated. */ static GTY(()) limbo_die_node *limbo_die_list; @@ -5551,6 +5718,14 @@ static GTY ((param_is (struct die_struct))) htab_t decl_die_table; The key is DECL_UID() ^ die_parent. */ static GTY ((param_is (struct die_struct))) htab_t common_block_die_table; +typedef struct GTY(()) die_arg_entry_struct { + dw_die_ref die; + tree arg; +} die_arg_entry; + +DEF_VEC_O(die_arg_entry); +DEF_VEC_ALLOC_O(die_arg_entry,gc); + /* Node of the variable location list. */ struct GTY ((chain_next ("%h.next"))) var_loc_node { rtx GTY (()) var_loc_note; @@ -5668,6 +5843,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; @@ -5685,6 +5899,8 @@ static GTY(()) int label_num; /* Cached result of previous call to lookup_filename. */ static GTY(()) struct dwarf_file_data * file_table_last_lookup; +static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table; + #ifdef DWARF2_DEBUGGING_INFO /* Offset from the "steady-state frame pointer" to the frame base, @@ -5709,10 +5925,11 @@ static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT); static inline HOST_WIDE_INT AT_int (dw_attr_ref); static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT); static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref); -static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long, - unsigned long); +static void add_AT_double (dw_die_ref, enum dwarf_attribute, + HOST_WIDE_INT, unsigned HOST_WIDE_INT); static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int, unsigned int, unsigned char *); +static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *); static hashval_t debug_str_do_hash (const void *); static int debug_str_eq (const void *, const void *); static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *); @@ -5775,6 +5992,16 @@ static dw_die_ref pop_compile_unit (dw_die_ref); static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *); static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *); static void die_checksum (dw_die_ref, struct md5_ctx *, int *); +static void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *); +static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *); +static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *); +static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref, + struct md5_ctx *, int *); +struct checksum_attributes; +static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref); +static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *); +static void checksum_die_context (dw_die_ref, struct md5_ctx *); +static void generate_type_signature (dw_die_ref, comdat_type_node *); static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *); static int same_dw_val_p (const dw_val_node *, const dw_val_node *, int *); static int same_attr_p (dw_attr_ref, dw_attr_ref, int *); @@ -5786,6 +6013,22 @@ static int is_comdat_die (dw_die_ref); static int is_symbol_die (dw_die_ref); static void assign_symbol_names (dw_die_ref); static void break_out_includes (dw_die_ref); +static int is_declaration_die (dw_die_ref); +static int should_move_die_to_comdat (dw_die_ref); +static dw_die_ref clone_as_declaration (dw_die_ref); +static dw_die_ref clone_die (dw_die_ref); +static dw_die_ref clone_tree (dw_die_ref); +static void copy_declaration_context (dw_die_ref, dw_die_ref); +static void generate_skeleton_ancestor_tree (skeleton_chain_node *); +static void generate_skeleton_bottom_up (skeleton_chain_node *); +static dw_die_ref generate_skeleton (dw_die_ref); +static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref, + dw_die_ref); +static void break_out_comdat_types (dw_die_ref); +static dw_die_ref copy_ancestor_tree (dw_die_ref, dw_die_ref, htab_t); +static void copy_decls_walk (dw_die_ref, dw_die_ref, htab_t); +static void copy_decls_for_unworthy_types (dw_die_ref); + static hashval_t htab_cu_hash (const void *); static int htab_cu_eq (const void *, const void *); static void htab_cu_del (void *); @@ -5809,6 +6052,7 @@ static void output_die_symbol (dw_die_ref); static void output_die (dw_die_ref); static void output_compilation_unit_header (void); static void output_comp_unit (dw_die_ref, int); +static void output_comdat_type_unit (comdat_type_node *); static const char *dwarf2_name (tree, int); static void add_pubname (tree, dw_die_ref); static void add_pubname_string (const char *, dw_die_ref); @@ -5826,6 +6070,8 @@ static dw_die_ref base_type_die (tree); static int is_base_type (tree); static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref); static dw_die_ref modified_type_die (tree, int, int, dw_die_ref); +static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref); +static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref); static int type_is_enum (const_tree); static unsigned int dbx_reg_number (const_rtx); static void add_loc_descr_op_piece (dw_loc_descr_ref *, int); @@ -5837,13 +6083,15 @@ static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx, static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT, enum var_init_status); static int is_based_loc (const_rtx); +static int resolve_one_addr (rtx *, void *); static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode, enum var_init_status); static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx, enum var_init_status); -static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status); -static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int); -static dw_loc_descr_ref loc_descriptor_from_tree (tree); +static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode, + enum var_init_status); +static dw_loc_list_ref loc_list_from_tree (tree, int); +static dw_loc_descr_ref loc_descriptor_from_tree (tree, int); static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int); static tree field_type (const_tree); static unsigned int simple_type_align_in_bits (const_tree); @@ -5851,16 +6099,16 @@ static unsigned int simple_decl_align_in_bits (const_tree); static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree); static HOST_WIDE_INT field_byte_offset (const_tree); static void add_AT_location_description (dw_die_ref, enum dwarf_attribute, - dw_loc_descr_ref); + dw_loc_list_ref); static void add_data_member_location_attribute (dw_die_ref, tree); -static void add_const_value_attribute (dw_die_ref, rtx); +static bool add_const_value_attribute (dw_die_ref, rtx); static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *); -static HOST_WIDE_INT extract_int (const unsigned char *, unsigned); static void insert_float (const_rtx, unsigned char *); static rtx rtl_for_decl_location (tree); -static void add_location_or_const_value_attribute (dw_die_ref, tree, +static bool add_location_or_const_value_attribute (dw_die_ref, tree, enum dwarf_attribute); -static void tree_add_const_value_attribute (dw_die_ref, tree); +static bool tree_add_const_value_attribute (dw_die_ref, tree); +static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree); static void add_name_attribute (dw_die_ref, const char *); static void add_comp_dir_attribute (dw_die_ref); static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree); @@ -5892,7 +6140,8 @@ static void gen_descr_array_type_die (tree, struct array_descr_info *, dw_die_re static void gen_entry_point_die (tree, dw_die_ref); #endif static dw_die_ref gen_enumeration_type_die (tree, dw_die_ref); -static dw_die_ref gen_formal_parameter_die (tree, tree, dw_die_ref); +static dw_die_ref gen_formal_parameter_die (tree, tree, bool, dw_die_ref); +static dw_die_ref gen_formal_parameter_pack_die (tree, tree, dw_die_ref, tree*); static void gen_unspecified_parameters_die (tree, dw_die_ref); static void gen_formal_types_die (tree, dw_die_ref); static void gen_subprogram_die (tree, dw_die_ref); @@ -5924,6 +6173,7 @@ static dw_die_ref declare_in_namespace (tree, dw_die_ref); static struct dwarf_file_data * lookup_filename (const char *); static void retry_incomplete_types (void); static void gen_type_die_for_member (tree, tree, dw_die_ref); +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 *, @@ -5941,6 +6191,8 @@ static void prune_unused_types_walk_attribs (dw_die_ref); static void prune_unused_types_prune (dw_die_ref); static void prune_unused_types (void); static int maybe_emit_file (struct dwarf_file_data *fd); +static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree); +static void gen_remaining_tmpl_value_param_die_attribute (void); /* Section names used to hold DWARF debugging information. */ #ifndef DEBUG_INFO_SECTION @@ -5967,6 +6219,12 @@ static int maybe_emit_file (struct dwarf_file_data *fd); #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 @@ -6225,6 +6483,16 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_condition"; case DW_TAG_shared_type: 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: + return "DW_TAG_GNU_formal_parameter_pack"; case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; case DW_TAG_format_label: @@ -6237,6 +6505,8 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_GNU_BINCL"; case DW_TAG_GNU_EINCL: return "DW_TAG_GNU_EINCL"; + case DW_TAG_GNU_template_template_param: + return "DW_TAG_GNU_template_template_param"; default: return "DW_TAG_"; } @@ -6401,6 +6671,19 @@ dwarf_attr_name (unsigned int attr) case DW_AT_call_line: return "DW_AT_call_line"; + 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"; case DW_AT_MIPS_loop_begin: @@ -6438,6 +6721,24 @@ 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"; case DW_AT_VMS_rtnbeg_pd_address: return "DW_AT_VMS_rtnbeg_pd_address"; @@ -6496,6 +6797,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_"; } @@ -6631,15 +6940,15 @@ AT_unsigned (dw_attr_ref a) /* Add an unsigned double integer attribute value to a DIE. */ static inline void -add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind, - long unsigned int val_hi, long unsigned int val_low) +add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind, + HOST_WIDE_INT high, unsigned HOST_WIDE_INT low) { dw_attr_node attr; attr.dw_attr = attr_kind; - attr.dw_attr_val.val_class = dw_val_class_long_long; - attr.dw_attr_val.v.val_long_long.hi = val_hi; - attr.dw_attr_val.v.val_long_long.low = val_low; + attr.dw_attr_val.val_class = dw_val_class_const_double; + attr.dw_attr_val.v.val_double.high = high; + attr.dw_attr_val.v.val_double.low = low; add_dwarf_attr (die, &attr); } @@ -6659,6 +6968,20 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind, add_dwarf_attr (die, &attr); } +/* Add an 8-byte data attribute value to a DIE. */ + +static inline void +add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind, + unsigned char data8[8]) +{ + dw_attr_node attr; + + attr.dw_attr = attr_kind; + attr.dw_attr_val.val_class = dw_val_class_data8; + memcpy (attr.dw_attr_val.v.val_data8, data8, 8); + add_dwarf_attr (die, &attr); +} + /* Hash and equality functions for debug_str_hash. */ static hashval_t @@ -6674,6 +6997,8 @@ debug_str_eq (const void *x1, const void *x2) (const char *)x2) == 0; } +/* Add STR to the indirect string hash table. */ + static struct indirect_string_node * find_AT_string (const char *str) { @@ -6716,6 +7041,37 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str) add_dwarf_attr (die, &attr); } +/* Create a label for an indirect string node, ensuring it is going to + be output, unless its reference count goes down to zero. */ + +static inline void +gen_label_for_indirect_string (struct indirect_string_node *node) +{ + char label[32]; + + if (node->label) + return; + + ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); + ++dw2_string_counter; + node->label = xstrdup (label); +} + +/* Create a SYMBOL_REF rtx whose value is the initial address of a + debug string STR. */ + +static inline rtx +get_debug_string_label (const char *str) +{ + struct indirect_string_node *node = find_AT_string (str); + + debug_str_hash_forced = true; + + gen_label_for_indirect_string (node); + + return gen_rtx_SYMBOL_REF (Pmode, node->label); +} + static inline const char * AT_string (dw_attr_ref a) { @@ -6731,7 +7087,6 @@ AT_string_form (dw_attr_ref a) { struct indirect_string_node *node; unsigned int len; - char label[32]; gcc_assert (a && AT_class (a) == dw_val_class_str); @@ -6754,9 +7109,7 @@ AT_string_form (dw_attr_ref a) && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)) return node->form = DW_FORM_string; - ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); - ++dw2_string_counter; - node->label = xstrdup (label); + gen_label_for_indirect_string (node); return node->form = DW_FORM_strp; } @@ -7182,6 +7535,43 @@ remove_child_with_prev (dw_die_ref child, dw_die_ref prev) child->die_parent->die_child = prev; } +/* Replace OLD_CHILD with NEW_CHILD. PREV must have the property that + PREV->DIE_SIB == OLD_CHILD. Does not alter OLD_CHILD. */ + +static void +replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev) +{ + dw_die_ref parent = old_child->die_parent; + + gcc_assert (parent == prev->die_parent); + gcc_assert (prev->die_sib == old_child); + + new_child->die_parent = parent; + if (prev == old_child) + { + gcc_assert (parent->die_child == old_child); + new_child->die_sib = new_child; + } + else + { + prev->die_sib = new_child; + new_child->die_sib = old_child->die_sib; + } + if (old_child->die_parent->die_child == old_child) + old_child->die_parent->die_child = new_child; +} + +/* Move all children from OLD_PARENT to NEW_PARENT. */ + +static void +move_all_children (dw_die_ref old_parent, dw_die_ref new_parent) +{ + dw_die_ref c; + new_parent->die_child = old_parent->die_child; + old_parent->die_child = NULL; + FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent); +} + /* Remove child DIE whose die_tag is TAG. Do nothing if no child matches TAG. */ @@ -7346,6 +7736,8 @@ decl_loc_table_eq (const void *x, const void *y) static inline var_loc_list * lookup_decl_loc (const_tree decl) { + if (!decl_loc_table) + return NULL; return (var_loc_list *) htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl)); } @@ -7422,6 +7814,17 @@ print_spaces (FILE *outfile) fprintf (outfile, "%*s", print_indent, ""); } +/* Print a type signature in hex. */ + +static inline void +print_signature (FILE *outfile, char *sig) +{ + int i; + + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + fprintf (outfile, "%02x", sig[i] & 0xff); +} + /* Print the information associated with a given DIE, and its children. This routine is a debugging aid only. */ @@ -7438,6 +7841,13 @@ print_die (dw_die_ref die, FILE *outfile) print_spaces (outfile); fprintf (outfile, " abbrev id: %lu", die->die_abbrev); fprintf (outfile, " offset: %ld\n", die->die_offset); + if (dwarf_version >= 4 && die->die_id.die_type_node) + { + print_spaces (outfile); + fprintf (outfile, " signature: "); + print_signature (outfile, die->die_id.die_type_node->signature); + fprintf (outfile, "\n"); + } for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) { @@ -7468,10 +7878,11 @@ print_die (dw_die_ref die, FILE *outfile) case dw_val_class_unsigned_const: fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a)); break; - case dw_val_class_long_long: - fprintf (outfile, "constant (%lu,%lu)", - a->dw_attr_val.v.val_long_long.hi, - a->dw_attr_val.v.val_long_long.low); + case dw_val_class_const_double: + fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\ + HOST_WIDE_INT_PRINT_UNSIGNED")", + a->dw_attr_val.v.val_double.high, + a->dw_attr_val.v.val_double.low); break; case dw_val_class_vec: fprintf (outfile, "floating-point or vector constant"); @@ -7482,8 +7893,15 @@ print_die (dw_die_ref die, FILE *outfile) case dw_val_class_die_ref: if (AT_ref (a) != NULL) { - if (AT_ref (a)->die_symbol) - fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol); + if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node) + { + fprintf (outfile, "die -> signature: "); + print_signature (outfile, + AT_ref (a)->die_id.die_type_node->signature); + } + else if (dwarf_version < 4 && AT_ref (a)->die_id.die_symbol) + fprintf (outfile, "die -> label: %s", + AT_ref (a)->die_id.die_symbol); else fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset); } @@ -7505,6 +7923,14 @@ print_die (dw_die_ref die, FILE *outfile) fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename, AT_file (a)->emitted_number); break; + case dw_val_class_data8: + { + int i; + + for (i = 0; i < 8; i++) + fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]); + break; + } default: break; } @@ -7627,8 +8053,8 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark) case dw_val_class_unsigned_const: CHECKSUM (at->dw_attr_val.v.val_unsigned); break; - case dw_val_class_long_long: - CHECKSUM (at->dw_attr_val.v.val_long_long); + case dw_val_class_const_double: + CHECKSUM (at->dw_attr_val.v.val_double); break; case dw_val_class_vec: CHECKSUM (at->dw_attr_val.v.val_vec); @@ -7669,6 +8095,10 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark) CHECKSUM_STRING (AT_file (at)->filename); break; + case dw_val_class_data8: + CHECKSUM (at->dw_attr_val.v.val_data8); + break; + default: break; } @@ -7702,225 +8132,1130 @@ die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark) #undef CHECKSUM #undef CHECKSUM_STRING -/* Do the location expressions look same? */ -static inline int -same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark) -{ - return loc1->dw_loc_opc == loc2->dw_loc_opc - && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark) - && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark); -} +/* For DWARF-4 types, include the trailing NULL when checksumming strings. */ +#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx) +#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx) +#define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx) +#define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx) +#define CHECKSUM_ATTR(FOO) \ + if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark) -/* Do the values look the same? */ -static int -same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark) +/* Calculate the checksum of a number in signed LEB128 format. */ + +static void +checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx) { - dw_loc_descr_ref loc1, loc2; - rtx r1, r2; + unsigned char byte; + bool more; - if (v1->val_class != v2->val_class) - return 0; + while (1) + { + byte = (value & 0x7f); + value >>= 7; + more = !((value == 0 && (byte & 0x40) == 0) + || (value == -1 && (byte & 0x40) != 0)); + if (more) + byte |= 0x80; + CHECKSUM (byte); + if (!more) + break; + } +} - switch (v1->val_class) +/* Calculate the checksum of a number in unsigned LEB128 format. */ + +static void +checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx) +{ + while (1) { - case dw_val_class_const: - return v1->v.val_int == v2->v.val_int; - case dw_val_class_unsigned_const: - return v1->v.val_unsigned == v2->v.val_unsigned; - case dw_val_class_long_long: - return v1->v.val_long_long.hi == v2->v.val_long_long.hi - && v1->v.val_long_long.low == v2->v.val_long_long.low; - case dw_val_class_vec: - if (v1->v.val_vec.length != v2->v.val_vec.length - || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size) - return 0; - if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array, - v1->v.val_vec.length * v1->v.val_vec.elt_size)) - return 0; - return 1; - case dw_val_class_flag: - return v1->v.val_flag == v2->v.val_flag; - case dw_val_class_str: - return !strcmp(v1->v.val_str->str, v2->v.val_str->str); + unsigned char byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + CHECKSUM (byte); + if (value == 0) + break; + } +} - case dw_val_class_addr: - r1 = v1->v.val_addr; - r2 = v2->v.val_addr; - if (GET_CODE (r1) != GET_CODE (r2)) - return 0; - gcc_assert (GET_CODE (r1) == SYMBOL_REF); - return !strcmp (XSTR (r1, 0), XSTR (r2, 0)); +/* Checksum the context of the DIE. This adds the names of any + surrounding namespaces or structures to the checksum. */ - case dw_val_class_offset: - return v1->v.val_offset == v2->v.val_offset; +static void +checksum_die_context (dw_die_ref die, struct md5_ctx *ctx) +{ + const char *name; + dw_die_ref spec; + int tag = die->die_tag; - case dw_val_class_loc: - for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc; - loc1 && loc2; - loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next) - if (!same_loc_p (loc1, loc2, mark)) - return 0; - return !loc1 && !loc2; + if (tag != DW_TAG_namespace + && tag != DW_TAG_structure_type + && tag != DW_TAG_class_type) + return; - case dw_val_class_die_ref: - return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark); + name = get_AT_string (die, DW_AT_name); - case dw_val_class_fde_ref: - case dw_val_class_lbl_id: - case dw_val_class_lineptr: - case dw_val_class_macptr: - return 1; + spec = get_AT_ref (die, DW_AT_specification); + if (spec != NULL) + die = spec; - case dw_val_class_file: - return v1->v.val_file == v2->v.val_file; + if (die->die_parent != NULL) + checksum_die_context (die->die_parent, ctx); - default: - return 1; - } + CHECKSUM_ULEB128 ('C'); + CHECKSUM_ULEB128 (tag); + if (name != NULL) + CHECKSUM_STRING (name); } -/* Do the attributes look the same? */ +/* Calculate the checksum of a location expression. */ -static int -same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark) +static inline void +loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx) { - if (at1->dw_attr != at2->dw_attr) - return 0; - - /* We don't care that this was compiled with a different compiler - snapshot; if the output is the same, that's what matters. */ - if (at1->dw_attr == DW_AT_producer) - return 1; + /* Special case for lone DW_OP_plus_uconst: checksum as if the location + were emitted as a DW_FORM_sdata instead of a location expression. */ + if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL) + { + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned); + return; + } - return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark); + /* Otherwise, just checksum the raw location expression. */ + while (loc != NULL) + { + CHECKSUM_ULEB128 (loc->dw_loc_opc); + CHECKSUM (loc->dw_loc_oprnd1); + CHECKSUM (loc->dw_loc_oprnd2); + loc = loc->dw_loc_next; + } } -/* Do the dies look the same? */ +/* Calculate the checksum of an attribute. */ -static int -same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark) +static void +attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at, + struct md5_ctx *ctx, int *mark) { - dw_die_ref c1, c2; - dw_attr_ref a1; - unsigned ix; + dw_loc_descr_ref loc; + rtx r; - /* To avoid infinite recursion. */ - if (die1->die_mark) - return die1->die_mark == die2->die_mark; - die1->die_mark = die2->die_mark = ++(*mark); + if (AT_class (at) == dw_val_class_die_ref) + { + dw_die_ref target_die = AT_ref (at); + + /* For pointer and reference types, we checksum only the (qualified) + name of the target type (if there is a name). For friend entries, + we checksum only the (qualified) name of the target type or function. + This allows the checksum to remain the same whether the target type + is complete or not. */ + if ((at->dw_attr == DW_AT_type + && (tag == DW_TAG_pointer_type + || tag == DW_TAG_reference_type + || tag == DW_TAG_ptr_to_member_type)) + || (at->dw_attr == DW_AT_friend + && tag == DW_TAG_friend)) + { + dw_attr_ref name_attr = get_AT (target_die, DW_AT_name); - if (die1->die_tag != die2->die_tag) - return 0; + if (name_attr != NULL) + { + dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification); + + if (decl == NULL) + decl = target_die; + CHECKSUM_ULEB128 ('N'); + CHECKSUM_ULEB128 (at->dw_attr); + if (decl->die_parent != NULL) + checksum_die_context (decl->die_parent, ctx); + CHECKSUM_ULEB128 ('E'); + CHECKSUM_STRING (AT_string (name_attr)); + return; + } + } - if (VEC_length (dw_attr_node, die1->die_attr) - != VEC_length (dw_attr_node, die2->die_attr)) - return 0; + /* For all other references to another DIE, we check to see if the + target DIE has already been visited. If it has, we emit a + backward reference; if not, we descend recursively. */ + if (target_die->die_mark > 0) + { + CHECKSUM_ULEB128 ('R'); + CHECKSUM_ULEB128 (at->dw_attr); + CHECKSUM_ULEB128 (target_die->die_mark); + } + else + { + dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification); + + if (decl == NULL) + decl = target_die; + target_die->die_mark = ++(*mark); + CHECKSUM_ULEB128 ('T'); + CHECKSUM_ULEB128 (at->dw_attr); + if (decl->die_parent != NULL) + checksum_die_context (decl->die_parent, ctx); + die_checksum_ordered (target_die, ctx, mark); + } + return; + } - for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++) - if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark)) - return 0; + CHECKSUM_ULEB128 ('A'); + CHECKSUM_ULEB128 (at->dw_attr); - c1 = die1->die_child; - c2 = die2->die_child; - if (! c1) + switch (AT_class (at)) { - if (c2) - return 0; - } - else - for (;;) - { - if (!same_die_p (c1, c2, mark)) - return 0; - c1 = c1->die_sib; - c2 = c2->die_sib; - if (c1 == die1->die_child) - { - if (c2 == die2->die_child) - break; - else - return 0; - } - } + case dw_val_class_const: + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int); + break; - return 1; -} + case dw_val_class_unsigned_const: + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned); + break; -/* Do the dies look the same? Wrapper around same_die_p. */ + case dw_val_class_const_double: + CHECKSUM_ULEB128 (DW_FORM_block); + CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double)); + CHECKSUM (at->dw_attr_val.v.val_double); + break; -static int -same_die_p_wrap (dw_die_ref die1, dw_die_ref die2) -{ - int mark = 0; - int ret = same_die_p (die1, die2, &mark); + case dw_val_class_vec: + CHECKSUM_ULEB128 (DW_FORM_block); + CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec)); + CHECKSUM (at->dw_attr_val.v.val_vec); + break; - unmark_all_dies (die1); - unmark_all_dies (die2); + case dw_val_class_flag: + CHECKSUM_ULEB128 (DW_FORM_flag); + CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0); + break; - return ret; -} + case dw_val_class_str: + CHECKSUM_ULEB128 (DW_FORM_string); + CHECKSUM_STRING (AT_string (at)); + break; -/* The prefix to attach to symbols on DIEs in the current comdat debug - info section. */ -static char *comdat_symbol_id; + case dw_val_class_addr: + r = AT_addr (at); + gcc_assert (GET_CODE (r) == SYMBOL_REF); + CHECKSUM_ULEB128 (DW_FORM_string); + CHECKSUM_STRING (XSTR (r, 0)); + break; -/* The index of the current symbol within the current comdat CU. */ -static unsigned int comdat_symbol_number; + case dw_val_class_offset: + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset); + break; -/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its - children, and set comdat_symbol_id accordingly. */ + case dw_val_class_loc: + for (loc = AT_loc (at); loc; loc = loc->dw_loc_next) + loc_checksum_ordered (loc, ctx); + break; -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"; - char *name = XALLOCAVEC (char, strlen (base) + 64); - char *p; - int i, mark; - unsigned char checksum[16]; - struct md5_ctx ctx; + case dw_val_class_fde_ref: + case dw_val_class_lbl_id: + case dw_val_class_lineptr: + case dw_val_class_macptr: + break; - /* Compute the checksum of the DIE, then append part of it as hex digits to - the name filename of the unit. */ + case dw_val_class_file: + CHECKSUM_ULEB128 (DW_FORM_string); + CHECKSUM_STRING (AT_file (at)->filename); + break; - md5_init_ctx (&ctx); - mark = 0; - die_checksum (unit_die, &ctx, &mark); + case dw_val_class_data8: + CHECKSUM (at->dw_attr_val.v.val_data8); + break; + + default: + break; + } +} + +struct checksum_attributes +{ + dw_attr_ref at_name; + dw_attr_ref at_type; + dw_attr_ref at_friend; + dw_attr_ref at_accessibility; + dw_attr_ref at_address_class; + dw_attr_ref at_allocated; + dw_attr_ref at_artificial; + dw_attr_ref at_associated; + dw_attr_ref at_binary_scale; + dw_attr_ref at_bit_offset; + dw_attr_ref at_bit_size; + dw_attr_ref at_bit_stride; + dw_attr_ref at_byte_size; + dw_attr_ref at_byte_stride; + dw_attr_ref at_const_value; + dw_attr_ref at_containing_type; + dw_attr_ref at_count; + dw_attr_ref at_data_location; + dw_attr_ref at_data_member_location; + dw_attr_ref at_decimal_scale; + dw_attr_ref at_decimal_sign; + dw_attr_ref at_default_value; + dw_attr_ref at_digit_count; + dw_attr_ref at_discr; + dw_attr_ref at_discr_list; + dw_attr_ref at_discr_value; + dw_attr_ref at_encoding; + dw_attr_ref at_endianity; + dw_attr_ref at_explicit; + dw_attr_ref at_is_optional; + dw_attr_ref at_location; + dw_attr_ref at_lower_bound; + dw_attr_ref at_mutable; + dw_attr_ref at_ordering; + dw_attr_ref at_picture_string; + dw_attr_ref at_prototyped; + dw_attr_ref at_small; + dw_attr_ref at_segment; + dw_attr_ref at_string_length; + dw_attr_ref at_threads_scaled; + dw_attr_ref at_upper_bound; + dw_attr_ref at_use_location; + dw_attr_ref at_use_UTF8; + dw_attr_ref at_variable_parameter; + dw_attr_ref at_virtuality; + dw_attr_ref at_visibility; + dw_attr_ref at_vtable_elem_location; +}; + +/* Collect the attributes that we will want to use for the checksum. */ + +static void +collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die) +{ + dw_attr_ref a; + unsigned ix; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + { + switch (a->dw_attr) + { + case DW_AT_name: + attrs->at_name = a; + break; + case DW_AT_type: + attrs->at_type = a; + break; + case DW_AT_friend: + attrs->at_friend = a; + break; + case DW_AT_accessibility: + attrs->at_accessibility = a; + break; + case DW_AT_address_class: + attrs->at_address_class = a; + break; + case DW_AT_allocated: + attrs->at_allocated = a; + break; + case DW_AT_artificial: + attrs->at_artificial = a; + break; + case DW_AT_associated: + attrs->at_associated = a; + break; + case DW_AT_binary_scale: + attrs->at_binary_scale = a; + break; + case DW_AT_bit_offset: + attrs->at_bit_offset = a; + break; + case DW_AT_bit_size: + attrs->at_bit_size = a; + break; + case DW_AT_bit_stride: + attrs->at_bit_stride = a; + break; + case DW_AT_byte_size: + attrs->at_byte_size = a; + break; + case DW_AT_byte_stride: + attrs->at_byte_stride = a; + break; + case DW_AT_const_value: + attrs->at_const_value = a; + break; + case DW_AT_containing_type: + attrs->at_containing_type = a; + break; + case DW_AT_count: + attrs->at_count = a; + break; + case DW_AT_data_location: + attrs->at_data_location = a; + break; + case DW_AT_data_member_location: + attrs->at_data_member_location = a; + break; + case DW_AT_decimal_scale: + attrs->at_decimal_scale = a; + break; + case DW_AT_decimal_sign: + attrs->at_decimal_sign = a; + break; + case DW_AT_default_value: + attrs->at_default_value = a; + break; + case DW_AT_digit_count: + attrs->at_digit_count = a; + break; + case DW_AT_discr: + attrs->at_discr = a; + break; + case DW_AT_discr_list: + attrs->at_discr_list = a; + break; + case DW_AT_discr_value: + attrs->at_discr_value = a; + break; + case DW_AT_encoding: + attrs->at_encoding = a; + break; + case DW_AT_endianity: + attrs->at_endianity = a; + break; + case DW_AT_explicit: + attrs->at_explicit = a; + break; + case DW_AT_is_optional: + attrs->at_is_optional = a; + break; + case DW_AT_location: + attrs->at_location = a; + break; + case DW_AT_lower_bound: + attrs->at_lower_bound = a; + break; + case DW_AT_mutable: + attrs->at_mutable = a; + break; + case DW_AT_ordering: + attrs->at_ordering = a; + break; + case DW_AT_picture_string: + attrs->at_picture_string = a; + break; + case DW_AT_prototyped: + attrs->at_prototyped = a; + break; + case DW_AT_small: + attrs->at_small = a; + break; + case DW_AT_segment: + attrs->at_segment = a; + break; + case DW_AT_string_length: + attrs->at_string_length = a; + break; + case DW_AT_threads_scaled: + attrs->at_threads_scaled = a; + break; + case DW_AT_upper_bound: + attrs->at_upper_bound = a; + break; + case DW_AT_use_location: + attrs->at_use_location = a; + break; + case DW_AT_use_UTF8: + attrs->at_use_UTF8 = a; + break; + case DW_AT_variable_parameter: + attrs->at_variable_parameter = a; + break; + case DW_AT_virtuality: + attrs->at_virtuality = a; + break; + case DW_AT_visibility: + attrs->at_visibility = a; + break; + case DW_AT_vtable_elem_location: + attrs->at_vtable_elem_location = a; + break; + default: + break; + } + } +} + +/* Calculate the checksum of a DIE, using an ordered subset of attributes. */ + +static void +die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark) +{ + dw_die_ref c; + dw_die_ref decl; + struct checksum_attributes attrs; + + CHECKSUM_ULEB128 ('D'); + CHECKSUM_ULEB128 (die->die_tag); + + memset (&attrs, 0, sizeof (attrs)); + + decl = get_AT_ref (die, DW_AT_specification); + if (decl != NULL) + collect_checksum_attributes (&attrs, decl); + collect_checksum_attributes (&attrs, die); + + CHECKSUM_ATTR (attrs.at_name); + CHECKSUM_ATTR (attrs.at_accessibility); + CHECKSUM_ATTR (attrs.at_address_class); + CHECKSUM_ATTR (attrs.at_allocated); + CHECKSUM_ATTR (attrs.at_artificial); + CHECKSUM_ATTR (attrs.at_associated); + CHECKSUM_ATTR (attrs.at_binary_scale); + CHECKSUM_ATTR (attrs.at_bit_offset); + CHECKSUM_ATTR (attrs.at_bit_size); + CHECKSUM_ATTR (attrs.at_bit_stride); + CHECKSUM_ATTR (attrs.at_byte_size); + CHECKSUM_ATTR (attrs.at_byte_stride); + CHECKSUM_ATTR (attrs.at_const_value); + CHECKSUM_ATTR (attrs.at_containing_type); + CHECKSUM_ATTR (attrs.at_count); + CHECKSUM_ATTR (attrs.at_data_location); + CHECKSUM_ATTR (attrs.at_data_member_location); + CHECKSUM_ATTR (attrs.at_decimal_scale); + CHECKSUM_ATTR (attrs.at_decimal_sign); + CHECKSUM_ATTR (attrs.at_default_value); + CHECKSUM_ATTR (attrs.at_digit_count); + CHECKSUM_ATTR (attrs.at_discr); + CHECKSUM_ATTR (attrs.at_discr_list); + CHECKSUM_ATTR (attrs.at_discr_value); + CHECKSUM_ATTR (attrs.at_encoding); + CHECKSUM_ATTR (attrs.at_endianity); + CHECKSUM_ATTR (attrs.at_explicit); + CHECKSUM_ATTR (attrs.at_is_optional); + CHECKSUM_ATTR (attrs.at_location); + CHECKSUM_ATTR (attrs.at_lower_bound); + CHECKSUM_ATTR (attrs.at_mutable); + CHECKSUM_ATTR (attrs.at_ordering); + CHECKSUM_ATTR (attrs.at_picture_string); + CHECKSUM_ATTR (attrs.at_prototyped); + CHECKSUM_ATTR (attrs.at_small); + CHECKSUM_ATTR (attrs.at_segment); + CHECKSUM_ATTR (attrs.at_string_length); + CHECKSUM_ATTR (attrs.at_threads_scaled); + CHECKSUM_ATTR (attrs.at_upper_bound); + CHECKSUM_ATTR (attrs.at_use_location); + CHECKSUM_ATTR (attrs.at_use_UTF8); + CHECKSUM_ATTR (attrs.at_variable_parameter); + CHECKSUM_ATTR (attrs.at_virtuality); + CHECKSUM_ATTR (attrs.at_visibility); + CHECKSUM_ATTR (attrs.at_vtable_elem_location); + CHECKSUM_ATTR (attrs.at_type); + CHECKSUM_ATTR (attrs.at_friend); + + /* Checksum the child DIEs, except for nested types and member functions. */ + c = die->die_child; + if (c) do { + dw_attr_ref name_attr; + + c = c->die_sib; + name_attr = get_AT (c, DW_AT_name); + if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram) + && name_attr != NULL) + { + CHECKSUM_ULEB128 ('S'); + CHECKSUM_ULEB128 (c->die_tag); + CHECKSUM_STRING (AT_string (name_attr)); + } + else + { + /* Mark this DIE so it gets processed when unmarking. */ + if (c->die_mark == 0) + c->die_mark = -1; + die_checksum_ordered (c, ctx, mark); + } + } while (c != die->die_child); + + CHECKSUM_ULEB128 (0); +} + +#undef CHECKSUM +#undef CHECKSUM_STRING +#undef CHECKSUM_ATTR +#undef CHECKSUM_LEB128 +#undef CHECKSUM_ULEB128 + +/* Generate the type signature for DIE. This is computed by generating an + MD5 checksum over the DIE's tag, its relevant attributes, and its + children. Attributes that are references to other DIEs are processed + by recursion, using the MARK field to prevent infinite recursion. + If the DIE is nested inside a namespace or another type, we also + need to include that context in the signature. The lower 64 bits + of the resulting MD5 checksum comprise the signature. */ + +static void +generate_type_signature (dw_die_ref die, comdat_type_node *type_node) +{ + int mark; + const char *name; + unsigned char checksum[16]; + struct md5_ctx ctx; + dw_die_ref decl; + + name = get_AT_string (die, DW_AT_name); + decl = get_AT_ref (die, DW_AT_specification); + + /* First, compute a signature for just the type name (and its surrounding + context, if any. This is stored in the type unit DIE for link-time + ODR (one-definition rule) checking. */ + + if (is_cxx() && name != NULL) + { + md5_init_ctx (&ctx); + + /* Checksum the names of surrounding namespaces and structures. */ + if (decl != NULL && decl->die_parent != NULL) + checksum_die_context (decl->die_parent, &ctx); + + md5_process_bytes (&die->die_tag, sizeof (die->die_tag), &ctx); + md5_process_bytes (name, strlen (name) + 1, &ctx); + md5_finish_ctx (&ctx, checksum); + + add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]); + } + + /* Next, compute the complete type signature. */ + + md5_init_ctx (&ctx); + mark = 1; + die->die_mark = mark; + + /* Checksum the names of surrounding namespaces and structures. */ + if (decl != NULL && decl->die_parent != NULL) + checksum_die_context (decl->die_parent, &ctx); + + /* Checksum the DIE and its children. */ + die_checksum_ordered (die, &ctx, &mark); + unmark_all_dies (die); + md5_finish_ctx (&ctx, checksum); + + /* Store the signature in the type node and link the type DIE and the + type node together. */ + memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE], + DWARF_TYPE_SIGNATURE_SIZE); + die->die_id.die_type_node = type_node; + type_node->type_die = die; + + /* If the DIE is a specification, link its declaration to the type node + as well. */ + if (decl != NULL) + decl->die_id.die_type_node = type_node; +} + +/* Do the location expressions look same? */ +static inline int +same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark) +{ + return loc1->dw_loc_opc == loc2->dw_loc_opc + && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark) + && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark); +} + +/* Do the values look the same? */ +static int +same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark) +{ + dw_loc_descr_ref loc1, loc2; + rtx r1, r2; + + if (v1->val_class != v2->val_class) + return 0; + + switch (v1->val_class) + { + case dw_val_class_const: + return v1->v.val_int == v2->v.val_int; + case dw_val_class_unsigned_const: + return v1->v.val_unsigned == v2->v.val_unsigned; + case dw_val_class_const_double: + return v1->v.val_double.high == v2->v.val_double.high + && v1->v.val_double.low == v2->v.val_double.low; + case dw_val_class_vec: + if (v1->v.val_vec.length != v2->v.val_vec.length + || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size) + return 0; + if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array, + v1->v.val_vec.length * v1->v.val_vec.elt_size)) + return 0; + return 1; + case dw_val_class_flag: + return v1->v.val_flag == v2->v.val_flag; + case dw_val_class_str: + return !strcmp(v1->v.val_str->str, v2->v.val_str->str); + + case dw_val_class_addr: + r1 = v1->v.val_addr; + r2 = v2->v.val_addr; + if (GET_CODE (r1) != GET_CODE (r2)) + return 0; + return !rtx_equal_p (r1, r2); + + case dw_val_class_offset: + return v1->v.val_offset == v2->v.val_offset; + + case dw_val_class_loc: + for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc; + loc1 && loc2; + loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next) + if (!same_loc_p (loc1, loc2, mark)) + return 0; + return !loc1 && !loc2; + + case dw_val_class_die_ref: + return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark); + + case dw_val_class_fde_ref: + case dw_val_class_lbl_id: + case dw_val_class_lineptr: + case dw_val_class_macptr: + return 1; + + case dw_val_class_file: + return v1->v.val_file == v2->v.val_file; + + case dw_val_class_data8: + return !memcmp (v1->v.val_data8, v2->v.val_data8, 8); + + default: + return 1; + } +} + +/* Do the attributes look the same? */ + +static int +same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark) +{ + if (at1->dw_attr != at2->dw_attr) + return 0; + + /* We don't care that this was compiled with a different compiler + snapshot; if the output is the same, that's what matters. */ + if (at1->dw_attr == DW_AT_producer) + return 1; + + return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark); +} + +/* Do the dies look the same? */ + +static int +same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark) +{ + dw_die_ref c1, c2; + dw_attr_ref a1; + unsigned ix; + + /* To avoid infinite recursion. */ + if (die1->die_mark) + return die1->die_mark == die2->die_mark; + die1->die_mark = die2->die_mark = ++(*mark); + + if (die1->die_tag != die2->die_tag) + return 0; + + if (VEC_length (dw_attr_node, die1->die_attr) + != VEC_length (dw_attr_node, die2->die_attr)) + return 0; + + for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++) + if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark)) + return 0; + + c1 = die1->die_child; + c2 = die2->die_child; + if (! c1) + { + if (c2) + return 0; + } + else + for (;;) + { + if (!same_die_p (c1, c2, mark)) + return 0; + c1 = c1->die_sib; + c2 = c2->die_sib; + if (c1 == die1->die_child) + { + if (c2 == die2->die_child) + break; + else + return 0; + } + } + + return 1; +} + +/* Do the dies look the same? Wrapper around same_die_p. */ + +static int +same_die_p_wrap (dw_die_ref die1, dw_die_ref die2) +{ + int mark = 0; + int ret = same_die_p (die1, die2, &mark); + + unmark_all_dies (die1); + unmark_all_dies (die2); + + return ret; +} + +/* The prefix to attach to symbols on DIEs in the current comdat debug + info section. */ +static char *comdat_symbol_id; + +/* The index of the current symbol within the current comdat CU. */ +static unsigned int comdat_symbol_number; + +/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its + 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"; + char *name = XALLOCAVEC (char, strlen (base) + 64); + char *p; + int i, mark; + unsigned char checksum[16]; + struct md5_ctx ctx; + + /* Compute the checksum of the DIE, then append part of it as hex digits to + the name filename of the unit. */ + + md5_init_ctx (&ctx); + mark = 0; + die_checksum (unit_die, &ctx, &mark); unmark_all_dies (unit_die); md5_finish_ctx (&ctx, checksum); - sprintf (name, "%s.", base); - clean_symbol_name (name); + sprintf (name, "%s.", base); + clean_symbol_name (name); + + p = name + strlen (name); + for (i = 0; i < 4; i++) + { + sprintf (p, "%.2x", checksum[i]); + p += 2; + } + + comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name); + comdat_symbol_number = 0; +} + +/* Returns nonzero if DIE represents a type, in the sense of TYPE_P. */ + +static int +is_type_die (dw_die_ref die) +{ + switch (die->die_tag) + { + case DW_TAG_array_type: + case DW_TAG_class_type: + case DW_TAG_interface_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subroutine_type: + case DW_TAG_union_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_set_type: + case DW_TAG_subrange_type: + case DW_TAG_base_type: + case DW_TAG_const_type: + case DW_TAG_file_type: + case DW_TAG_packed_type: + case DW_TAG_volatile_type: + case DW_TAG_typedef: + return 1; + default: + return 0; + } +} + +/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU. + Basically, we want to choose the bits that are likely to be shared between + compilations (types) and leave out the bits that are specific to individual + compilations (functions). */ + +static int +is_comdat_die (dw_die_ref c) +{ + /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as + we do for stabs. The advantage is a greater likelihood of sharing between + objects that don't include headers in the same order (and therefore would + put the base types in a different comdat). jason 8/28/00 */ + + if (c->die_tag == DW_TAG_base_type) + return 0; + + if (c->die_tag == DW_TAG_pointer_type + || c->die_tag == DW_TAG_reference_type + || c->die_tag == DW_TAG_const_type + || c->die_tag == DW_TAG_volatile_type) + { + dw_die_ref t = get_AT_ref (c, DW_AT_type); + + return t ? is_comdat_die (t) : 0; + } + + return is_type_die (c); +} + +/* Returns 1 iff C is the sort of DIE that might be referred to from another + compilation unit. */ + +static int +is_symbol_die (dw_die_ref c) +{ + return (is_type_die (c) + || is_declaration_die (c) + || c->die_tag == DW_TAG_namespace + || c->die_tag == DW_TAG_module); +} + +static char * +gen_internal_sym (const char *prefix) +{ + char buf[256]; + + ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++); + return xstrdup (buf); +} + +/* Assign symbols to all worthy DIEs under DIE. */ + +static void +assign_symbol_names (dw_die_ref die) +{ + dw_die_ref c; + + if (is_symbol_die (die)) + { + if (comdat_symbol_id) + { + char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64); + + sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX, + comdat_symbol_id, comdat_symbol_number++); + die->die_id.die_symbol = xstrdup (p); + } + else + die->die_id.die_symbol = gen_internal_sym ("LDIE"); + } + + FOR_EACH_CHILD (die, c, assign_symbol_names (c)); +} + +struct cu_hash_table_entry +{ + dw_die_ref cu; + unsigned min_comdat_num, max_comdat_num; + struct cu_hash_table_entry *next; +}; + +/* Routines to manipulate hash table of CUs. */ +static hashval_t +htab_cu_hash (const void *of) +{ + const struct cu_hash_table_entry *const entry = + (const struct cu_hash_table_entry *) of; + + return htab_hash_string (entry->cu->die_id.die_symbol); +} + +static int +htab_cu_eq (const void *of1, const void *of2) +{ + const struct cu_hash_table_entry *const entry1 = + (const struct cu_hash_table_entry *) of1; + const struct die_struct *const entry2 = (const struct die_struct *) of2; + + return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol); +} + +static void +htab_cu_del (void *what) +{ + struct cu_hash_table_entry *next, + *entry = (struct cu_hash_table_entry *) what; + + while (entry) + { + next = entry->next; + free (entry); + entry = next; + } +} + +/* Check whether we have already seen this CU and set up SYM_NUM + accordingly. */ +static int +check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num) +{ + struct cu_hash_table_entry dummy; + struct cu_hash_table_entry **slot, *entry, *last = &dummy; + + dummy.max_comdat_num = 0; + + slot = (struct cu_hash_table_entry **) + htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol), + INSERT); + entry = *slot; + + for (; entry; last = entry, entry = entry->next) + { + if (same_die_p_wrap (cu, entry->cu)) + break; + } + + if (entry) + { + *sym_num = entry->min_comdat_num; + return 1; + } + + entry = XCNEW (struct cu_hash_table_entry); + entry->cu = cu; + entry->min_comdat_num = *sym_num = last->max_comdat_num; + entry->next = *slot; + *slot = entry; + + return 0; +} + +/* Record SYM_NUM to record of CU in HTABLE. */ +static void +record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num) +{ + struct cu_hash_table_entry **slot, *entry; + + slot = (struct cu_hash_table_entry **) + htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol), + NO_INSERT); + entry = *slot; + + entry->max_comdat_num = sym_num; +} + +/* Traverse the DIE (which is always comp_unit_die), and set up + additional compilation units for each of the include files we see + bracketed by BINCL/EINCL. */ + +static void +break_out_includes (dw_die_ref die) +{ + dw_die_ref c; + dw_die_ref unit = NULL; + limbo_die_node *node, **pnode; + htab_t cu_hash_table; + + c = die->die_child; + if (c) do { + dw_die_ref prev = c; + c = c->die_sib; + while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL + || (unit && is_comdat_die (c))) + { + dw_die_ref next = c->die_sib; + + /* This DIE is for a secondary CU; remove it from the main one. */ + remove_child_with_prev (c, prev); + + if (c->die_tag == DW_TAG_GNU_BINCL) + unit = push_new_compile_unit (unit, c); + else if (c->die_tag == DW_TAG_GNU_EINCL) + unit = pop_compile_unit (unit); + else + add_child_die (unit, c); + c = next; + if (c == die->die_child) + break; + } + } while (c != die->die_child); + +#if 0 + /* We can only use this in debugging, since the frontend doesn't check + to make sure that we leave every include file we enter. */ + gcc_assert (!unit); +#endif - p = name + strlen (name); - for (i = 0; i < 4; i++) + assign_symbol_names (die); + cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del); + for (node = limbo_die_list, pnode = &limbo_die_list; + node; + node = node->next) { - sprintf (p, "%.2x", checksum[i]); - p += 2; + int is_dupl; + + compute_section_prefix (node->die); + is_dupl = check_duplicate_cu (node->die, cu_hash_table, + &comdat_symbol_number); + assign_symbol_names (node->die); + if (is_dupl) + *pnode = node->next; + else + { + pnode = &node->next; + record_comdat_symbol_number (node->die, cu_hash_table, + comdat_symbol_number); + } } + htab_delete (cu_hash_table); +} - comdat_symbol_id = unit_die->die_symbol = xstrdup (name); - comdat_symbol_number = 0; +/* Return non-zero if this DIE is a declaration. */ + +static int +is_declaration_die (dw_die_ref die) +{ + dw_attr_ref a; + unsigned ix; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + if (a->dw_attr == DW_AT_declaration) + return 1; + + return 0; } -/* Returns nonzero if DIE represents a type, in the sense of TYPE_P. */ +/* Return non-zero if this is a type DIE that should be moved to a + COMDAT .debug_types section. */ static int -is_type_die (dw_die_ref die) +should_move_die_to_comdat (dw_die_ref die) { switch (die->die_tag) { - case DW_TAG_array_type: case DW_TAG_class_type: - case DW_TAG_interface_type: + case DW_TAG_structure_type: case DW_TAG_enumeration_type: + case DW_TAG_union_type: + /* Don't move declarations or inlined instances. */ + if (is_declaration_die (die) || get_AT (die, DW_AT_abstract_origin)) + return 0; + return 1; + case DW_TAG_array_type: + case DW_TAG_interface_type: case DW_TAG_pointer_type: case DW_TAG_reference_type: case DW_TAG_string_type: - case DW_TAG_structure_type: case DW_TAG_subroutine_type: - case DW_TAG_union_type: case DW_TAG_ptr_to_member_type: case DW_TAG_set_type: case DW_TAG_subrange_type: @@ -7930,242 +9265,497 @@ is_type_die (dw_die_ref die) case DW_TAG_packed_type: case DW_TAG_volatile_type: case DW_TAG_typedef: - return 1; default: return 0; } } -/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU. - Basically, we want to choose the bits that are likely to be shared between - compilations (types) and leave out the bits that are specific to individual - compilations (functions). */ +/* Make a clone of DIE. */ -static int -is_comdat_die (dw_die_ref c) +static dw_die_ref +clone_die (dw_die_ref die) { - /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as - we do for stabs. The advantage is a greater likelihood of sharing between - objects that don't include headers in the same order (and therefore would - put the base types in a different comdat). jason 8/28/00 */ + dw_die_ref clone; + dw_attr_ref a; + unsigned ix; - if (c->die_tag == DW_TAG_base_type) - return 0; + clone = GGC_CNEW (die_node); + clone->die_tag = die->die_tag; - if (c->die_tag == DW_TAG_pointer_type - || c->die_tag == DW_TAG_reference_type - || c->die_tag == DW_TAG_const_type - || c->die_tag == DW_TAG_volatile_type) + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + add_dwarf_attr (clone, a); + + return clone; +} + +/* Make a clone of the tree rooted at DIE. */ + +static dw_die_ref +clone_tree (dw_die_ref die) +{ + dw_die_ref c; + dw_die_ref clone = clone_die (die); + + FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c))); + + return clone; +} + +/* Make a clone of DIE as a declaration. */ + +static dw_die_ref +clone_as_declaration (dw_die_ref die) +{ + dw_die_ref clone; + dw_die_ref decl; + dw_attr_ref a; + unsigned ix; + + /* If the DIE is already a declaration, just clone it. */ + if (is_declaration_die (die)) + return clone_die (die); + + /* If the DIE is a specification, just clone its declaration DIE. */ + decl = get_AT_ref (die, DW_AT_specification); + if (decl != NULL) + return clone_die (decl); + + clone = GGC_CNEW (die_node); + clone->die_tag = die->die_tag; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) { - dw_die_ref t = get_AT_ref (c, DW_AT_type); + /* We don't want to copy over all attributes. + For example we don't want DW_AT_byte_size because otherwise we will no + longer have a declaration and GDB will treat it as a definition. */ - return t ? is_comdat_die (t) : 0; + switch (a->dw_attr) + { + case DW_AT_artificial: + case DW_AT_containing_type: + case DW_AT_external: + case DW_AT_name: + case DW_AT_type: + case DW_AT_virtuality: + case DW_AT_MIPS_linkage_name: + add_dwarf_attr (clone, a); + break; + case DW_AT_byte_size: + default: + break; + } } - return is_type_die (c); + if (die->die_id.die_type_node) + add_AT_die_ref (clone, DW_AT_signature, die); + + add_AT_flag (clone, DW_AT_declaration, 1); + return clone; } -/* Returns 1 iff C is the sort of DIE that might be referred to from another - compilation unit. */ +/* Copy the declaration context to the new compile unit DIE. This includes + any surrounding namespace or type declarations. If the DIE has an + AT_specification attribute, it also includes attributes and children + attached to the specification. */ -static int -is_symbol_die (dw_die_ref c) +static void +copy_declaration_context (dw_die_ref unit, dw_die_ref die) { - return (is_type_die (c) - || (get_AT (c, DW_AT_declaration) - && !get_AT (c, DW_AT_specification)) - || c->die_tag == DW_TAG_namespace - || c->die_tag == DW_TAG_module); + dw_die_ref decl; + dw_die_ref new_decl; + + decl = get_AT_ref (die, DW_AT_specification); + if (decl == NULL) + decl = die; + else + { + unsigned ix; + dw_die_ref c; + dw_attr_ref a; + + /* Copy the type node pointer from the new DIE to the original + declaration DIE so we can forward references later. */ + decl->die_id.die_type_node = die->die_id.die_type_node; + + remove_AT (die, DW_AT_specification); + + for (ix = 0; VEC_iterate (dw_attr_node, decl->die_attr, ix, a); ix++) + { + if (a->dw_attr != DW_AT_name + && a->dw_attr != DW_AT_declaration + && a->dw_attr != DW_AT_external) + add_dwarf_attr (die, a); + } + + FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree(c))); + } + + if (decl->die_parent != NULL + && decl->die_parent->die_tag != DW_TAG_compile_unit + && decl->die_parent->die_tag != DW_TAG_type_unit) + { + new_decl = copy_ancestor_tree (unit, decl, NULL); + if (new_decl != NULL) + { + remove_AT (new_decl, DW_AT_signature); + add_AT_specification (die, new_decl); + } + } } -static char * -gen_internal_sym (const char *prefix) +/* Generate the skeleton ancestor tree for the given NODE, then clone + the DIE and add the clone into the tree. */ + +static void +generate_skeleton_ancestor_tree (skeleton_chain_node *node) { - char buf[256]; + if (node->new_die != NULL) + return; - ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++); - return xstrdup (buf); + node->new_die = clone_as_declaration (node->old_die); + + if (node->parent != NULL) + { + generate_skeleton_ancestor_tree (node->parent); + add_child_die (node->parent->new_die, node->new_die); + } } -/* Assign symbols to all worthy DIEs under DIE. */ +/* Generate a skeleton tree of DIEs containing any declarations that are + found in the original tree. We traverse the tree looking for declaration + DIEs, and construct the skeleton from the bottom up whenever we find one. */ static void -assign_symbol_names (dw_die_ref die) +generate_skeleton_bottom_up (skeleton_chain_node *parent) { + skeleton_chain_node node; dw_die_ref c; + dw_die_ref first; + dw_die_ref prev = NULL; + dw_die_ref next = NULL; - if (is_symbol_die (die)) - { - if (comdat_symbol_id) - { - char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64); + node.parent = parent; - sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX, - comdat_symbol_id, comdat_symbol_number++); - die->die_symbol = xstrdup (p); - } - else - die->die_symbol = gen_internal_sym ("LDIE"); + first = c = parent->old_die->die_child; + if (c) + next = c->die_sib; + if (c) do { + if (prev == NULL || prev->die_sib == c) + prev = c; + c = next; + next = (c == first ? NULL : c->die_sib); + node.old_die = c; + node.new_die = NULL; + if (is_declaration_die (c)) + { + /* Clone the existing DIE, move the original to the skeleton + tree (which is in the main CU), and put the clone, with + all the original's children, where the original came from. */ + dw_die_ref clone = clone_die (c); + move_all_children (c, clone); + + replace_child (c, clone, prev); + generate_skeleton_ancestor_tree (parent); + add_child_die (parent->new_die, c); + node.new_die = c; + c = clone; + } + generate_skeleton_bottom_up (&node); + } while (next != NULL); +} + +/* Wrapper function for generate_skeleton_bottom_up. */ + +static dw_die_ref +generate_skeleton (dw_die_ref die) +{ + skeleton_chain_node node; + + node.old_die = die; + node.new_die = NULL; + node.parent = NULL; + + /* If this type definition is nested inside another type, + always leave at least a declaration in its place. */ + if (die->die_parent != NULL && is_type_die (die->die_parent)) + node.new_die = clone_as_declaration (die); + + generate_skeleton_bottom_up (&node); + return node.new_die; +} + +/* Remove the DIE from its parent, possibly replacing it with a cloned + declaration. The original DIE will be moved to a new compile unit + so that existing references to it follow it to the new location. If + any of the original DIE's descendants is a declaration, we need to + replace the original DIE with a skeleton tree and move the + declarations back into the skeleton tree. */ + +static dw_die_ref +remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev) +{ + dw_die_ref skeleton; + + skeleton = generate_skeleton (child); + if (skeleton == NULL) + remove_child_with_prev (child, prev); + else + { + skeleton->die_id.die_type_node = child->die_id.die_type_node; + replace_child (child, skeleton, prev); } - FOR_EACH_CHILD (die, c, assign_symbol_names (c)); + return skeleton; } -struct cu_hash_table_entry +/* Traverse the DIE and set up additional .debug_types sections for each + type worthy of being placed in a COMDAT section. */ + +static void +break_out_comdat_types (dw_die_ref die) { - dw_die_ref cu; - unsigned min_comdat_num, max_comdat_num; - struct cu_hash_table_entry *next; + dw_die_ref c; + dw_die_ref first; + dw_die_ref prev = NULL; + dw_die_ref next = NULL; + dw_die_ref unit = NULL; + + first = c = die->die_child; + if (c) + next = c->die_sib; + if (c) do { + if (prev == NULL || prev->die_sib == c) + prev = c; + c = next; + next = (c == first ? NULL : c->die_sib); + if (should_move_die_to_comdat (c)) + { + dw_die_ref replacement; + comdat_type_node_ref type_node; + + /* Create a new type unit DIE as the root for the new tree, and + add it to the list of comdat types. */ + unit = new_die (DW_TAG_type_unit, NULL, NULL); + add_AT_unsigned (unit, DW_AT_language, + get_AT_unsigned (comp_unit_die, DW_AT_language)); + type_node = GGC_CNEW (comdat_type_node); + type_node->root_die = unit; + type_node->next = comdat_type_list; + comdat_type_list = type_node; + + /* Generate the type signature. */ + generate_type_signature (c, type_node); + + /* Copy the declaration context, attributes, and children of the + declaration into the new compile unit DIE. */ + copy_declaration_context (unit, c); + + /* Remove this DIE from the main CU. */ + replacement = remove_child_or_replace_with_skeleton (c, prev); + + /* Break out nested types into their own type units. */ + break_out_comdat_types (c); + + /* Add the DIE to the new compunit. */ + add_child_die (unit, c); + + if (replacement != NULL) + c = replacement; + } + else if (c->die_tag == DW_TAG_namespace + || c->die_tag == DW_TAG_class_type + || c->die_tag == DW_TAG_structure_type + || c->die_tag == DW_TAG_union_type) + { + /* Look for nested types that can be broken out. */ + break_out_comdat_types (c); + } + } while (next != NULL); +} + +/* Structure to map a DIE in one CU to its copy in a comdat type unit. */ + +struct decl_table_entry +{ + dw_die_ref orig; + dw_die_ref copy; }; -/* Routines to manipulate hash table of CUs. */ +/* Routines to manipulate hash table of copied declarations. */ + static hashval_t -htab_cu_hash (const void *of) +htab_decl_hash (const void *of) { - const struct cu_hash_table_entry *const entry = - (const struct cu_hash_table_entry *) of; + const struct decl_table_entry *const entry = + (const struct decl_table_entry *) of; - return htab_hash_string (entry->cu->die_symbol); + return htab_hash_pointer (entry->orig); } static int -htab_cu_eq (const void *of1, const void *of2) +htab_decl_eq (const void *of1, const void *of2) { - const struct cu_hash_table_entry *const entry1 = - (const struct cu_hash_table_entry *) of1; + const struct decl_table_entry *const entry1 = + (const struct decl_table_entry *) of1; const struct die_struct *const entry2 = (const struct die_struct *) of2; - return !strcmp (entry1->cu->die_symbol, entry2->die_symbol); + return entry1->orig == entry2; } static void -htab_cu_del (void *what) +htab_decl_del (void *what) { - struct cu_hash_table_entry *next, - *entry = (struct cu_hash_table_entry *) what; + struct decl_table_entry *entry = (struct decl_table_entry *) what; - while (entry) - { - next = entry->next; - free (entry); - entry = next; - } + free (entry); } -/* Check whether we have already seen this CU and set up SYM_NUM - accordingly. */ -static int -check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num) -{ - struct cu_hash_table_entry dummy; - struct cu_hash_table_entry **slot, *entry, *last = &dummy; - - dummy.max_comdat_num = 0; +/* 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. */ - slot = (struct cu_hash_table_entry **) - htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol), - INSERT); - entry = *slot; +static dw_die_ref +copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table) +{ + dw_die_ref parent = die->die_parent; + dw_die_ref new_parent = unit; + dw_die_ref copy; + void **slot = NULL; + struct decl_table_entry *entry = NULL; - for (; entry; last = entry, entry = entry->next) + if (decl_table) { - if (same_die_p_wrap (cu, entry->cu)) - break; + /* Check if the entry has already been copied to UNIT. */ + slot = htab_find_slot_with_hash (decl_table, die, + htab_hash_pointer (die), INSERT); + if (*slot != HTAB_EMPTY_ENTRY) + { + entry = (struct decl_table_entry *) *slot; + return entry->copy; + } + + /* Record in DECL_TABLE that DIE has been copied to UNIT. */ + entry = XCNEW (struct decl_table_entry); + entry->orig = die; + entry->copy = NULL; + *slot = entry; } - if (entry) + if (parent != NULL) { - *sym_num = entry->min_comdat_num; - return 1; + dw_die_ref spec = get_AT_ref (parent, DW_AT_specification); + if (spec != NULL) + parent = spec; + if (parent->die_tag != DW_TAG_compile_unit + && parent->die_tag != DW_TAG_type_unit) + new_parent = copy_ancestor_tree (unit, parent, decl_table); } - entry = XCNEW (struct cu_hash_table_entry); - entry->cu = cu; - entry->min_comdat_num = *sym_num = last->max_comdat_num; - entry->next = *slot; - *slot = entry; - - return 0; -} - -/* Record SYM_NUM to record of CU in HTABLE. */ -static void -record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num) -{ - struct cu_hash_table_entry **slot, *entry; + copy = clone_as_declaration (die); + add_child_die (new_parent, copy); - slot = (struct cu_hash_table_entry **) - htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol), - NO_INSERT); - entry = *slot; + if (decl_table != NULL) + { + /* Make sure the copy is marked as part of the type unit. */ + copy->die_mark = 1; + /* Record the pointer to the copy. */ + entry->copy = copy; + } - entry->max_comdat_num = sym_num; + return copy; } -/* Traverse the DIE (which is always comp_unit_die), and set up - additional compilation units for each of the include files we see - bracketed by BINCL/EINCL. */ +/* Walk the DIE and its children, looking for references to incomplete + or trivial types that are unmarked (i.e., that are not in the current + type_unit). */ static void -break_out_includes (dw_die_ref die) +copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table) { dw_die_ref c; - dw_die_ref unit = NULL; - limbo_die_node *node, **pnode; - htab_t cu_hash_table; + dw_attr_ref a; + unsigned ix; - c = die->die_child; - if (c) do { - dw_die_ref prev = c; - c = c->die_sib; - while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL - || (unit && is_comdat_die (c))) - { - dw_die_ref next = c->die_sib; + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + { + if (AT_class (a) == dw_val_class_die_ref) + { + dw_die_ref targ = AT_ref (a); + comdat_type_node_ref type_node = targ->die_id.die_type_node; + void **slot; + struct decl_table_entry *entry; - /* This DIE is for a secondary CU; remove it from the main one. */ - remove_child_with_prev (c, prev); + if (targ->die_mark != 0 || type_node != NULL) + continue; - if (c->die_tag == DW_TAG_GNU_BINCL) - unit = push_new_compile_unit (unit, c); - else if (c->die_tag == DW_TAG_GNU_EINCL) - unit = pop_compile_unit (unit); - else - add_child_die (unit, c); - c = next; - if (c == die->die_child) - break; - } - } while (c != die->die_child); + slot = htab_find_slot_with_hash (decl_table, targ, + htab_hash_pointer (targ), INSERT); -#if 0 - /* We can only use this in debugging, since the frontend doesn't check - to make sure that we leave every include file we enter. */ - gcc_assert (!unit); -#endif + if (*slot != HTAB_EMPTY_ENTRY) + { + /* TARG has already been copied, so we just need to + modify the reference to point to the copy. */ + entry = (struct decl_table_entry *) *slot; + a->dw_attr_val.v.val_die_ref.die = entry->copy; + } + else + { + dw_die_ref parent = unit; + dw_die_ref copy = clone_tree (targ); + + /* Make sure the cloned tree is marked as part of the + type unit. */ + mark_dies (copy); + + /* Record in DECL_TABLE that TARG has been copied. + Need to do this now, before the recursive call, + because DECL_TABLE may be expanded and SLOT + would no longer be a valid pointer. */ + entry = XCNEW (struct decl_table_entry); + entry->orig = targ; + entry->copy = copy; + *slot = entry; + + /* If TARG has surrounding context, copy its ancestor tree + into the new type unit. */ + if (targ->die_parent != NULL + && targ->die_parent->die_tag != DW_TAG_compile_unit + && targ->die_parent->die_tag != DW_TAG_type_unit) + parent = copy_ancestor_tree (unit, targ->die_parent, + decl_table); + + add_child_die (parent, copy); + a->dw_attr_val.v.val_die_ref.die = copy; + + /* Make sure the newly-copied DIE is walked. If it was + installed in a previously-added context, it won't + get visited otherwise. */ + if (parent != unit) + copy_decls_walk (unit, parent, decl_table); + } + } + } - assign_symbol_names (die); - cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del); - for (node = limbo_die_list, pnode = &limbo_die_list; - node; - node = node->next) - { - int is_dupl; + FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table)); +} - compute_section_prefix (node->die); - is_dupl = check_duplicate_cu (node->die, cu_hash_table, - &comdat_symbol_number); - assign_symbol_names (node->die); - if (is_dupl) - *pnode = node->next; - else - { - pnode = &node->next; - record_comdat_symbol_number (node->die, cu_hash_table, - comdat_symbol_number); - } - } - htab_delete (cu_hash_table); +/* Copy declarations for "unworthy" types into the new comdat section. + Incomplete types, modified types, and certain other types aren't broken + out into comdat sections of their own, so they don't have a signature, + and we need to copy the declaration into the same section so that we + don't have an external reference. */ + +static void +copy_decls_for_unworthy_types (dw_die_ref unit) +{ + htab_t decl_table; + + mark_dies (unit); + decl_table = htab_create (10, htab_decl_hash, htab_decl_eq, htab_decl_del); + copy_decls_walk (unit, unit, decl_table); + htab_delete (decl_table); + unmark_dies (unit); } /* Traverse the DIE and add a sibling attribute if it may have the @@ -8222,7 +9812,7 @@ build_abbrev_table (dw_die_ref die) if (AT_class (a) == dw_val_class_die_ref && AT_ref (a)->die_mark == 0) { - gcc_assert (AT_ref (a)->die_symbol); + gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol); set_AT_ref_external (a, 1); } @@ -8337,8 +9927,10 @@ size_of_die (dw_die_ref die) case dw_val_class_unsigned_const: size += constant_size (AT_unsigned (a)); break; - case dw_val_class_long_long: - size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */ + case dw_val_class_const_double: + size += 2 * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; + if (HOST_BITS_PER_WIDE_INT >= 64) + size++; /* block */ break; case dw_val_class_vec: size += constant_size (a->dw_attr_val.v.val_vec.length @@ -8350,10 +9942,19 @@ size_of_die (dw_die_ref die) size += 1; break; case dw_val_class_die_ref: - /* In DWARF2, DW_FORM_ref_addr is sized by target address length, - whereas in DWARF3 it's always sized as an offset. */ - if (AT_ref_external (a) && dwarf_version == 2) - size += DWARF2_ADDR_SIZE; + if (AT_ref_external (a)) + { + /* In DWARF4, we use DW_FORM_sig8; for earlier versions + we use DW_FORM_ref_addr. In DWARF2, DW_FORM_ref_addr + is sized by target address length, whereas in DWARF3 + it's always sized as an offset. */ + if (dwarf_version >= 4) + size += DWARF_TYPE_SIGNATURE_SIZE; + else if (dwarf_version == 2) + size += DWARF2_ADDR_SIZE; + else + size += DWARF_OFFSET_SIZE; + } else size += DWARF_OFFSET_SIZE; break; @@ -8376,6 +9977,9 @@ size_of_die (dw_die_ref die) case dw_val_class_file: size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)); break; + case dw_val_class_data8: + size += 8; + break; default: gcc_unreachable (); } @@ -8427,7 +10031,8 @@ unmark_dies (dw_die_ref die) { dw_die_ref c; - gcc_assert (die->die_mark); + if (dwarf_version < 4) + gcc_assert (die->die_mark); die->die_mark = 0; FOR_EACH_CHILD (die, c, unmark_dies (c)); @@ -8503,7 +10108,30 @@ value_format (dw_attr_ref a) switch (a->dw_attr_val.val_class) { case dw_val_class_addr: - return DW_FORM_addr; + /* Only very few attributes allow DW_FORM_addr. */ + switch (a->dw_attr) + { + case DW_AT_low_pc: + case DW_AT_high_pc: + case DW_AT_entry_pc: + case DW_AT_trampoline: + return DW_FORM_addr; + default: + break; + } + switch (DWARF2_ADDR_SIZE) + { + case 1: + return DW_FORM_data1; + case 2: + return DW_FORM_data2; + case 4: + return DW_FORM_data4; + case 8: + return DW_FORM_data8; + default: + gcc_unreachable (); + } case dw_val_class_range_list: case dw_val_class_offset: case dw_val_class_loc_list: @@ -8542,8 +10170,19 @@ value_format (dw_attr_ref a) default: gcc_unreachable (); } - case dw_val_class_long_long: - return DW_FORM_block1; + case dw_val_class_const_double: + switch (HOST_BITS_PER_WIDE_INT) + { + case 8: + return DW_FORM_data2; + case 16: + return DW_FORM_data4; + case 32: + return DW_FORM_data8; + case 64: + default: + return DW_FORM_block1; + } case dw_val_class_vec: switch (constant_size (a->dw_attr_val.v.val_vec.length * a->dw_attr_val.v.val_vec.elt_size)) @@ -8561,7 +10200,7 @@ value_format (dw_attr_ref a) return DW_FORM_flag; case dw_val_class_die_ref: if (AT_ref_external (a)) - return DW_FORM_ref_addr; + return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr; else return DW_FORM_ref; case dw_val_class_fde_ref: @@ -8586,6 +10225,9 @@ value_format (dw_attr_ref a) gcc_unreachable (); } + case dw_val_class_data8: + return DW_FORM_data8; + default: gcc_unreachable (); } @@ -8645,7 +10287,7 @@ output_abbrev_section (void) static inline void output_die_symbol (dw_die_ref die) { - char *sym = die->die_symbol; + char *sym = die->die_id.die_symbol; if (sym == 0) return; @@ -8747,6 +10389,17 @@ output_loc_list (dw_loc_list_ref list_head) list_head->ll_symbol); } +/* Output a type signature. */ + +static inline void +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], i == 0 ? "%s" : NULL, name); +} + /* Output the DIE and its attributes. Called recursively to generate the definitions of each child DIE. */ @@ -8760,7 +10413,7 @@ output_die (dw_die_ref die) /* If someone in another CU might refer to us, set up a symbol for them to point to. */ - if (die->die_symbol) + if (dwarf_version < 4 && die->die_id.die_symbol) output_die_symbol (die); dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)", @@ -8815,28 +10468,30 @@ output_die (dw_die_ref die) AT_unsigned (a), "%s", name); break; - case dw_val_class_long_long: + case dw_val_class_const_double: { unsigned HOST_WIDE_INT first, second; - dw2_asm_output_data (1, - 2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR, - "%s", name); + if (HOST_BITS_PER_WIDE_INT >= 64) + dw2_asm_output_data (1, + 2 * HOST_BITS_PER_WIDE_INT + / HOST_BITS_PER_CHAR, + NULL); if (WORDS_BIG_ENDIAN) { - first = a->dw_attr_val.v.val_long_long.hi; - second = a->dw_attr_val.v.val_long_long.low; + first = a->dw_attr_val.v.val_double.high; + second = a->dw_attr_val.v.val_double.low; } else { - first = a->dw_attr_val.v.val_long_long.low; - second = a->dw_attr_val.v.val_long_long.hi; + first = a->dw_attr_val.v.val_double.low; + second = a->dw_attr_val.v.val_double.high; } - dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR, - first, "long long constant"); - dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR, + dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR, + first, name); + dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR, second, NULL); } break; @@ -8880,18 +10535,30 @@ output_die (dw_die_ref die) case dw_val_class_die_ref: if (AT_ref_external (a)) { - char *sym = AT_ref (a)->die_symbol; - int size; - - gcc_assert (sym); + if (dwarf_version >= 4) + { + comdat_type_node_ref type_node = + AT_ref (a)->die_id.die_type_node; - /* In DWARF2, DW_FORM_ref_addr is sized by target address - length, whereas in DWARF3 it's always sized as an offset. */ - if (dwarf_version == 2) - size = DWARF2_ADDR_SIZE; + gcc_assert (type_node); + output_signature (type_node->signature, name); + } else - size = DWARF_OFFSET_SIZE; - dw2_asm_output_offset (size, sym, debug_info_section, "%s", name); + { + char *sym = AT_ref (a)->die_id.die_symbol; + int size; + + gcc_assert (sym); + /* In DWARF2, DW_FORM_ref_addr is sized by target address + length, whereas in DWARF3 it's always sized as an + offset. */ + if (dwarf_version == 2) + size = DWARF2_ADDR_SIZE; + else + size = DWARF_OFFSET_SIZE; + dw2_asm_output_offset (size, sym, debug_info_section, "%s", + name); + } } else { @@ -8945,6 +10612,16 @@ output_die (dw_die_ref die) break; } + case dw_val_class_data8: + { + int i; + + for (i = 0; i < 8; i++) + dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i], + i == 0 ? "%s" : NULL, name); + break; + } + default: gcc_unreachable (); } @@ -8964,13 +10641,20 @@ output_die (dw_die_ref die) static void output_compilation_unit_header (void) { + int ver = dwarf_version; + + /* Don't mark the output as DWARF-4 until we make full use of the + version 4 extensions, and gdb supports them. For now, -gdwarf-4 + selects only a few extensions from the DWARF-4 spec. */ + if (ver > 3) + ver = 3; 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, next_die_offset - DWARF_INITIAL_LENGTH_SIZE, "Length of Compilation Unit Info"); - dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + dw2_asm_output_data (2, ver, "DWARF version number"); dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label, debug_abbrev_section, "Offset Into Abbrev. Section"); @@ -9002,14 +10686,14 @@ output_comp_unit (dw_die_ref die, int output_if_empty) next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; calc_die_sizes (die); - oldsym = die->die_symbol; + oldsym = die->die_id.die_symbol; if (oldsym) { tmp = XALLOCAVEC (char, strlen (oldsym) + 24); sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym); secname = tmp; - die->die_symbol = NULL; + die->die_id.die_symbol = NULL; switch_to_section (get_section (secname, SECTION_DEBUG, NULL)); } else @@ -9024,10 +10708,60 @@ output_comp_unit (dw_die_ref die, int output_if_empty) if (oldsym) { unmark_dies (die); - die->die_symbol = oldsym; + die->die_id.die_symbol = oldsym; } } +/* Output a comdat type unit DIE and its children. */ + +static void +output_comdat_type_unit (comdat_type_node *node) +{ + const char *secname; + char *tmp; + int i; +#if defined (OBJECT_FORMAT_ELF) + tree comdat_key; +#endif + + /* First mark all the DIEs in this CU so we know which get local refs. */ + mark_dies (node->root_die); + + build_abbrev_table (node->root_die); + + /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ + next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE; + calc_die_sizes (node->root_die); + +#if defined (OBJECT_FORMAT_ELF) + secname = ".debug_types"; + tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2); + sprintf (tmp, "wt."); + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff); + comdat_key = get_identifier (tmp); + targetm.asm_out.named_section (secname, + SECTION_DEBUG | SECTION_LINKONCE, + comdat_key); +#else + tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2); + sprintf (tmp, ".gnu.linkonce.wt."); + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff); + secname = tmp; + switch_to_section (get_section (secname, SECTION_DEBUG, NULL)); +#endif + + /* Output debugging information. */ + output_compilation_unit_header (); + output_signature (node->signature, "Type Signature"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset, + "Offset to Type DIE"); + output_die (node->root_die); + + unmark_dies (node->root_die); +} + /* Return the DWARF2/3 pubname associated with a decl. */ static const char * @@ -9052,7 +10786,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. */ @@ -9082,7 +10820,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. */ @@ -9524,7 +11266,6 @@ output_file_names (void) int ndirs; int idx_offset; int i; - int idx; if (!last_emitted_file) { @@ -9651,7 +11392,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, @@ -9745,6 +11485,13 @@ output_line_info (void) long line_delta; unsigned long current_file; unsigned long function; + int ver = dwarf_version; + + /* Don't mark the output as DWARF-4 until we make full use of the + version 4 extensions, and gdb supports them. For now, -gdwarf-4 + selects only a few extensions from the DWARF-4 spec. */ + if (ver > 3) + ver = 3; ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0); @@ -9758,7 +11505,7 @@ output_line_info (void) "Length of Source Line Info"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + dw2_asm_output_data (2, ver, "DWARF Version"); dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); ASM_OUTPUT_LABEL (asm_out_file, p1); @@ -10041,6 +11788,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. @@ -10080,13 +11950,20 @@ base_type_die (tree type) case REAL_TYPE: if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))) - encoding = DW_ATE_decimal_float; + { + if (dwarf_version >= 3 || !dwarf_strict) + encoding = DW_ATE_decimal_float; + else + encoding = DW_ATE_lo_user; + } else encoding = DW_ATE_float; break; case FIXED_POINT_TYPE: - if (TYPE_UNSIGNED (type)) + if (!(dwarf_version >= 3 || !dwarf_strict)) + encoding = DW_ATE_lo_user; + else if (TYPE_UNSIGNED (type)) encoding = DW_ATE_unsigned_fixed; else encoding = DW_ATE_signed_fixed; @@ -10284,6 +12161,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) { @@ -10291,6 +12171,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 @@ -10321,10 +12204,16 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, /* Builtin types don't have a DECL_ORIGINAL_TYPE. For those, don't output a DW_TAG_typedef, since there isn't one in the - user's program; just attach a DW_AT_name to the type. */ + user's program; just attach a DW_AT_name to the type. + Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type + if the base type already has the same name. */ if (name - && (TREE_CODE (name) != TYPE_DECL - || (TREE_TYPE (name) == qualified_type && DECL_NAME (name)))) + && ((TREE_CODE (name) != TYPE_DECL + && (qualified_type == TYPE_MAIN_VARIANT (type) + || (!is_const_type && !is_volatile_type))) + || (TREE_CODE (name) == TYPE_DECL + && TREE_TYPE (name) == qualified_type + && DECL_NAME (name)))) { if (TREE_CODE (name) == TYPE_DECL) /* Could just call add_name_and_src_coords_attributes here, @@ -10347,10 +12236,191 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, TYPE_VOLATILE (item_type), context_die); - if (sub_die != NULL) - add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); + if (sub_die != NULL) + add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); + + return mod_type_die; +} + +/* Generate DIEs for the generic parameters of T. + T must be either a generic type or a generic function. + See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more. */ + +static void +gen_generic_params_dies (tree t) +{ + tree parms, args; + int parms_num, i; + dw_die_ref die = NULL; + + if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t))) + return; + + if (TYPE_P (t)) + die = lookup_type_die (t); + else if (DECL_P (t)) + die = lookup_decl_die (t); + + gcc_assert (die); + + parms = lang_hooks.get_innermost_generic_parms (t); + if (!parms) + /* T has no generic parameter. It means T is neither a generic type + or function. End of story. */ + return; + + parms_num = TREE_VEC_LENGTH (parms); + args = lang_hooks.get_innermost_generic_args (t); + for (i = 0; i < parms_num; i++) + { + tree parm, arg, arg_pack_elems; + + parm = TREE_VEC_ELT (parms, i); + arg = TREE_VEC_ELT (args, i); + arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg); + gcc_assert (parm && TREE_VALUE (parm) && arg); + + if (parm && TREE_VALUE (parm) && arg) + { + /* If PARM represents a template parameter pack, + emit a DW_TAG_GNU_template_parameter_pack DIE, followed + by DW_TAG_template_*_parameter DIEs for the argument + pack elements of ARG. Note that ARG would then be + an argument pack. */ + if (arg_pack_elems) + template_parameter_pack_die (TREE_VALUE (parm), + arg_pack_elems, + die); + else + generic_parameter_die (TREE_VALUE (parm), arg, + true /* Emit DW_AT_name */, die); + } + } +} + +/* Create and return a DIE for PARM which should be + the representation of a generic type parameter. + For instance, in the C++ front end, PARM would be a template parameter. + ARG is the argument to PARM. + EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the + name of the PARM. + PARENT_DIE is the parent DIE which the new created DIE should be added to, + as a child node. */ + +static dw_die_ref +generic_parameter_die (tree parm, tree arg, + bool emit_name_p, + dw_die_ref parent_die) +{ + dw_die_ref tmpl_die = NULL; + const char *name = NULL; + + if (!parm || !DECL_NAME (parm) || !arg) + return NULL; + + /* We support non-type generic parameters and arguments, + type generic parameters and arguments, as well as + generic generic parameters (a.k.a. template template parameters in C++) + and arguments. */ + if (TREE_CODE (parm) == PARM_DECL) + /* PARM is a nontype generic parameter */ + tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm); + else if (TREE_CODE (parm) == TYPE_DECL) + /* PARM is a type generic parameter. */ + tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm); + else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm)) + /* PARM is a generic generic parameter. + Its DIE is a GNU extension. It shall have a + DW_AT_name attribute to represent the name of the template template + parameter, and a DW_AT_GNU_template_name attribute to represent the + name of the template template argument. */ + tmpl_die = new_die (DW_TAG_GNU_template_template_param, + parent_die, parm); + else + gcc_unreachable (); + + if (tmpl_die) + { + tree tmpl_type; + + /* If PARM is a generic parameter pack, it means we are + emitting debug info for a template argument pack element. + In other terms, ARG is a template argument pack element. + In that case, we don't emit any DW_AT_name attribute for + the die. */ + if (emit_name_p) + { + name = IDENTIFIER_POINTER (DECL_NAME (parm)); + gcc_assert (name); + add_AT_string (tmpl_die, DW_AT_name, name); + } + + if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm)) + { + /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter + TMPL_DIE should have a child DW_AT_type attribute that is set + to the type of the argument to PARM, which is ARG. + If PARM is a type generic parameter, TMPL_DIE should have a + child DW_AT_type that is set to ARG. */ + tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg); + add_type_attribute (tmpl_die, tmpl_type, 0, + TREE_THIS_VOLATILE (tmpl_type), + parent_die); + } + else + { + /* So TMPL_DIE is a DIE representing a + a generic generic template parameter, a.k.a template template + parameter in C++ and arg is a template. */ + + /* 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); + if (name) + add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); + } + + if (TREE_CODE (parm) == PARM_DECL) + /* So PARM is a non-type generic parameter. + DWARF3 5.6.8 says we must set a DW_AT_const_value child + attribute of TMPL_DIE which value represents the value + of ARG. + We must be careful here: + The value of ARG might reference some function decls. + We might currently be emitting debug info for a generic + type and types are emitted before function decls, we don't + know if the function decls referenced by ARG will actually be + emitted after cgraph computations. + So must defer the generation of the DW_AT_const_value to + after cgraph is ready. */ + append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg); + } + + return tmpl_die; +} - return mod_type_die; +/* Generate and return a DW_TAG_GNU_template_parameter_pack DIE representing. + PARM_PACK must be a template parameter pack. The returned DIE + will be child DIE of PARENT_DIE. */ + +static dw_die_ref +template_parameter_pack_die (tree parm_pack, + tree parm_pack_args, + dw_die_ref parent_die) +{ + dw_die_ref die; + int j; + + gcc_assert (parent_die && parm_pack); + + die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, 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), + false /* Don't emit DW_AT_name */, + die); + return die; } /* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is @@ -10552,6 +12622,63 @@ int_loc_descriptor (HOST_WIDE_INT i) #endif #ifdef DWARF2_DEBUGGING_INFO +/* Return loc description representing "address" of integer value. + This can appear only as toplevel expression. */ + +static dw_loc_descr_ref +address_of_int_loc_descriptor (int size, HOST_WIDE_INT i) +{ + int litsize; + dw_loc_descr_ref loc_result = NULL; + + if (!(dwarf_version >= 4 || !dwarf_strict)) + return NULL; + + if (i >= 0) + { + if (i <= 31) + litsize = 1; + else if (i <= 0xff) + litsize = 2; + else if (i <= 0xffff) + litsize = 3; + else if (HOST_BITS_PER_WIDE_INT == 32 + || i <= 0xffffffff) + litsize = 5; + else + litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i); + } + else + { + if (i >= -0x80) + litsize = 2; + else if (i >= -0x8000) + litsize = 3; + else if (HOST_BITS_PER_WIDE_INT == 32 + || i >= -0x80000000) + litsize = 5; + else + litsize = 1 + size_of_sleb128 (i); + } + /* Determine if DW_OP_stack_value or DW_OP_implicit_value + is more compact. For DW_OP_stack_value we need: + litsize + 1 (DW_OP_stack_value) + and for DW_OP_implicit_value: + 1 (DW_OP_implicit_value) + 1 (length) + size. */ + if ((int) DWARF2_ADDR_SIZE >= size && litsize + 1 <= 1 + 1 + size) + { + loc_result = int_loc_descriptor (i); + add_loc_descr (&loc_result, + new_loc_descr (DW_OP_stack_value, 0, 0)); + return loc_result; + } + + loc_result = new_loc_descr (DW_OP_implicit_value, + size, 0); + loc_result->dw_loc_oprnd2.val_class = dw_val_class_const; + loc_result->dw_loc_oprnd2.v.val_int = i; + return loc_result; +} /* Return a location descriptor that designates a base+offset location. */ @@ -10637,36 +12764,6 @@ is_based_loc (const_rtx rtl) && CONST_INT_P (XEXP (rtl, 1))))); } -/* Return a descriptor that describes the concatenation of N locations - used to form the address of a memory location. */ - -static dw_loc_descr_ref -concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode, - enum var_init_status initialized) -{ - unsigned int i; - dw_loc_descr_ref cc_loc_result = NULL; - unsigned int n = XVECLEN (concatn, 0); - - for (i = 0; i < n; ++i) - { - dw_loc_descr_ref ref; - rtx x = XVECEXP (concatn, 0, i); - - ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED); - if (ref == NULL) - return NULL; - - add_loc_descr (&cc_loc_result, ref); - add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x))); - } - - if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED) - add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); - - return cc_loc_result; -} - /* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0) failed. */ @@ -10685,7 +12782,7 @@ tls_mem_loc_descriptor (rtx mem) || !DECL_THREAD_LOCAL_P (base)) return NULL; - loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2); + loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1); if (loc_result == NULL) return NULL; @@ -10695,6 +12792,90 @@ tls_mem_loc_descriptor (rtx mem) return loc_result; } +/* Output debug info about reason why we failed to expand expression as dwarf + expression. */ + +static void +expansion_failed (tree expr, rtx rtl, char const *reason) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Failed to expand as dwarf: "); + if (expr) + print_generic_expr (dump_file, expr, dump_flags); + if (rtl) + { + fprintf (dump_file, "\n"); + print_rtl (dump_file, rtl); + } + fprintf (dump_file, "\nReason: %s\n", reason); + } +} + +/* Helper function for const_ok_for_output, called either directly + or via for_each_rtx. */ + +static int +const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED) +{ + rtx rtl = *rtlp; + + if (GET_CODE (rtl) != SYMBOL_REF) + return 0; + + if (CONSTANT_POOL_ADDRESS_P (rtl)) + { + bool marked; + get_pool_constant_mark (rtl, &marked); + /* If all references to this pool constant were optimized away, + it was not output and thus we can't represent it. */ + if (!marked) + { + expansion_failed (NULL_TREE, rtl, + "Constant was removed from constant pool.\n"); + return 1; + } + } + + if (SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE) + return 1; + + /* Avoid references to external symbols in debug info, on several targets + the linker might even refuse to link when linking a shared library, + and in many other cases the relocations for .debug_info/.debug_loc are + dropped, so the address becomes zero anyway. Hidden symbols, guaranteed + to be defined within the same shared library or executable are fine. */ + if (SYMBOL_REF_EXTERNAL_P (rtl)) + { + tree decl = SYMBOL_REF_DECL (rtl); + + if (decl == NULL || !targetm.binds_local_p (decl)) + { + expansion_failed (NULL_TREE, rtl, + "Symbol not defined in current TU.\n"); + return 1; + } + } + + return 0; +} + +/* Return true if constant RTL can be emitted in DW_OP_addr or + DW_AT_const_value. TLS SYMBOL_REFs, external SYMBOL_REFs or + non-marked constant pool SYMBOL_REFs can't be referenced in it. */ + +static bool +const_ok_for_output (rtx rtl) +{ + if (GET_CODE (rtl) == SYMBOL_REF) + return const_ok_for_output_1 (&rtl, NULL) == 0; + + if (GET_CODE (rtl) == CONST) + return for_each_rtx (&XEXP (rtl, 0), const_ok_for_output_1, NULL) == 0; + + return true; +} + /* The following routine converts the RTL for a variable or parameter (resident in memory) into an equivalent Dwarf representation of a mechanism for getting the address of that same variable onto the top of a @@ -10719,6 +12900,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, { dw_loc_descr_ref mem_loc_result = NULL; enum dwarf_location_atom op; + dw_loc_descr_ref op0, op1; /* Note that for a dynamically sized array, the location we will generate a description of here will be the lowest numbered location which is @@ -10732,10 +12914,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) @@ -10743,9 +12922,15 @@ 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); - - /* ... fall through ... */ + 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; case REG: /* Whenever a register number forms a part of the description of the @@ -10775,6 +12960,29 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, } break; + case SIGN_EXTEND: + case ZERO_EXTEND: + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); + if (op0 == 0) + break; + else + { + int shift = DWARF2_ADDR_SIZE + - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))); + shift *= BITS_PER_UNIT; + if (GET_CODE (rtl) == SIGN_EXTEND) + op = DW_OP_shra; + else + op = DW_OP_shr; + mem_loc_result = op0; + add_loc_descr (&mem_loc_result, int_loc_descriptor (shift)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0)); + add_loc_descr (&mem_loc_result, int_loc_descriptor (shift)); + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + } + break; + case MEM: mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl), VAR_INIT_STATUS_INITIALIZED); @@ -10816,15 +13024,50 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, FIXME: might try to use DW_OP_const_value here, though DW_OP_piece complicates it. */ if (!marked) - return 0; + { + 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) + { + dw_loc_descr_ref temp; + + /* If this is not defined, we have no way to emit the data. */ + if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel) + break; + + temp = new_loc_descr (DW_OP_addr, 0, 0); + temp->dw_loc_oprnd1.val_class = dw_val_class_addr; + temp->dw_loc_oprnd1.v.val_addr = rtl; + temp->dtprel = true; + + mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0); + add_loc_descr (&mem_loc_result, temp); + + break; } + if (!const_ok_for_output (rtl)) + break; + + symref: mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl; VEC_safe_push (rtx, gc, used_rtx_array, rtl); break; + case CONCAT: + case CONCATN: + case VAR_LOCATION: + expansion_failed (NULL_TREE, rtl, + "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor"); + return 0; + case PRE_MODIFY: /* Extract the PLUS expression nested inside and fall into PLUS code below. */ @@ -10873,10 +13116,22 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, /* If a pseudo-reg is optimized away, it is possible for it to be replaced with a MEM containing a multiply or shift. */ + case MINUS: + op = DW_OP_minus; + goto do_binop; + case MULT: op = DW_OP_mul; goto do_binop; + case DIV: + op = DW_OP_div; + goto do_binop; + + case MOD: + op = DW_OP_mod; + goto do_binop; + case ASHIFT: op = DW_OP_shl; goto do_binop; @@ -10889,39 +13144,349 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, op = DW_OP_shr; goto do_binop; + case AND: + op = DW_OP_and; + goto do_binop; + + case IOR: + op = DW_OP_or; + goto do_binop; + + case XOR: + op = DW_OP_xor; + goto do_binop; + do_binop: - { - dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); - dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, - VAR_INIT_STATUS_INITIALIZED); + 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; + 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 (op, 0, 0)); + break; + + case NOT: + op = DW_OP_not; + goto do_unop; + + case ABS: + op = DW_OP_abs; + goto do_unop; + + case NEG: + op = DW_OP_neg; + goto do_unop; + + do_unop: + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); - mem_loc_result = op0; - add_loc_descr (&mem_loc_result, op1); - add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + if (op0 == 0) break; - } + + mem_loc_result = op0; + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + break; case CONST_INT: mem_loc_result = int_loc_descriptor (INTVAL (rtl)); break; - case CONCATN: - mem_loc_result = concatn_mem_loc_descriptor (rtl, mode, - VAR_INIT_STATUS_INITIALIZED); + case EQ: + op = DW_OP_eq; + goto do_scompare; + + case GE: + op = DW_OP_ge; + goto do_scompare; + + case GT: + op = DW_OP_gt; + goto do_scompare; + + case LE: + op = DW_OP_le; + goto do_scompare; + + case LT: + op = DW_OP_lt; + goto do_scompare; + + case NE: + op = DW_OP_ne; + 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))) + 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 (op0 == 0 || op1 == 0) + break; + + 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 + { + add_loc_descr (&op1, int_loc_descriptor (shift)); + add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); + } + } + + do_compare: + mem_loc_result = op0; + add_loc_descr (&mem_loc_result, op1); + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + if (STORE_FLAG_VALUE != 1) + { + add_loc_descr (&mem_loc_result, + int_loc_descriptor (STORE_FLAG_VALUE)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0)); + } + break; + + case GEU: + op = DW_OP_ge; + goto do_ucompare; + + case GTU: + op = DW_OP_gt; + goto do_ucompare; + + case LEU: + op = DW_OP_le; + goto do_ucompare; + + case LTU: + op = DW_OP_lt; + 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))) + 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 (op0 == 0 || op1 == 0) + break; + + 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 + { + 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)); + } + goto do_compare; + + case SMIN: + case SMAX: + case UMIN: + case UMAX: + 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))) + 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 (op0 == 0 || op1 == 0) + break; + + add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0)); + add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0)); + add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0)); + if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX) + { + 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)); + 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)); + add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0)); + } + } + else 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)); + add_loc_descr (&op1, int_loc_descriptor (shift)); + add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); + } + + if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN) + op = DW_OP_lt; + else + op = DW_OP_gt; + mem_loc_result = op0; + add_loc_descr (&mem_loc_result, op1); + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + { + dw_loc_descr_ref bra_node, drop_node; + + bra_node = new_loc_descr (DW_OP_bra, 0, 0); + add_loc_descr (&mem_loc_result, bra_node); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0)); + drop_node = new_loc_descr (DW_OP_drop, 0, 0); + add_loc_descr (&mem_loc_result, drop_node); + bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc; + bra_node->dw_loc_oprnd1.v.val_loc = drop_node; + } + break; + + case ZERO_EXTRACT: + case SIGN_EXTRACT: + if (CONST_INT_P (XEXP (rtl, 1)) + && CONST_INT_P (XEXP (rtl, 2)) + && ((unsigned) INTVAL (XEXP (rtl, 1)) + + (unsigned) INTVAL (XEXP (rtl, 2)) + <= GET_MODE_BITSIZE (GET_MODE (rtl))) + && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE + && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE) + { + int shift, size; + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); + if (op0 == 0) + break; + if (GET_CODE (rtl) == SIGN_EXTRACT) + op = DW_OP_shra; + else + op = DW_OP_shr; + mem_loc_result = op0; + size = INTVAL (XEXP (rtl, 1)); + shift = INTVAL (XEXP (rtl, 2)); + if (BITS_BIG_ENDIAN) + shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) + - shift - size; + 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; + case COMPARE: + case IF_THEN_ELSE: + case ROTATE: + case ROTATERT: + case TRUNCATE: + /* In theory, we could implement the above. */ + /* DWARF cannot represent the unsigned compare operations + natively. */ + case SS_MULT: + case US_MULT: + case SS_DIV: + case US_DIV: + case UDIV: + case UMOD: + case UNORDERED: + case ORDERED: + case UNEQ: + case UNGE: + case UNGT: + case UNLE: + case UNLT: + case LTGT: + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case UNSIGNED_FLOAT: + case FIX: + case UNSIGNED_FIX: + case FRACT_CONVERT: + case UNSIGNED_FRACT_CONVERT: + case SAT_FRACT: + case UNSIGNED_SAT_FRACT: + case SQRT: + case BSWAP: + case FFS: + case CLZ: + case CTZ: + case POPCOUNT: + case PARITY: + case ASM_OPERANDS: case UNSPEC: + case HIGH: /* If delegitimize_address couldn't do anything with the UNSPEC, we can't express it in the debug info. This can happen e.g. with some TLS UNSPECs. */ break; + case CONST_STRING: + resolve_one_addr (&rtl, NULL); + goto symref; + default: +#ifdef ENABLE_CHECKING + print_rtl (stderr, rtl); gcc_unreachable (); +#else + break; +#endif } if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED) @@ -10937,8 +13502,10 @@ static dw_loc_descr_ref concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized) { dw_loc_descr_ref cc_loc_result = NULL; - dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED); - dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED); + dw_loc_descr_ref x0_ref + = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED); + dw_loc_descr_ref x1_ref + = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED); if (x0_ref == 0 || x1_ref == 0) return 0; @@ -10970,7 +13537,7 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized) dw_loc_descr_ref ref; rtx x = XVECEXP (concatn, 0, i); - ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED); + ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED); if (ref == NULL) return NULL; @@ -10990,10 +13557,15 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized) memory location we provide a Dwarf postfix expression describing how to generate the (dynamic) address of the object onto the address stack. + MODE is mode of the decl if this loc_descriptor is going to be used in + .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are + allowed, VOIDmode otherwise. + If we don't know how to describe it, return 0. */ static dw_loc_descr_ref -loc_descriptor (rtx rtl, enum var_init_status initialized) +loc_descriptor (rtx rtl, enum machine_mode mode, + enum var_init_status initialized) { dw_loc_descr_ref loc_result = NULL; @@ -11005,14 +13577,18 @@ loc_descriptor (rtx rtl, enum var_init_status initialized) 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 = SUBREG_REG (rtl); - - /* ... fall through ... */ + loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized); + break; case REG: loc_result = reg_loc_descriptor (rtl, initialized); break; + case SIGN_EXTEND: + case ZERO_EXTEND: + loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized); + break; + case MEM: loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl), initialized); @@ -11033,7 +13609,8 @@ loc_descriptor (rtx rtl, enum var_init_status initialized) /* Single part. */ if (GET_CODE (XEXP (rtl, 1)) != PARALLEL) { - loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized); + loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode, + initialized); break; } @@ -11049,7 +13626,7 @@ loc_descriptor (rtx rtl, enum var_init_status initialized) /* Create the first one, so we have something to add to. */ loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0), - initialized); + VOIDmode, initialized); if (loc_result == NULL) return NULL; mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0)); @@ -11059,7 +13636,7 @@ loc_descriptor (rtx rtl, enum var_init_status initialized) dw_loc_descr_ref temp; temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0), - initialized); + VOIDmode, initialized); if (temp == NULL) return NULL; add_loc_descr (&loc_result, temp); @@ -11069,23 +13646,548 @@ loc_descriptor (rtx rtl, enum var_init_status initialized) } break; - default: - gcc_unreachable (); + case CONST_INT: + if (mode != VOIDmode && mode != BLKmode) + loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode), + INTVAL (rtl)); + break; + + case CONST_DOUBLE: + if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict)) + { + /* 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)) + { + unsigned int length = GET_MODE_SIZE (mode); + unsigned char *array = GGC_NEWVEC (unsigned char, length); + + insert_float (rtl, array); + loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec; + loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4; + loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4; + loc_result->dw_loc_oprnd2.v.val_vec.array = array; + } + else + { + loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double; + loc_result->dw_loc_oprnd2.v.val_double.high + = CONST_DOUBLE_HIGH (rtl); + loc_result->dw_loc_oprnd2.v.val_double.low + = CONST_DOUBLE_LOW (rtl); + } + } + break; + + case CONST_VECTOR: + if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict)) + { + unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl)); + unsigned int length = CONST_VECTOR_NUNITS (rtl); + unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size); + unsigned int i; + unsigned char *p; + + mode = GET_MODE (rtl); + switch (GET_MODE_CLASS (mode)) + { + case MODE_VECTOR_INT: + for (i = 0, p = array; i < length; i++, p += elt_size) + { + rtx elt = CONST_VECTOR_ELT (rtl, i); + HOST_WIDE_INT lo, hi; + + switch (GET_CODE (elt)) + { + case CONST_INT: + lo = INTVAL (elt); + hi = -(lo < 0); + break; + + case CONST_DOUBLE: + lo = CONST_DOUBLE_LOW (elt); + hi = CONST_DOUBLE_HIGH (elt); + break; + + default: + gcc_unreachable (); + } + + if (elt_size <= sizeof (HOST_WIDE_INT)) + insert_int (lo, elt_size, p); + else + { + unsigned char *p0 = p; + unsigned char *p1 = p + sizeof (HOST_WIDE_INT); + + gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT)); + if (WORDS_BIG_ENDIAN) + { + p0 = p1; + p1 = p; + } + insert_int (lo, sizeof (HOST_WIDE_INT), p0); + insert_int (hi, sizeof (HOST_WIDE_INT), p1); + } + } + break; + + case MODE_VECTOR_FLOAT: + for (i = 0, p = array; i < length; i++, p += elt_size) + { + rtx elt = CONST_VECTOR_ELT (rtl, i); + insert_float (elt, p); + } + break; + + default: + gcc_unreachable (); + } + + loc_result = new_loc_descr (DW_OP_implicit_value, + length * elt_size, 0); + loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec; + loc_result->dw_loc_oprnd2.v.val_vec.length = length; + loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size; + loc_result->dw_loc_oprnd2.v.val_vec.array = array; + } + break; + + case CONST: + if (mode == VOIDmode + || GET_CODE (XEXP (rtl, 0)) == CONST_INT + || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE + || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR) + { + loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized); + break; + } + /* FALLTHROUGH */ + case SYMBOL_REF: + if (!const_ok_for_output (rtl)) + break; + case LABEL_REF: + 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; + VEC_safe_push (rtx, gc, used_rtx_array, rtl); + } + break; + + default: + if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode + && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE + && (dwarf_version >= 4 || !dwarf_strict)) + { + /* Value expression. */ + loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized); + if (loc_result) + add_loc_descr (&loc_result, + new_loc_descr (DW_OP_stack_value, 0, 0)); + } + break; + } + + return loc_result; +} + +/* We need to figure out what section we should use as the base for the + address ranges where a given location is valid. + 1. If this particular DECL has a section associated with it, use that. + 2. If this function has a section associated with it, use that. + 3. Otherwise, use the text section. + XXX: If you split a variable across multiple sections, we won't notice. */ + +static const char * +secname_for_decl (const_tree decl) +{ + const char *secname; + + if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl)) + { + tree sectree = DECL_SECTION_NAME (decl); + secname = TREE_STRING_POINTER (sectree); + } + else if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) + { + tree sectree = DECL_SECTION_NAME (current_function_decl); + secname = TREE_STRING_POINTER (sectree); + } + else if (cfun && in_cold_section_p) + secname = crtl->subsections.cold_section_label; + else + secname = text_section_label; + + return secname; +} + +/* Return true when DECL_BY_REFERENCE is defined and set for DECL. */ + +static bool +decl_by_reference_p (tree decl) +{ + return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL + || TREE_CODE (decl) == VAR_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. */ + +static dw_loc_descr_ref +dw_loc_list_1 (tree loc, rtx varloc, int want_address, + enum var_init_status initialized) +{ + int have_address = 0; + dw_loc_descr_ref descr; + enum machine_mode mode; + + if (want_address != 2) + { + gcc_assert (GET_CODE (varloc) == VAR_LOCATION); + /* Single part. */ + if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) + { + varloc = XEXP (XEXP (varloc, 1), 0); + mode = GET_MODE (varloc); + if (MEM_P (varloc)) + { + varloc = XEXP (varloc, 0); + have_address = 1; + } + descr = mem_loc_descriptor (varloc, mode, initialized); + } + else + return 0; + } + else + { + descr = loc_descriptor (varloc, DECL_MODE (loc), initialized); + have_address = 1; + } + + if (!descr) + return 0; + + if (want_address == 2 && !have_address + && (dwarf_version >= 4 || !dwarf_strict)) + { + if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE) + { + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; + } + add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0)); + have_address = 1; + } + /* Show if we can't fill the request for an address. */ + if (want_address && !have_address) + { + expansion_failed (loc, NULL_RTX, + "Want address and only have value"); + return 0; + } + + /* If we've got an address and don't want one, dereference. */ + if (!want_address && have_address) + { + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc)); + enum dwarf_location_atom op; + + if (size > DWARF2_ADDR_SIZE || size == -1) + { + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; + } + else if (size == DWARF2_ADDR_SIZE) + op = DW_OP_deref; + else + op = DW_OP_deref_size; + + add_loc_descr (&descr, new_loc_descr (op, size, 0)); + } + + 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. */ + +static dw_loc_list_ref +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]; + + /* Now that we know what section we are using for a base, + actually construct the list of locations. + The first location information is what is passed to the + function that creates the location list, and the remaining + locations just get added on to that list. + Note that we only know the start address for a location + (IE location changes), so to build the range, we use + the range [current location start, next location start]. + 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) + if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) + { + /* The variable has a location between NODE->LABEL and + NODE->NEXT->LABEL. */ + 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 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); + } + return list; +} + +/* Return if the loc_list has only single element and thus can be represented + as location description. */ + +static bool +single_element_loc_list_p (dw_loc_list_ref list) +{ + return (!list->dw_loc_next && !list->begin && !list->end); +} + +/* To each location in list LIST add loc descr REF. */ + +static void +add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref) +{ + dw_loc_descr_ref copy; + add_loc_descr (&list->expr, ref); + list = list->dw_loc_next; + while (list) + { + copy = GGC_CNEW (dw_loc_descr_node); + memcpy (copy, ref, sizeof (dw_loc_descr_node)); + add_loc_descr (&list->expr, copy); + while (copy->dw_loc_next) + { + dw_loc_descr_ref new_copy = GGC_CNEW (dw_loc_descr_node); + memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node)); + copy->dw_loc_next = new_copy; + copy = new_copy; + } + list = list->dw_loc_next; + } +} + +/* Given two lists RET and LIST + produce location list that is result of adding expression in LIST + to expression in RET on each possition in program. + Might be destructive on both RET and LIST. + + 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. + Adding that will improve quality of debug info especially for SRA-ed + structures. */ + +static void +add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list) +{ + if (!list) + return; + if (!*ret) + { + *ret = list; + return; + } + if (!list->dw_loc_next) + { + add_loc_descr_to_each (*ret, list->expr); + return; + } + if (!(*ret)->dw_loc_next) + { + add_loc_descr_to_each (list, (*ret)->expr); + *ret = list; + return; + } + expansion_failed (NULL_TREE, NULL_RTX, + "Don't know how to merge two non-trivial" + " location lists.\n"); + *ret = NULL; + return; +} + +/* LOC is constant expression. Try a luck, look it up in constant + pool and return its loc_descr of its address. */ + +static dw_loc_descr_ref +cst_pool_loc_descr (tree loc) +{ + /* Get an RTL for this, if something has been emitted. */ + rtx rtl = lookup_constant_def (loc); + enum machine_mode mode; + + if (!rtl || !MEM_P (rtl)) + { + gcc_assert (!rtl); + return 0; + } + gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF); + + /* TODO: We might get more coverage if we was actually delaying expansion + of all expressions till end of compilation when constant pools are fully + populated. */ + if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0)))) + { + expansion_failed (loc, NULL_RTX, + "CST value in contant pool but not marked."); + return 0; + } + mode = GET_MODE (rtl); + rtl = XEXP (rtl, 0); + return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); +} + +/* Return dw_loc_list representing address of addr_expr LOC + by looking for innder INDIRECT_REF expression and turing it + into simple arithmetics. */ + +static dw_loc_list_ref +loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev) +{ + tree obj, offset; + HOST_WIDE_INT bitsize, bitpos, bytepos; + enum machine_mode mode; + int volatilep; + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc)); + dw_loc_list_ref list_ret = NULL, list_ret1 = NULL; + + obj = get_inner_reference (TREE_OPERAND (loc, 0), + &bitsize, &bitpos, &offset, &mode, + &unsignedp, &volatilep, false); + STRIP_NOPS (obj); + if (bitpos % BITS_PER_UNIT) + { + expansion_failed (loc, NULL_RTX, "bitfield access"); + return 0; } - - return loc_result; + if (!INDIRECT_REF_P (obj)) + { + expansion_failed (obj, + NULL_RTX, "no indirect ref in inner refrence"); + return 0; + } + if (!offset && !bitpos) + list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1); + else if (toplev + && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE + && (dwarf_version >= 4 || !dwarf_strict)) + { + list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0); + if (!list_ret) + return 0; + if (offset) + { + /* Variable offset. */ + list_ret1 = loc_list_from_tree (offset, 0); + if (list_ret1 == 0) + return 0; + add_loc_list (&list_ret, list_ret1); + if (!list_ret) + return 0; + add_loc_descr_to_each (list_ret, + new_loc_descr (DW_OP_plus, 0, 0)); + } + bytepos = bitpos / BITS_PER_UNIT; + 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); + add_loc_descr_to_each (list_ret, + new_loc_descr (DW_OP_stack_value, 0, 0)); + } + return list_ret; } -/* Similar, but generate the descriptor from trees instead of rtl. This comes - up particularly with variable length arrays. WANT_ADDRESS is 2 if this is - a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a - top-level invocation, and we require the address of LOC; is 0 if we require - the value of LOC. */ -static dw_loc_descr_ref -loc_descriptor_from_tree_1 (tree loc, int want_address) +/* Generate Dwarf location list representing LOC. + If WANT_ADDRESS is false, expression computing LOC will be computed + If WANT_ADDRESS is 1, expression computing address of LOC will be returned + if WANT_ADDRESS is 2, expression computing address useable in location + will be returned (i.e. DW_OP_reg can be used + to refer to register values). */ + +static dw_loc_list_ref +loc_list_from_tree (tree loc, int want_address) { - dw_loc_descr_ref ret, ret1; + dw_loc_descr_ref ret = NULL, ret1 = NULL; + dw_loc_list_ref list_ret = NULL, list_ret1 = NULL; int have_address = 0; enum dwarf_location_atom op; @@ -11096,6 +14198,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) switch (TREE_CODE (loc)) { case ERROR_MARK: + expansion_failed (loc, NULL_RTX, "ERROR_MARK"); return 0; case PLACEHOLDER_EXPR: @@ -11103,25 +14206,45 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) position of other fields. We don't try to encode this here. The only user of this is Ada, which encodes the needed information using the names of types. */ + expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR"); return 0; case CALL_EXPR: + expansion_failed (loc, NULL_RTX, "CALL_EXPR"); + /* There are no opcodes for these operations. */ return 0; case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: + expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT"); /* There are no opcodes for these operations. */ return 0; case ADDR_EXPR: - /* If we already want an address, there's nothing we can do. */ + /* If we already want an address, see if there is INDIRECT_REF inside + e.g. for &this->field. */ if (want_address) - return 0; - - /* Otherwise, process the argument and look for the address. */ - return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1); + { + list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref + (loc, want_address == 2); + if (list_ret) + have_address = 1; + else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0)) + && (ret = cst_pool_loc_descr (loc))) + have_address = 1; + } + /* Otherwise, process the argument and look for the address. */ + if (!list_ret && !ret) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1); + else + { + if (want_address) + expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR"); + return NULL; + } + break; case VAR_DECL: if (DECL_THREAD_LOCAL_P (loc)) @@ -11134,7 +14257,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (targetm.have_tls) { /* If this is not defined, we have no way to emit the - data. */ + data. */ if (!targetm.asm_out.output_dwarf_dtprel) return 0; @@ -11149,7 +14272,8 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) } else { - if (!targetm.emutls.debug_form_tls_address) + if (!targetm.emutls.debug_form_tls_address + || !(dwarf_version >= 3 || !dwarf_strict)) return 0; loc = emutls_decl (loc); first_op = DW_OP_addr; @@ -11181,17 +14305,28 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) case PARM_DECL: if (DECL_HAS_VALUE_EXPR_P (loc)) - return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc), - want_address); + return loc_list_from_tree (DECL_VALUE_EXPR (loc), + want_address); /* FALLTHRU */ 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; + break; + } + rtl = rtl_for_decl_location (loc); if (rtl == NULL_RTX) - return 0; + { + expansion_failed (loc, NULL_RTX, "DECL has no RTL"); + return 0; + } else if (CONST_INT_P (rtl)) { HOST_WIDE_INT val = INTVAL (rtl); @@ -11200,8 +14335,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) ret = int_loc_descriptor (val); } else if (GET_CODE (rtl) == CONST_STRING) - return 0; - else if (CONSTANT_P (rtl)) + { + expansion_failed (loc, NULL_RTX, "CONST_STRING"); + return 0; + } + else if (CONSTANT_P (rtl) && const_ok_for_output (rtl)) { ret = new_loc_descr (DW_OP_addr, 0, 0); ret->dw_loc_oprnd1.val_class = dw_val_class_addr; @@ -11213,37 +14351,50 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) /* Certain constructs can only be represented at top-level. */ if (want_address == 2) - return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED); - - mode = GET_MODE (rtl); - if (MEM_P (rtl)) { - rtl = XEXP (rtl, 0); + ret = loc_descriptor (rtl, VOIDmode, + VAR_INIT_STATUS_INITIALIZED); have_address = 1; } - ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + else + { + mode = GET_MODE (rtl); + if (MEM_P (rtl)) + { + rtl = XEXP (rtl, 0); + have_address = 1; + } + ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + } + if (!ret) + expansion_failed (loc, rtl, + "failed to produce loc descriptor for rtl"); } } break; case INDIRECT_REF: - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); + case ALIGN_INDIRECT_REF: + case MISALIGNED_INDIRECT_REF: + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); have_address = 1; break; case COMPOUND_EXPR: - return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address); + return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address); CASE_CONVERT: case VIEW_CONVERT_EXPR: case SAVE_EXPR: case MODIFY_EXPR: - return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address); + return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address); case COMPONENT_REF: case BIT_FIELD_REF: case ARRAY_REF: case ARRAY_RANGE_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: { tree obj, offset; HOST_WIDE_INT bitsize, bitpos, bytepos; @@ -11254,52 +14405,75 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode, &unsignedp, &volatilep, false); - if (obj == loc) - return 0; + gcc_assert (obj != loc); - ret = loc_descriptor_from_tree_1 (obj, 1); - if (ret == 0 - || bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0) + list_ret = loc_list_from_tree (obj, + want_address == 2 + && !bitpos && !offset ? 2 : 1); + /* TODO: We can extract value of the small expression via shifting even + for nonzero bitpos. */ + if (list_ret == 0) return 0; + if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0) + { + expansion_failed (loc, NULL_RTX, + "bitfield access"); + return 0; + } if (offset != NULL_TREE) { /* Variable offset. */ - ret1 = loc_descriptor_from_tree_1 (offset, 0); - if (ret1 == 0) + list_ret1 = loc_list_from_tree (offset, 0); + if (list_ret1 == 0) return 0; - add_loc_descr (&ret, ret1); - add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0)); + add_loc_list (&list_ret, list_ret1); + if (!list_ret) + return 0; + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0)); } bytepos = bitpos / BITS_PER_UNIT; - loc_descr_plus_const (&ret, bytepos); + 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); have_address = 1; break; } case INTEGER_CST: - if (host_integerp (loc, 0)) + if ((want_address || !host_integerp (loc, 0)) + && (ret = cst_pool_loc_descr (loc))) + have_address = 1; + else if (want_address == 2 + && host_integerp (loc, 0) + && (ret = address_of_int_loc_descriptor + (int_size_in_bytes (TREE_TYPE (loc)), + tree_low_cst (loc, 0)))) + have_address = 1; + else if (host_integerp (loc, 0)) ret = int_loc_descriptor (tree_low_cst (loc, 0)); else - return 0; + { + expansion_failed (loc, NULL_RTX, + "Integer operand is not host integer"); + return 0; + } break; case CONSTRUCTOR: - { - /* Get an RTL for this, if something has been emitted. */ - rtx rtl = lookup_constant_def (loc); - enum machine_mode mode; - - if (!rtl || !MEM_P (rtl)) - return 0; - mode = GET_MODE (rtl); - rtl = XEXP (rtl, 0); - ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + if ((ret = cst_pool_loc_descr (loc))) have_address = 1; - break; - } + else + /* We can construct small constants here using int_loc_descriptor. */ + expansion_failed (loc, NULL_RTX, + "constructor or constant not in constant pool"); + break; case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: @@ -11353,11 +14527,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST && host_integerp (TREE_OPERAND (loc, 1), 0)) { - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - if (ret == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + if (list_ret == 0) return 0; - loc_descr_plus_const (&ret, tree_low_cst (TREE_OPERAND (loc, 1), 0)); + loc_list_plus_const (list_ret, tree_low_cst (TREE_OPERAND (loc, 1), 0)); break; } @@ -11401,13 +14575,15 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) goto do_binop; do_binop: - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0); - if (ret == 0 || ret1 == 0) + 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_descr (&ret, ret1); - add_loc_descr (&ret, new_loc_descr (op, 0, 0)); + add_loc_list (&list_ret, list_ret1); + if (list_ret == 0) + return 0; + add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0)); break; case TRUTH_NOT_EXPR: @@ -11424,11 +14600,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) goto do_unop; do_unop: - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - if (ret == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + if (list_ret == 0) return 0; - add_loc_descr (&ret, new_loc_descr (op, 0, 0)); + add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0)); break; case MIN_EXPR: @@ -11448,29 +14624,29 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) case COND_EXPR: { dw_loc_descr_ref lhs - = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0); - dw_loc_descr_ref rhs - = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0); + = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0); + dw_loc_list_ref rhs + = loc_list_from_tree (TREE_OPERAND (loc, 2), 0); dw_loc_descr_ref bra_node, jump_node, tmp; - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - if (ret == 0 || lhs == 0 || rhs == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + if (list_ret == 0 || lhs == 0 || rhs == 0) return 0; bra_node = new_loc_descr (DW_OP_bra, 0, 0); - add_loc_descr (&ret, bra_node); + add_loc_descr_to_each (list_ret, bra_node); - add_loc_descr (&ret, rhs); + add_loc_list (&list_ret, rhs); jump_node = new_loc_descr (DW_OP_skip, 0, 0); - add_loc_descr (&ret, jump_node); + add_loc_descr_to_each (list_ret, jump_node); - add_loc_descr (&ret, lhs); + add_loc_descr_to_each (list_ret, lhs); bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc; bra_node->dw_loc_oprnd1.v.val_loc = lhs; /* ??? Need a node to point the skip at. Use a nop. */ tmp = new_loc_descr (DW_OP_nop, 0, 0); - add_loc_descr (&ret, tmp); + add_loc_descr_to_each (list_ret, tmp); jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc; jump_node->dw_loc_oprnd1.v.val_loc = tmp; } @@ -11484,7 +14660,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) up, for instance, with the C STMT_EXPR. */ if ((unsigned int) TREE_CODE (loc) >= (unsigned int) LAST_AND_UNUSED_TREE_CODE) - return 0; + { + expansion_failed (loc, NULL_RTX, + "language specific tree node"); + return 0; + } #ifdef ENABLE_CHECKING /* Otherwise this is a generic code; we should just lists all of @@ -11497,32 +14677,76 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) #endif } + if (!ret && !list_ret) + return 0; + + if (want_address == 2 && !have_address + && (dwarf_version >= 4 || !dwarf_strict)) + { + if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE) + { + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; + } + if (ret) + add_loc_descr (&ret, new_loc_descr (DW_OP_stack_value, 0, 0)); + else + add_loc_descr_to_each (list_ret, + new_loc_descr (DW_OP_stack_value, 0, 0)); + have_address = 1; + } /* Show if we can't fill the request for an address. */ if (want_address && !have_address) - return 0; + { + expansion_failed (loc, NULL_RTX, + "Want address and only have value"); + return 0; + } + + gcc_assert (!ret || !list_ret); /* If we've got an address and don't want one, dereference. */ - if (!want_address && have_address && ret) + if (!want_address && have_address) { HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc)); if (size > DWARF2_ADDR_SIZE || size == -1) - return 0; + { + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; + } else if (size == DWARF2_ADDR_SIZE) op = DW_OP_deref; else op = DW_OP_deref_size; - add_loc_descr (&ret, new_loc_descr (op, size, 0)); + if (ret) + add_loc_descr (&ret, new_loc_descr (op, size, 0)); + else + add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0)); } + if (ret) + list_ret = single_element_loc_list (ret); - return ret; + return list_ret; } -static inline dw_loc_descr_ref -loc_descriptor_from_tree (tree loc) +/* Same as above but return only single location expression. */ +static dw_loc_descr_ref +loc_descriptor_from_tree (tree loc, int want_address) { - return loc_descriptor_from_tree_1 (loc, 2); + dw_loc_list_ref ret = loc_list_from_tree (loc, want_address); + if (!ret) + return NULL; + if (ret->dw_loc_next) + { + expansion_failed (loc, NULL_RTX, + "Location list where only loc descriptor needed"); + return NULL; + } + return ret->expr; } /* Given a value, round it up to the lowest multiple of `boundary' @@ -11632,9 +14856,9 @@ field_byte_offset (const_tree decl) field_size_tree = DECL_SIZE (decl); /* The size could be unspecified if there was an error, or for - a flexible array member. */ + a flexible array member. */ if (!field_size_tree) - field_size_tree = bitsize_zero_node; + field_size_tree = bitsize_zero_node; /* If the size of the field is not constant, use the type size. */ if (host_integerp (field_size_tree, 1)) @@ -11729,10 +14953,14 @@ field_byte_offset (const_tree decl) static inline void add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind, - dw_loc_descr_ref descr) + dw_loc_list_ref descr) { - if (descr != 0) - add_AT_loc (die, attr_kind, descr); + if (descr == 0) + return; + if (single_element_loc_list_p (descr)) + add_AT_loc (die, attr_kind, descr->expr); + else + add_AT_loc_list (die, attr_kind, descr); } /* Attach the specialized form of location attribute used for data members of @@ -11818,11 +15046,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 @@ -11831,7 +15059,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); } } @@ -11895,7 +15123,7 @@ insert_float (const_rtx rtl, unsigned char *array) to an inlined function. They can also arise in C++ where declared constants do not necessarily get memory "homes". */ -static void +static bool add_const_value_attribute (dw_die_ref die, rtx rtl) { switch (GET_CODE (rtl)) @@ -11909,13 +15137,13 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) else add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val); } - break; + return true; case CONST_DOUBLE: /* 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. */ + represented. */ { enum machine_mode mode = GET_MODE (rtl); @@ -11928,15 +15156,10 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) add_AT_vec (die, DW_AT_const_value, length / 4, 4, array); } else - { - /* ??? We really should be using HOST_WIDE_INT throughout. */ - gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT); - - add_AT_long_long (die, DW_AT_const_value, - CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); - } + add_AT_double (die, DW_AT_const_value, + CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); } - break; + return true; case CONST_VECTOR: { @@ -12004,18 +15227,25 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) add_AT_vec (die, DW_AT_const_value, length, elt_size, array); } - break; + return true; case CONST_STRING: - add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0)); - break; + 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; + case CONST: + if (CONSTANT_P (XEXP (rtl, 0))) + return add_const_value_attribute (die, XEXP (rtl, 0)); + /* FALLTHROUGH */ case SYMBOL_REF: + if (!const_ok_for_output (rtl)) + return false; case LABEL_REF: - case CONST: add_AT_addr (die, DW_AT_const_value, rtl); VEC_safe_push (rtx, gc, used_rtx_array, rtl); - break; + return true; case PLUS: /* In cases where an inlined instance of an inline function is passed @@ -12029,13 +15259,27 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) *value* which the artificial local variable always has during its lifetime. We currently have no way to represent such quasi-constant values in Dwarf, so for now we just punt and generate nothing. */ - break; + return false; + + case HIGH: + case CONST_FIXED: + return false; + + case MEM: + if (GET_CODE (XEXP (rtl, 0)) == CONST_STRING + && MEM_READONLY_P (rtl) + && GET_MODE (rtl) == BLKmode) + { + add_AT_string (die, DW_AT_const_value, XSTR (XEXP (rtl, 0), 0)); + return true; + } + return false; default: /* No other kinds of rtx should be possible here. */ gcc_unreachable (); } - + return false; } /* Determine whether the evaluation of EXPR references any variables @@ -12057,17 +15301,20 @@ reference_to_unused (tree * tp, int * walk_subtrees, else if (!cgraph_global_info_ready && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL)) return *tp; - else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL) + else if (TREE_CODE (*tp) == VAR_DECL) { struct varpool_node *node = varpool_node (*tp); if (!node->needed) return *tp; } - else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL + else if (TREE_CODE (*tp) == FUNCTION_DECL && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp))) { - struct cgraph_node *node = cgraph_node (*tp); - if (node->process || TREE_ASM_WRITTEN (*tp)) + /* The call graph machinery must have finished analyzing, + optimizing and gimplifying the CU by now. + So if *TP has no call graph node associated + to it, it means *TP will not be emitted. */ + if (!cgraph_get_node (*tp)) return *tp; } else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp)) @@ -12099,8 +15346,12 @@ rtl_for_decl_init (tree init, tree type) TREE_STRING_LENGTH (init) - 1) == 0 && ((size_t) TREE_STRING_LENGTH (init) == strlen (TREE_STRING_POINTER (init)) + 1)) - rtl = gen_rtx_CONST_STRING (VOIDmode, - ggc_strdup (TREE_STRING_POINTER (init))); + { + rtl = gen_rtx_CONST_STRING (VOIDmode, + ggc_strdup (TREE_STRING_POINTER (init))); + rtl = gen_rtx_MEM (BLKmode, rtl); + MEM_READONLY_P (rtl) = 1; + } } /* Other aggregates, and complex values, could be represented using CONCAT: FIXME! */ @@ -12361,37 +15612,28 @@ rtl_for_decl_location (tree decl) if (rtl) rtl = avoid_constant_pool_reference (rtl); - return rtl; -} - -/* We need to figure out what section we should use as the base for the - address ranges where a given location is valid. - 1. If this particular DECL has a section associated with it, use that. - 2. If this function has a section associated with it, use that. - 3. Otherwise, use the text section. - XXX: If you split a variable across multiple sections, we won't notice. */ - -static const char * -secname_for_decl (const_tree decl) -{ - const char *secname; - - if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl)) - { - tree sectree = DECL_SECTION_NAME (decl); - secname = TREE_STRING_POINTER (sectree); - } - else if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) - { - tree sectree = DECL_SECTION_NAME (current_function_decl); - secname = TREE_STRING_POINTER (sectree); + /* 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 = DECL_RTL (decl); + /* Reset DECL_RTL back, as various parts of the compiler expects + DECL_RTL set meaning it is actually going to be output. */ + SET_DECL_RTL (decl, NULL); + if (!MEM_P (rtl) + || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF + || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl) + rtl = NULL_RTX; } - else if (cfun && in_cold_section_p) - secname = crtl->subsections.cold_section_label; - else - secname = text_section_label; - return secname; + return rtl; } /* Check whether decl is a Fortran COMMON symbol. If not, NULL_TREE is @@ -12407,12 +15649,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 ()) @@ -12444,60 +15685,6 @@ fortran_common (tree decl, HOST_WIDE_INT *value) return cvar; } -/* Dereference a location expression LOC if DECL is passed by invisible - reference. */ - -static dw_loc_descr_ref -loc_by_reference (dw_loc_descr_ref loc, tree decl) -{ - HOST_WIDE_INT size; - enum dwarf_location_atom op; - - if (loc == NULL) - return NULL; - - if ((TREE_CODE (decl) != PARM_DECL - && TREE_CODE (decl) != RESULT_DECL - && TREE_CODE (decl) != VAR_DECL) - || !DECL_BY_REFERENCE (decl)) - return loc; - - /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead - change it into corresponding DW_OP_breg{0...31,x} 0. Then the - location expression is considered to be address of a memory location, - rather than the register itself. */ - if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31) - || loc->dw_loc_opc == DW_OP_regx) - && (loc->dw_loc_next == NULL - || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit - && loc->dw_loc_next->dw_loc_next == NULL))) - { - if (loc->dw_loc_opc == DW_OP_regx) - { - loc->dw_loc_opc = DW_OP_bregx; - loc->dw_loc_oprnd2.v.val_int = 0; - } - else - { - loc->dw_loc_opc - = (enum dwarf_location_atom) - (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0)); - loc->dw_loc_oprnd1.v.val_int = 0; - } - return loc; - } - - size = int_size_in_bytes (TREE_TYPE (decl)); - if (size > DWARF2_ADDR_SIZE || size == -1) - return 0; - else if (size == DWARF2_ADDR_SIZE) - op = DW_OP_deref; - else - op = DW_OP_deref_size; - add_loc_descr (&loc, new_loc_descr (op, size, 0)); - return loc; -} - /* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value data attribute for a variable or a parameter. We generate the DW_AT_const_value attribute only in those cases where the given variable @@ -12509,137 +15696,54 @@ loc_by_reference (dw_loc_descr_ref loc, tree decl) pointer. This can happen for example if an actual argument in an inlined function call evaluates to a compile-time constant address. */ -static void +static bool add_location_or_const_value_attribute (dw_die_ref die, tree decl, enum dwarf_attribute attr) { rtx rtl; - dw_loc_descr_ref descr; + dw_loc_list_ref list; var_loc_list *loc_list; - struct var_loc_node *node; + if (TREE_CODE (decl) == ERROR_MARK) - return; + return false; gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL); - /* See if we possibly have multiple locations for this variable. */ - loc_list = lookup_decl_loc (decl); - - /* If it truly has multiple locations, the first and last node will - differ. */ - if (loc_list && loc_list->first != loc_list->last) - { - const char *endname, *secname; - dw_loc_list_ref list; - rtx varloc; - enum var_init_status initialized; - - /* Now that we know what section we are using for a base, - actually construct the list of locations. - The first location information is what is passed to the - function that creates the location list, and the remaining - locations just get added on to that list. - Note that we only know the start address for a location - (IE location changes), so to build the range, we use - the range [current location start, next location start]. - 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; - varloc = NOTE_VAR_LOCATION (node->var_loc_note); - 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; - - descr = loc_by_reference (loc_descriptor (varloc, initialized), decl); - list = new_loc_list (descr, node->label, node->next->label, secname, 1); - node = node->next; - - for (; 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 - NODE->NEXT->LABEL. */ - enum var_init_status initialized = - NOTE_VAR_LOCATION_STATUS (node->var_loc_note); - varloc = NOTE_VAR_LOCATION (node->var_loc_note); - descr = loc_by_reference (loc_descriptor (varloc, initialized), - decl); - add_loc_descr_to_loc_list (&list, descr, - node->label, node->next->label, secname); - } - - /* 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) - { - char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; - enum var_init_status initialized = - NOTE_VAR_LOCATION_STATUS (node->var_loc_note); - - varloc = NOTE_VAR_LOCATION (node->var_loc_note); - 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); - } - descr = loc_by_reference (loc_descriptor (varloc, initialized), - decl); - add_loc_descr_to_loc_list (&list, descr, - node->label, endname, secname); - } - - /* Finally, add the location list to the DIE, and we are done. */ - add_AT_loc_list (die, attr, list); - return; - } - /* Try to get some constant RTL for this decl, and use that as the value of the location. */ rtl = rtl_for_decl_location (decl); - if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)) - { - add_const_value_attribute (die, rtl); - return; - } + if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING) + && add_const_value_attribute (die, rtl)) + return true; - /* If we have tried to generate the location otherwise, and it - didn't work out (we wouldn't be here if we did), and we have a one entry - location list, try generating a location from that. */ - if (loc_list && loc_list->first) + /* See if we have single element location list that is equivalent to + 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) { - enum var_init_status status; + struct var_loc_node *node; + node = loc_list->first; - status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); - descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status); - if (descr) - { - descr = loc_by_reference (descr, decl); - add_AT_location_description (die, attr, descr); - return; - } + 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); + if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING) + && add_const_value_attribute (die, rtl)) + return true; } - - /* We couldn't get any rtl, so try directly generating the location - description from the tree. */ - descr = loc_descriptor_from_tree (decl); - if (descr) + list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2); + if (list) { - descr = loc_by_reference (descr, decl); - add_AT_location_description (die, attr, descr); - return; + add_AT_location_description (die, attr, list); + return true; } /* None of that worked, so it must not really have a location; try adding a constant value attribute from the DECL_INITIAL. */ - tree_add_const_value_attribute (die, decl); + return tree_add_const_value_attribute_for_decl (die, decl); } /* Add VARIABLE and DIE into deferred locations list. */ @@ -12800,29 +15904,25 @@ native_encode_initializer (tree init, unsigned char *array, int size) } } -/* If we don't have a copy of this variable in memory for some reason (such - as a C++ member constant that doesn't have an out-of-line definition), - we should tell the debugger about the constant value. */ +/* Attach a DW_AT_const_value attribute to DIE. The value of the + attribute is the const value T. */ -static void -tree_add_const_value_attribute (dw_die_ref var_die, tree decl) +static bool +tree_add_const_value_attribute (dw_die_ref die, tree t) { tree init; - tree type = TREE_TYPE (decl); + tree type = TREE_TYPE (t); rtx rtl; - if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL) - return; + if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node) + return false; - init = DECL_INITIAL (decl); - if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init) - /* OK */; - else - return; + init = t; + gcc_assert (!DECL_P (init)); rtl = rtl_for_decl_init (init, type); if (rtl) - add_const_value_attribute (var_die, 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)) @@ -12833,9 +15933,41 @@ tree_add_const_value_attribute (dw_die_ref var_die, tree decl) unsigned char *array = GGC_CNEWVEC (unsigned char, size); if (native_encode_initializer (init, array, size)) - add_AT_vec (var_die, DW_AT_const_value, size, 1, array); + { + add_AT_vec (die, DW_AT_const_value, size, 1, array); + return true; + } } } + return false; +} + +/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the + attribute is the const value of T, where T is an integral constant + variable with static storage duration + (so it can't be a PARM_DECL or a RESULT_DECL). */ + +static bool +tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl) +{ + + if (!decl + || (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != CONST_DECL)) + return false; + + if (TREE_READONLY (decl) + && ! TREE_THIS_VOLATILE (decl) + && DECL_INITIAL (decl)) + /* OK */; + 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)); } /* Convert the CFI instructions for the current function into a @@ -13008,14 +16140,33 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b /* All fixed-bounds are represented by INTEGER_CST nodes. */ case INTEGER_CST: - if (! host_integerp (bound, 0) - || (bound_attr == DW_AT_lower_bound - && (((is_c_family () || is_java ()) && integer_zerop (bound)) - || (is_fortran () && integer_onep (bound))))) - /* Use the default. */ - ; - else - add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0)); + { + unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound)); + + /* Use the default if possible. */ + if (bound_attr == DW_AT_lower_bound + && (((is_c_family () || is_java ()) && integer_zerop (bound)) + || (is_fortran () && integer_onep (bound)))) + ; + + /* Otherwise represent the bound as an unsigned value with the + precision of its type. The precision and signedness of the + type will be necessary to re-interpret it unambiguously. */ + else if (prec < HOST_BITS_PER_WIDE_INT) + { + unsigned HOST_WIDE_INT mask + = ((unsigned HOST_WIDE_INT) 1 << prec) - 1; + add_AT_unsigned (subrange_die, bound_attr, + TREE_INT_CST_LOW (bound) & mask); + } + else if (prec == HOST_BITS_PER_WIDE_INT + || TREE_INT_CST_HIGH (bound) == 0) + add_AT_unsigned (subrange_die, bound_attr, + TREE_INT_CST_LOW (bound)); + else + add_AT_double (subrange_die, bound_attr, TREE_INT_CST_HIGH (bound), + TREE_INT_CST_LOW (bound)); + } break; CASE_CONVERT: @@ -13031,7 +16182,7 @@ 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_descr_ref loc; + 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 @@ -13042,7 +16193,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b add_AT_die_ref (subrange_die, bound_attr, decl_die); else { - loc = loc_descriptor_from_tree_1 (bound, 0); + loc = loc_list_from_tree (bound, 0); add_AT_location_description (subrange_die, bound_attr, loc); } break; @@ -13054,10 +16205,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b evaluate the value of the array bound. */ dw_die_ref ctx, decl_die; - dw_loc_descr_ref loc; + dw_loc_list_ref list; - loc = loc_descriptor_from_tree (bound); - if (loc == NULL) + list = loc_list_from_tree (bound, 2); + if (list == NULL) break; if (current_function_decl == 0) @@ -13068,7 +16219,10 @@ 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); - add_AT_loc (decl_die, DW_AT_location, loc); + 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_die_ref (subrange_die, bound_attr, decl_die); break; @@ -13350,7 +16504,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); @@ -13674,12 +16830,12 @@ gen_array_type_die (tree type, dw_die_ref context_die) && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) { tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - dw_loc_descr_ref loc = loc_descriptor_from_tree (szdecl); + dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2); size = int_size_in_bytes (TREE_TYPE (szdecl)); if (loc && size > 0) { - add_AT_loc (array_die, DW_AT_string_length, loc); + add_AT_location_description (array_die, DW_AT_string_length, loc); if (size != DWARF2_ADDR_SIZE) add_AT_unsigned (array_die, DW_AT_byte_size, size); } @@ -13738,7 +16894,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) @@ -13773,7 +16929,7 @@ descr_info_loc (tree val, tree base_decl) CASE_CONVERT: return descr_info_loc (TREE_OPERAND (val, 0), base_decl); case VAR_DECL: - return loc_descriptor_from_tree_1 (val, 0); + return loc_descriptor_from_tree (val, 0); case INTEGER_CST: if (host_integerp (val, 0)) return int_loc_descriptor (tree_low_cst (val, 0)); @@ -13970,7 +17126,9 @@ record_type_tag (tree type) return DW_TAG_class_type; case RECORD_IS_INTERFACE: - return DW_TAG_interface_type; + if (dwarf_version >= 3 || !dwarf_strict) + return DW_TAG_interface_type; + return DW_TAG_structure_type; default: gcc_unreachable (); @@ -14059,10 +17217,13 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die) DIE to represent a formal parameter object (or some inlining thereof). If it's the latter, then this function is only being called to output a DW_TAG_formal_parameter DIE to stand as a placeholder for some formal - argument type of some subprogram type. */ + argument type of some subprogram type. + If EMIT_NAME_P is true, name and source coordinate attributes + are emitted. */ static dw_die_ref -gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die) +gen_formal_parameter_die (tree node, tree origin, bool emit_name_p, + dw_die_ref context_die) { tree node_or_origin = node ? node : origin; dw_die_ref parm_die @@ -14078,8 +17239,9 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die) else { tree type = TREE_TYPE (node); - add_name_and_src_coords_attributes (parm_die, node); - if (DECL_BY_REFERENCE (node)) + if (emit_name_p) + add_name_and_src_coords_attributes (parm_die, node); + if (decl_by_reference_p (node)) add_type_attribute (parm_die, TREE_TYPE (type), 0, 0, context_die); else @@ -14111,6 +17273,47 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die) return parm_die; } +/* Generate and return a DW_TAG_GNU_formal_parameter_pack. Also generate + children DW_TAG_formal_parameter DIEs representing the arguments of the + parameter pack. + + PARM_PACK must be a function parameter pack. + PACK_ARG is the first argument of the parameter pack. Its TREE_CHAIN + must point to the subsequent arguments of the function PACK_ARG belongs to. + SUBR_DIE is the DIE of the function PACK_ARG belongs to. + If NEXT_ARG is non NULL, *NEXT_ARG is set to the function argument + following the last one for which a DIE was generated. */ + +static dw_die_ref +gen_formal_parameter_pack_die (tree parm_pack, + tree pack_arg, + dw_die_ref subr_die, + tree *next_arg) +{ + tree arg; + dw_die_ref parm_pack_die; + + gcc_assert (parm_pack + && lang_hooks.function_parameter_pack_p (parm_pack) + && subr_die); + + parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack); + add_src_coords_attributes (parm_pack_die, parm_pack); + + for (arg = pack_arg; arg; arg = TREE_CHAIN (arg)) + { + if (! lang_hooks.decls.function_parm_expanded_from_pack_p (arg, + parm_pack)) + break; + gen_formal_parameter_die (arg, NULL, + false /* Don't emit name attribute. */, + parm_pack_die); + } + if (next_arg) + *next_arg = arg; + return parm_pack_die; +} + /* Generate a special type of DIE used as a stand-in for a trailing ellipsis at the end of an (ANSI prototyped) formal parameters list. */ @@ -14154,7 +17357,9 @@ gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die) break; /* Output a (nameless) DIE to represent the formal parameter itself. */ - parm_die = gen_formal_parameter_die (formal_type, NULL, context_die); + parm_die = gen_formal_parameter_die (formal_type, NULL, + true /* Emit name attribute. */, + context_die); if ((TREE_CODE (function_or_method_type) == METHOD_TYPE && link == first_parm_type) || (arg && DECL_ARTIFICIAL (arg))) @@ -14230,16 +17435,22 @@ dwarf2out_abstract_function (tree decl) tree save_fn; tree context; int was_abstract = DECL_ABSTRACT (decl); + htab_t old_decl_loc_table; /* Make sure we have the actual abstract inline, not a clone. */ decl = DECL_ORIGIN (decl); - htab_empty (decl_loc_table); 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; + /* Be sure we've emitted the in-class declaration DIE (if any) first, so we don't get confused by DECL_ABSTRACT. */ if (debug_info_level > DINFO_LEVEL_TERSE) @@ -14261,14 +17472,16 @@ dwarf2out_abstract_function (tree decl) set_decl_abstract_flags (decl, 0); current_function_decl = save_fn; + decl_loc_table = old_decl_loc_table; pop_cfun (); } /* Helper function of premark_used_types() which gets called through - htab_traverse_resize(). + htab_traverse. Marks the DIE of a given type in *SLOT as perennial, so it never gets marked as unused by prune_unused_types. */ + static int premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED) { @@ -14282,7 +17495,42 @@ premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED) return 1; } +/* Helper function of premark_types_used_by_global_vars which gets called + through htab_traverse. + + Marks the DIE of a given type in *SLOT as perennial, so it never gets + marked as unused by prune_unused_types. The DIE of the type is marked + only if the global variable using the type will actually be emitted. */ + +static int +premark_types_used_by_global_vars_helper (void **slot, + void *data ATTRIBUTE_UNUSED) +{ + struct types_used_by_vars_entry *entry; + dw_die_ref die; + + entry = (struct types_used_by_vars_entry *) *slot; + gcc_assert (entry->type != NULL + && entry->var_decl != NULL); + die = lookup_type_die (entry->type); + if (die) + { + /* Ask cgraph if the global variable really is to be emitted. + If yes, then we'll keep the DIE of ENTRY->TYPE. */ + struct varpool_node *node = varpool_node (entry->var_decl); + if (node->needed) + { + die->die_perennial_p = 1; + /* Keep the parent DIEs as well. */ + while ((die = die->die_parent) && die->die_perennial_p == 0) + die->die_perennial_p = 1; + } + } + return 1; +} + /* Mark all members of used_types_hash as perennial. */ + static void premark_used_types (void) { @@ -14290,6 +17538,16 @@ premark_used_types (void) htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL); } +/* Mark all members of types_used_by_vars_entry as perennial. */ + +static void +premark_types_used_by_global_vars (void) +{ + if (types_used_by_vars_hash) + htab_traverse (types_used_by_vars_hash, + premark_types_used_by_global_vars_helper, NULL); +} + /* Generate a DIE to represent a declared function (either file-scope or block-local). */ @@ -14422,7 +17680,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) /* If this is an explicit function declaration then generate a DW_AT_explicit attribute. */ - if (lang_hooks.decls.function_decl_explicit_p (decl)) + if (lang_hooks.decls.function_decl_explicit_p (decl) + && (dwarf_version >= 3 || !dwarf_strict)) add_AT_flag (subr_die, DW_AT_explicit, 1); /* The first time we see a member function, it is in the context of @@ -14531,9 +17790,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (cfun->static_chain_decl) add_AT_location_description (subr_die, DW_AT_static_link, - loc_descriptor_from_tree (cfun->static_chain_decl)); + loc_list_from_tree (cfun->static_chain_decl, 2)); } + /* Generate child dies for template paramaters. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + gen_generic_params_dies (decl); + /* 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 @@ -14554,21 +17817,46 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) else { /* Generate DIEs to represent all known formal parameters. */ - tree arg_decls = DECL_ARGUMENTS (decl); - tree parm; - - /* When generating DIEs, generate the unspecified_parameters DIE - instead if we come across the arg "__builtin_va_alist" */ - for (parm = arg_decls; parm; parm = TREE_CHAIN (parm)) - if (TREE_CODE (parm) == PARM_DECL) - { - if (DECL_NAME (parm) - && !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)), - "__builtin_va_alist")) - gen_unspecified_parameters_die (parm, subr_die); - else + tree parm = DECL_ARGUMENTS (decl); + tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl); + 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) + { gen_decl_die (parm, NULL, subr_die); - } + parm = TREE_CHAIN (parm); + } + + if (generic_decl_parm) + generic_decl_parm = TREE_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 - @@ -14664,26 +17952,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_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) @@ -14695,9 +17963,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) of a data member. */ if (com_decl) { - tree field; dw_die_ref com_die; - dw_loc_descr_ref loc; + dw_loc_list_ref loc; die_node com_die_arg; var_die = lookup_decl_die (decl_or_origin); @@ -14705,22 +17972,23 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) { if (get_AT (var_die, DW_AT_location) == NULL) { - loc = loc_descriptor_from_tree (com_decl); + loc = loc_list_from_tree (com_decl, off ? 1 : 2); if (loc) { if (off) { /* Optimize the common case. */ - if (loc->dw_loc_opc == DW_OP_addr - && loc->dw_loc_next == NULL - && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) + if (single_element_loc_list_p (loc) + && loc->expr->dw_loc_opc == DW_OP_addr + && loc->expr->dw_loc_next == NULL + && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) - loc->dw_loc_oprnd1.v.val_addr - = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off); + loc->expr->dw_loc_oprnd1.v.val_addr + = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off); else - loc_descr_plus_const (&loc, off); + loc_list_plus_const (loc, off); } - add_AT_loc (var_die, DW_AT_location, loc); + add_AT_location_description (var_die, DW_AT_location, loc); remove_AT (var_die, DW_AT_declaration); } } @@ -14732,11 +18000,10 @@ 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); - loc = loc_descriptor_from_tree (com_decl); + loc = loc_list_from_tree (com_decl, 2); if (com_die == NULL) { const char *cnam @@ -14747,10 +18014,10 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) add_name_and_src_coords_attributes (com_die, com_decl); if (loc) { - add_AT_loc (com_die, DW_AT_location, loc); + add_AT_location_description (com_die, DW_AT_location, loc); /* Avoid sharing the same loc descriptor between DW_TAG_common_block and DW_TAG_variable. */ - loc = loc_descriptor_from_tree (com_decl); + loc = loc_list_from_tree (com_decl, 2); } else if (DECL_EXTERNAL (decl)) add_AT_flag (com_die, DW_AT_declaration, 1); @@ -14761,8 +18028,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) } else if (get_AT (com_die, DW_AT_location) == NULL && loc) { - add_AT_loc (com_die, DW_AT_location, loc); - loc = loc_descriptor_from_tree (com_decl); + add_AT_location_description (com_die, DW_AT_location, loc); + loc = loc_list_from_tree (com_decl, 2); remove_AT (com_die, DW_AT_declaration); } var_die = new_die (DW_TAG_variable, com_die, decl); @@ -14775,15 +18042,16 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) if (off) { /* Optimize the common case. */ - if (loc->dw_loc_opc == DW_OP_addr - && loc->dw_loc_next == NULL - && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) - loc->dw_loc_oprnd1.v.val_addr - = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off); + if (single_element_loc_list_p (loc) + && loc->expr->dw_loc_opc == DW_OP_addr + && loc->expr->dw_loc_next == NULL + && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) + loc->expr->dw_loc_oprnd1.v.val_addr + = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off); else - loc_descr_plus_const (&loc, off); + loc_list_plus_const (loc, off); } - add_AT_loc (var_die, DW_AT_location, loc); + add_AT_location_description (var_die, DW_AT_location, loc); } else if (DECL_EXTERNAL (decl)) add_AT_flag (var_die, DW_AT_declaration, 1); @@ -14795,8 +18063,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 @@ -14846,10 +18113,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) tree type = TREE_TYPE (decl); add_name_and_src_coords_attributes (var_die, decl); - if ((TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL - || TREE_CODE (decl) == VAR_DECL) - && DECL_BY_REFERENCE (decl)) + if (decl_by_reference_p (decl)) add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die); else add_type_attribute (var_die, type, TREE_READONLY (decl), @@ -14895,7 +18159,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) add_pubname (decl_or_origin, var_die); } else - tree_add_const_value_attribute (var_die, decl_or_origin); + tree_add_const_value_attribute_for_decl (var_die, decl_or_origin); } /* Generate a DIE to represent a named constant. */ @@ -14913,7 +18177,7 @@ gen_const_die (tree decl, dw_die_ref context_die) add_AT_flag (const_die, DW_AT_external, 1); if (DECL_ARTIFICIAL (decl)) add_AT_flag (const_die, DW_AT_artificial, 1); - tree_add_const_value_attribute (const_die, decl); + tree_add_const_value_attribute_for_decl (const_die, decl); } /* Generate a DIE to represent a label identifier. */ @@ -14967,8 +18231,11 @@ add_call_src_coords_attributes (tree stmt, dw_die_ref die) { expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt)); - add_AT_file (die, DW_AT_call_file, lookup_filename (s.file)); - add_AT_unsigned (die, DW_AT_call_line, s.line); + if (dwarf_version >= 3 || !dwarf_strict) + { + add_AT_file (die, DW_AT_call_file, lookup_filename (s.file)); + add_AT_unsigned (die, DW_AT_call_line, s.line); + } } @@ -14980,7 +18247,8 @@ add_high_low_attributes (tree stmt, dw_die_ref die) { char label[MAX_ARTIFICIAL_LABEL_BYTES]; - if (BLOCK_FRAGMENT_CHAIN (stmt)) + if (BLOCK_FRAGMENT_CHAIN (stmt) + && (dwarf_version >= 3 || !dwarf_strict)) { tree chain; @@ -15182,24 +18450,26 @@ gen_compile_unit_die (const char *filename) add_AT_string (die, DW_AT_producer, producer); + language = DW_LANG_C89; if (strcmp (language_string, "GNU C++") == 0) language = DW_LANG_C_plus_plus; - else if (strcmp (language_string, "GNU Ada") == 0) - language = DW_LANG_Ada95; else if (strcmp (language_string, "GNU F77") == 0) language = DW_LANG_Fortran77; - else if (strcmp (language_string, "GNU Fortran") == 0) - language = DW_LANG_Fortran95; else if (strcmp (language_string, "GNU Pascal") == 0) language = DW_LANG_Pascal83; - else if (strcmp (language_string, "GNU Java") == 0) - language = DW_LANG_Java; - else if (strcmp (language_string, "GNU Objective-C") == 0) - language = DW_LANG_ObjC; - else if (strcmp (language_string, "GNU Objective-C++") == 0) - language = DW_LANG_ObjC_plus_plus; - else - language = DW_LANG_C89; + else if (dwarf_version >= 3 || !dwarf_strict) + { + if (strcmp (language_string, "GNU Ada") == 0) + language = DW_LANG_Ada95; + else if (strcmp (language_string, "GNU Fortran") == 0) + language = DW_LANG_Fortran95; + else if (strcmp (language_string, "GNU Java") == 0) + language = DW_LANG_Java; + else if (strcmp (language_string, "GNU Objective-C") == 0) + language = DW_LANG_ObjC; + else if (strcmp (language_string, "GNU Objective-C++") == 0) + language = DW_LANG_ObjC_plus_plus; + } add_AT_unsigned (die, DW_AT_language, language); return die; @@ -15332,6 +18602,11 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, else remove_AT (type_die, DW_AT_declaration); + /* Generate child dies for template paramaters. */ + if (debug_info_level > DINFO_LEVEL_TERSE + && COMPLETE_TYPE_P (type)) + gen_generic_params_dies (type); + /* If this type has been completed, then give it a byte_size attribute and then give a list of members. */ if (complete && !ns_decl) @@ -15474,7 +18749,8 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, /* If this is an array type with hidden descriptor, handle it first. */ if (!TREE_ASM_WRITTEN (type) && lang_hooks.types.get_array_descr_info - && lang_hooks.types.get_array_descr_info (type, &info)) + && lang_hooks.types.get_array_descr_info (type, &info) + && (dwarf_version >= 3 || !dwarf_strict)) { gen_descr_array_type_die (type, &info, context_die); TREE_ASM_WRITTEN (type) = 1; @@ -15812,7 +19088,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); } @@ -15858,7 +19134,11 @@ force_decl_die (tree decl) break; case NAMESPACE_DECL: - dwarf2out_decl (decl); + if (dwarf_version >= 3 || !dwarf_strict) + dwarf2out_decl (decl); + else + /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace. */ + decl_die = comp_unit_die; break; default: @@ -15961,7 +19241,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)) @@ -16121,9 +19405,7 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) /* Output any DIEs that are needed to specify the type of this data object. */ - if ((TREE_CODE (decl_or_origin) == RESULT_DECL - || TREE_CODE (decl_or_origin) == VAR_DECL) - && DECL_BY_REFERENCE (decl_or_origin)) + if (decl_by_reference_p (decl_or_origin)) gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die); else gen_type_die (TREE_TYPE (decl_or_origin), context_die); @@ -16143,7 +19425,9 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) if (!origin) origin = decl_ultimate_origin (decl); if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL) - gen_formal_parameter_die (decl, origin, context_die); + gen_formal_parameter_die (decl, origin, + true /* Emit name attribute. */, + context_die); else gen_variable_die (decl, origin, context_die); break; @@ -16165,12 +19449,15 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die); else gen_type_die (TREE_TYPE (decl_or_origin), context_die); - gen_formal_parameter_die (decl, origin, context_die); + gen_formal_parameter_die (decl, origin, + true /* Emit name attribute. */, + context_die); break; case NAMESPACE_DECL: case IMPORTED_DECL: - gen_namespace_die (decl, context_die); + if (dwarf_version >= 3 || !dwarf_strict) + gen_namespace_die (decl, context_die); break; default: @@ -16268,9 +19555,14 @@ dwarf2out_imported_module_or_decl_1 (tree decl, } if (TREE_CODE (decl) == NAMESPACE_DECL) - imported_die = new_die (DW_TAG_imported_module, - lexical_block_die, - lexical_block); + { + if (dwarf_version >= 3 || !dwarf_strict) + imported_die = new_die (DW_TAG_imported_module, + lexical_block_die, + lexical_block); + else + return; + } else imported_die = new_die (DW_TAG_imported_declaration, lexical_block_die, @@ -16311,6 +19603,10 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context, && TYPE_P (context) && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE)) return; + + if (!(dwarf_version >= 3 || !dwarf_strict)) + return; + scope_die = get_context_die (context); if (child) @@ -16587,30 +19883,207 @@ maybe_emit_file (struct dwarf_file_data * fd) return fd->emitted_number; } +/* Schedule generation of a DW_AT_const_value attribute to DIE. + That generation should happen after function debug info has been + generated. The value of the attribute is the constant value of ARG. */ + +static void +append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg) +{ + die_arg_entry entry; + + if (!die || !arg) + return; + + if (!tmpl_value_parm_die_table) + tmpl_value_parm_die_table + = VEC_alloc (die_arg_entry, gc, 32); + + entry.die = die; + entry.arg = arg; + VEC_safe_push (die_arg_entry, gc, + tmpl_value_parm_die_table, + &entry); +} + +/* Add a DW_AT_const_value attribute to DIEs that were scheduled + by append_entry_to_tmpl_value_parm_die_table. This function must + be called after function DIEs have been generated. */ + +static void +gen_remaining_tmpl_value_param_die_attribute (void) +{ + if (tmpl_value_parm_die_table) + { + unsigned i; + die_arg_entry *e; + + for (i = 0; + VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e); + i++) + tree_add_const_value_attribute (e->die, e->arg); + } +} + + /* 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 @@ -16620,10 +20093,11 @@ dwarf2out_set_name (tree decl, tree name) static void dwarf2out_var_location (rtx loc_note) { - char loclabel[MAX_ARTIFICIAL_LABEL_BYTES]; + char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2]; struct var_loc_node *newloc; rtx next_real; static const char *last_label; + static const char *last_postcall_label; static bool last_in_cold_section_p; tree decl; @@ -16639,27 +20113,37 @@ dwarf2out_var_location (rtx loc_note) newloc = GGC_CNEW (struct var_loc_node); /* 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 - && last_var_location_insn == next_real - && last_in_cold_section_p == in_cold_section_p) - newloc->label = last_label; - else + if (last_var_location_insn == NULL_RTX + || last_var_location_insn != next_real + || last_in_cold_section_p != in_cold_section_p) { ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num); ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num); loclabel_num++; - newloc->label = ggc_strdup (loclabel); + last_label = ggc_strdup (loclabel); + last_postcall_label = NULL; } newloc->var_loc_note = loc_note; newloc->next = NULL; + if (!NOTE_DURING_CALL_P (loc_note)) + newloc->label = last_label; + else + { + if (!last_postcall_label) + { + sprintf (loclabel, "%s-1", last_label); + last_postcall_label = ggc_strdup (loclabel); + } + 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_label = newloc->label; last_in_cold_section_p = in_cold_section_p; decl = NOTE_VAR_LOCATION_DECL (loc_note); add_var_loc_to_decl (decl, newloc); @@ -16780,7 +20264,7 @@ dwarf2out_source_line (unsigned int line, const char *filename, static void dwarf2out_start_source_file (unsigned int lineno, const char *filename) { - if (flag_eliminate_dwarf2_dups) + if (flag_eliminate_dwarf2_dups && dwarf_version < 4) { /* Record the beginning of the file for break_out_includes. */ dw_die_ref bincl_die; @@ -16807,7 +20291,7 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename) static void dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED) { - if (flag_eliminate_dwarf2_dups) + if (flag_eliminate_dwarf2_dups && dwarf_version < 4) /* Record the end of the file for break_out_includes. */ new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL); @@ -16889,6 +20373,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 @@ -16917,6 +20405,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, @@ -16961,17 +20453,33 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) switch_to_section (cold_text_section); ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label); } + +} + +/* 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"); + } } /* A helper function for dwarf2out_finish called through - ht_forall. Emit one queued .debug_str string. */ + htab_traverse. Emit one queued .debug_str string. */ static int output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED) { struct indirect_string_node *node = (struct indirect_string_node *) *h; - if (node->form == DW_FORM_strp) + if (node->label && node->refcount) { switch_to_section (debug_str_section); ASM_OUTPUT_LABEL (asm_out_file, node->label); @@ -17021,8 +20529,12 @@ prune_unused_types_walk_attribs (dw_die_ref die) if (a->dw_attr_val.val_class == dw_val_class_die_ref) { /* A reference to another DIE. - Make sure that it will get emitted. */ - prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1); + Make sure that it will get emitted. + If it was broken out into a comdat group, don't follow it. */ + if (dwarf_version < 4 + || a->dw_attr == DW_AT_specification + || a->dw_attr_val.v.val_die_ref.die->die_id.die_type_node == NULL) + prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1); } /* Set the string's refcount to 0 so that prune_unused_types_mark accounts properly for it. */ @@ -17066,8 +20578,12 @@ prune_unused_types_mark (dw_die_ref die, int dokids) die->die_mark = 2; /* If this is an array type, we need to make sure our - kids get marked, even if they're types. */ - if (die->die_tag == DW_TAG_array_type) + kids get marked, even if they're types. If we're + breaking out types into comdat sections, do this + for all type definitions. */ + if (die->die_tag == DW_TAG_array_type + || (dwarf_version >= 4 + && is_type_die (die) && ! is_declaration_die (die))) FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1)); else FOR_EACH_CHILD (die, c, prune_unused_types_walk (c)); @@ -17249,6 +20765,20 @@ prune_unused_types_prune (dw_die_ref die) } while (c != die->die_child); } +/* A helper function for dwarf2out_finish called through + htab_traverse. Clear .debug_str strings that we haven't already + decided to emit. */ + +static int +prune_indirect_string (void **h, void *v ATTRIBUTE_UNUSED) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + + if (!node->label || !node->refcount) + htab_clear_slot (debug_str_hash, h); + + return 1; +} /* Remove dies representing declarations that we never use. */ @@ -17257,19 +20787,31 @@ prune_unused_types (void) { unsigned int i; 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. */ verify_marks_clear (comp_unit_die); for (node = limbo_die_list; node; node = node->next) verify_marks_clear (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + verify_marks_clear (ctnode->root_die); #endif /* ENABLE_ASSERT_CHECKING */ + /* Mark types that are used in global variables. */ + premark_types_used_by_global_vars (); + /* Set the mark on nodes that are actually used. */ prune_unused_types_walk (comp_unit_die); for (node = limbo_die_list; node; node = node->next) prune_unused_types_walk (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + { + prune_unused_types_walk (ctnode->root_die); + prune_unused_types_mark (ctnode->type_die, 1); + } /* Also set the mark on nodes referenced from the pubname_table or arange_table. */ @@ -17278,17 +20820,27 @@ 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) + if (debug_str_hash && debug_str_hash_forced) + htab_traverse (debug_str_hash, prune_indirect_string, NULL); + else if (debug_str_hash) htab_empty (debug_str_hash); prune_unused_types_prune (comp_unit_die); for (node = limbo_die_list; node; node = node->next) prune_unused_types_prune (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + prune_unused_types_prune (ctnode->root_die); /* Leave the marks clear. */ prune_unmark_dies (comp_unit_die); for (node = limbo_die_list; node; node = node->next) prune_unmark_dies (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + prune_unmark_dies (ctnode->root_die); } /* Set the parameter to true if there are any relative pathnames in @@ -17306,6 +20858,28 @@ file_table_relative_p (void ** slot, void *param) return 1; } +/* Routines to manipulate hash table of comdat type units. */ + +static hashval_t +htab_ct_hash (const void *of) +{ + hashval_t h; + const comdat_type_node *const type_node = (const comdat_type_node *) of; + + memcpy (&h, type_node->signature, sizeof (h)); + return h; +} + +static int +htab_ct_eq (const void *of1, const void *of2) +{ + const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1; + const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2; + + return (! memcmp (type_node_1->signature, type_node_2->signature, + DWARF_TYPE_SIGNATURE_SIZE)); +} + /* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref to the location it would have been added, should we know its DECL_ASSEMBLER_NAME when we added other attributes. This will @@ -17336,6 +20910,104 @@ move_linkage_attr (dw_die_ref die) } } +/* Helper function for resolve_addr, attempt to resolve + one CONST_STRING, return non-zero if not successful. Similarly verify that + SYMBOL_REFs refer to variables emitted in the current CU. */ + +static int +resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED) +{ + rtx rtl = *addr; + + if (GET_CODE (rtl) == CONST_STRING) + { + size_t len = strlen (XSTR (rtl, 0)) + 1; + tree t = build_string (len, XSTR (rtl, 0)); + tree tlen = build_int_cst (NULL_TREE, len - 1); + TREE_TYPE (t) + = build_array_type (char_type_node, build_index_type (tlen)); + rtl = lookup_constant_def (t); + if (!rtl || !MEM_P (rtl)) + return 1; + rtl = XEXP (rtl, 0); + VEC_safe_push (rtx, gc, used_rtx_array, rtl); + *addr = rtl; + return 0; + } + + if (GET_CODE (rtl) == SYMBOL_REF + && SYMBOL_REF_DECL (rtl) + && TREE_CODE (SYMBOL_REF_DECL (rtl)) == VAR_DECL + && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl))) + return 1; + + if (GET_CODE (rtl) == CONST + && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL)) + return 1; + + return 0; +} + +/* Helper function for resolve_addr, handle one location + expression, return false if at least one CONST_STRING or SYMBOL_REF in + the location list couldn't be resolved. */ + +static bool +resolve_addr_in_expr (dw_loc_descr_ref loc) +{ + for (; loc; loc = loc->dw_loc_next) + if ((loc->dw_loc_opc == DW_OP_addr + && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL)) + || (loc->dw_loc_opc == DW_OP_implicit_value + && loc->dw_loc_oprnd2.val_class == dw_val_class_addr + && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL))) + return false; + return true; +} + +/* Resolve DW_OP_addr and DW_AT_const_value CONST_STRING arguments to + an address in .rodata section if the string literal is emitted there, + or remove the containing location list or replace DW_AT_const_value + with DW_AT_location and empty location expression, if it isn't found + in .rodata. Similarly for SYMBOL_REFs, keep only those that refer + to something that has been emitted in the current CU. */ + +static void +resolve_addr (dw_die_ref die) +{ + dw_die_ref c; + dw_attr_ref a; + 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; + break; + case dw_val_class_loc: + if (!resolve_addr_in_expr (AT_loc (a))) + a->dw_attr_val.v.val_loc = NULL; + 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; + } + break; + default: + break; + } + + FOR_EACH_CHILD (die, c, resolve_addr (c)); +} + /* Output stuff that dwarf requires at the end of every file, and generate the DWARF-2 debugging info. */ @@ -17343,9 +21015,13 @@ static void dwarf2out_finish (const char *filename) { limbo_die_node *node, *next_node; + comdat_type_node *ctnode; + htab_t comdat_type_table; dw_die_ref die = 0; unsigned int i; + 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. */ add_name_attribute (comp_unit_die, remap_debug_filename (filename)); @@ -17424,6 +21100,8 @@ dwarf2out_finish (const char *filename) limbo_die_list = NULL; + resolve_addr (comp_unit_die); + for (node = deferred_asm_name; node; node = node->next) { tree decl = node->created_for; @@ -17446,14 +21124,39 @@ dwarf2out_finish (const char *filename) /* Generate separate CUs for each of the include files we've seen. They will go into limbo_die_list. */ - if (flag_eliminate_dwarf2_dups) + if (flag_eliminate_dwarf2_dups && dwarf_version < 4) break_out_includes (comp_unit_die); + /* Generate separate COMDAT sections for type DIEs. */ + if (dwarf_version >= 4) + { + 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 (); + } + /* 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); /* Output a terminator label for the .text section. */ switch_to_section (text_section); @@ -17466,7 +21169,8 @@ dwarf2out_finish (const char *filename) /* We can only use the low/high_pc attributes if all of the code was in .text. */ - if (!have_multiple_function_sections) + if (!have_multiple_function_sections + || !(dwarf_version >= 3 || !dwarf_strict)) { add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label); add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label); @@ -17535,6 +21239,27 @@ dwarf2out_finish (const char *filename) for (node = limbo_die_list; node; node = node->next) output_comp_unit (node->die, 0); + comdat_type_table = htab_create (100, htab_ct_hash, htab_ct_eq, NULL); + for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next) + { + void **slot = htab_find_slot (comdat_type_table, 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_NORMAL) + add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list, + debug_line_section_label); + + output_comdat_type_unit (ctnode); + *slot = ctnode; + } + htab_delete (comdat_type_table); + /* Output the main compilation unit if non-empty or if .debug_macinfo has been emitted. */ output_comp_unit (comp_unit_die, debug_info_level >= DINFO_LEVEL_VERBOSE); @@ -17560,6 +21285,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) @@ -17607,6 +21344,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { 0, /* init */ 0, /* finish */ + 0, /* assembly_start */ 0, /* define */ 0, /* undef */ 0, /* start_source_file */ @@ -17630,6 +21368,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 */ };