X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fdwarf2out.c;h=b99e45bc36798a50452722f311112e5ce150e38c;hb=4901d80eb64b632a826a5ed0a5785f3c14807b56;hp=71ba002cb85370f74099a53943b98e3a1975f848;hpb=aaec0525605f59f6cafd5cc087716a1cb59ae863;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 71ba002cb85..b99e45bc367 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1,6 +1,6 @@ /* Output Dwarf2 format symbol table information from GCC. Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Gary Funck (gary@intrepid.com). Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). @@ -94,9 +94,11 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "tree-flow.h" #include "cfglayout.h" +#include "opts.h" static void dwarf2out_source_line (unsigned int, const char *, int, bool); static rtx last_var_location_insn; +static rtx cached_next_real_insn; #ifdef VMS_DEBUGGING_INFO int vms_file_stats_name (const char *, long long *, long *, char *, int *); @@ -122,82 +124,6 @@ int vms_file_stats_name (const char *, long long *, long *, char *, int *); #pragma GCC poison DWARF2_UNWIND_INFO DWARF2_FRAME_INFO #endif -#ifndef INCOMING_RETURN_ADDR_RTX -#define INCOMING_RETURN_ADDR_RTX (gcc_unreachable (), NULL_RTX) -#endif - -/* Map register numbers held in the call frame info that gcc has - collected using DWARF_FRAME_REGNUM to those that should be output in - .debug_frame and .eh_frame. */ -#ifndef DWARF2_FRAME_REG_OUT -#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO) -#endif - -/* Save the result of dwarf2out_do_frame across PCH. */ -static GTY(()) bool saved_do_cfi_asm = 0; - -/* Decide whether we want to emit frame unwind information for the current - translation unit. */ - -int -dwarf2out_do_frame (void) -{ - /* We want to emit correct CFA location expressions or lists, so we - have to return true if we're going to output debug info, even if - we're not going to output frame or unwind info. */ - if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG) - return true; - - if (saved_do_cfi_asm) - return true; - - if (targetm.debug_unwind_info () == UI_DWARF2) - return true; - - if ((flag_unwind_tables || flag_exceptions) - && targetm_common.except_unwind_info (&global_options) == UI_DWARF2) - return true; - - return false; -} - -/* Decide whether to emit frame unwind via assembler directives. */ - -int -dwarf2out_do_cfi_asm (void) -{ - int enc; - -#ifdef MIPS_DEBUGGING_INFO - return false; -#endif - if (saved_do_cfi_asm) - return true; - if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ()) - return false; - if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE) - return false; - - /* Make sure the personality encoding is one the assembler can support. - In particular, aligned addresses can't be handled. */ - enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,/*global=*/1); - if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel) - return false; - enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,/*global=*/0); - if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel) - return false; - - /* If we can't get the assembler to emit only .debug_frame, and we don't need - dwarf2 unwind info for exceptions, then emit .debug_frame by hand. */ - if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE - && !flag_unwind_tables && !flag_exceptions - && targetm_common.except_unwind_info (&global_options) != UI_DWARF2) - return false; - - saved_do_cfi_asm = true; - return true; -} - /* The size of the target's pointer type. */ #ifndef PTR_SIZE #define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT) @@ -233,134 +159,9 @@ 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 ";#" -#endif - -typedef struct dw_cfi_struct *dw_cfi_ref; -typedef struct dw_fde_struct *dw_fde_ref; -typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref; - -/* Call frames are described using a sequence of Call Frame - Information instructions. The register number, offset - and address fields are provided as possible operands; - their use is selected by the opcode field. */ - -enum dw_cfi_oprnd_type { - dw_cfi_oprnd_unused, - dw_cfi_oprnd_reg_num, - dw_cfi_oprnd_offset, - dw_cfi_oprnd_addr, - dw_cfi_oprnd_loc -}; - -typedef union GTY(()) dw_cfi_oprnd_struct { - unsigned int GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num; - HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset; - const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr; - struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc; -} -dw_cfi_oprnd; - -typedef struct GTY(()) dw_cfi_struct { - enum dwarf_call_frame_info dw_cfi_opc; - dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)"))) - dw_cfi_oprnd1; - dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)"))) - dw_cfi_oprnd2; -} -dw_cfi_node; - -DEF_VEC_P (dw_cfi_ref); -DEF_VEC_ALLOC_P (dw_cfi_ref, heap); -DEF_VEC_ALLOC_P (dw_cfi_ref, gc); - -typedef VEC(dw_cfi_ref, gc) *cfi_vec; - -/* This is how we define the location of the CFA. We use to handle it - as REG + OFFSET all the time, but now it can be more complex. - It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET. - Instead of passing around REG and OFFSET, we pass a copy - of this structure. */ -typedef struct cfa_loc { - HOST_WIDE_INT offset; - HOST_WIDE_INT base_offset; - unsigned int reg; - BOOL_BITFIELD indirect : 1; /* 1 if CFA is accessed via a dereference. */ - BOOL_BITFIELD in_use : 1; /* 1 if a saved cfa is stored here. */ -} dw_cfa_location; - -/* All call frame descriptions (FDE's) in the GCC generated DWARF - refer to a single Common Information Entry (CIE), defined at - the beginning of the .debug_frame section. This use of a single - CIE obviates the need to keep track of multiple CIE's - in the DWARF generation routines below. */ - -typedef struct GTY(()) dw_fde_struct { - tree decl; - const char *dw_fde_begin; - const char *dw_fde_current_label; - const char *dw_fde_end; - const char *dw_fde_vms_end_prologue; - const char *dw_fde_vms_begin_epilogue; - const char *dw_fde_second_begin; - const char *dw_fde_second_end; - cfi_vec dw_fde_cfi; - int dw_fde_switch_cfi_index; /* Last CFI before switching sections. */ - HOST_WIDE_INT stack_realignment; - unsigned funcdef_number; - /* Dynamic realign argument pointer register. */ - unsigned int drap_reg; - /* Virtual dynamic realign argument pointer register. */ - unsigned int vdrap_reg; - /* These 3 flags are copied from rtl_data in function.h. */ - unsigned all_throwers_are_sibcalls : 1; - unsigned uses_eh_lsda : 1; - unsigned nothrow : 1; - /* Whether we did stack realign in this call frame. */ - unsigned stack_realign : 1; - /* Whether dynamic realign argument pointer register has been saved. */ - unsigned drap_reg_saved: 1; - /* True iff dw_fde_begin label is in text_section or cold_text_section. */ - unsigned in_std_section : 1; - /* True iff dw_fde_second_begin label is in text_section or - cold_text_section. */ - unsigned second_in_std_section : 1; -} -dw_fde_node; - /* Maximum size (in bytes) of an artificially generated label. */ #define MAX_ARTIFICIAL_LABEL_BYTES 30 -/* The size of addresses as they appear in the Dwarf 2 data. - Some architectures use word addresses to refer to code locations, - but Dwarf 2 info always uses byte addresses. On such machines, - Dwarf 2 addresses need to be larger than the architecture's - pointers. */ -#ifndef DWARF2_ADDR_SIZE -#define DWARF2_ADDR_SIZE (POINTER_SIZE / BITS_PER_UNIT) -#endif - -/* The size in bytes of a DWARF field indicating an offset or length - relative to a debug info section, specified to be 4 bytes in the - DWARF-2 specification. The SGI/MIPS ABI defines it to be the same - as PTR_SIZE. */ - -#ifndef DWARF_OFFSET_SIZE -#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 @@ -377,15 +178,6 @@ dw_fde_node; #define DWARF_ROUND(SIZE,BOUNDARY) \ ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY)) -/* Offsets recorded in opcodes are a multiple of this alignment factor. */ -#ifndef DWARF_CIE_DATA_ALIGNMENT -#ifdef STACK_GROWS_DOWNWARD -#define DWARF_CIE_DATA_ALIGNMENT (-((int) UNITS_PER_WORD)) -#else -#define DWARF_CIE_DATA_ALIGNMENT ((int) UNITS_PER_WORD) -#endif -#endif - /* CIE identifier. */ #if HOST_BITS_PER_WIDE_INT >= 64 #define DWARF_CIE_ID \ @@ -394,36 +186,12 @@ dw_fde_node; #define DWARF_CIE_ID DW_CIE_ID #endif -/* A pointer to the base of a table that contains frame description - information for each routine. */ -static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table; - -/* Number of elements currently allocated for fde_table. */ -static GTY(()) unsigned fde_table_allocated; - -/* Number of elements in fde_table currently in use. */ -static GTY(()) unsigned fde_table_in_use; +DEF_VEC_P (dw_fde_ref); +DEF_VEC_ALLOC_P (dw_fde_ref, gc); -/* Size (in elements) of increments by which we may expand the - fde_table. */ -#define FDE_TABLE_INCREMENT 256 - -/* Get the current fde_table entry we should use. */ - -static inline dw_fde_ref -current_fde (void) -{ - return fde_table_in_use ? &fde_table[fde_table_in_use - 1] : NULL; -} - -/* A vector of call frame insns for the CIE. */ -static GTY(()) cfi_vec cie_cfi_vec; - -/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram - attribute that accelerates the lookup of the FDE associated - with the subprogram. This variable holds the table index of the FDE - associated with the current function (body) definition. */ -static unsigned current_funcdef_fde; +/* A vector for a table that contains frame description + information for each routine. */ +static GTY(()) VEC(dw_fde_ref, gc) *fde_vec; struct GTY(()) indirect_string_node { const char *str; @@ -435,7 +203,6 @@ struct GTY(()) indirect_string_node { static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash; static GTY(()) int dw2_string_counter; -static GTY(()) unsigned long dwarf2out_cfi_label_num; /* True if the compilation unit places functions in more than one section. */ static GTY(()) bool have_multiple_function_sections = false; @@ -451,41 +218,12 @@ static GTY(()) section *cold_text_section; /* Forward declarations for functions defined in this file. */ static char *stripattributes (const char *); -static const char *dwarf_cfi_name (unsigned); -static dw_cfi_ref new_cfi (void); -static void add_cfi (cfi_vec *, dw_cfi_ref); -static void add_fde_cfi (const char *, dw_cfi_ref); -static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *, dw_cfa_location *); -static void lookup_cfa (dw_cfa_location *); -static void reg_save (const char *, unsigned, unsigned, HOST_WIDE_INT); -static void initial_return_save (rtx); -static HOST_WIDE_INT stack_adjust_offset (const_rtx, HOST_WIDE_INT, - HOST_WIDE_INT); -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 bool clobbers_queued_reg_save (const_rtx); -static void dwarf2out_frame_debug_expr (rtx, const char *); - -/* Support for complex CFA locations. */ -static void output_cfa_loc (dw_cfi_ref, int); -static void output_cfa_loc_raw (dw_cfi_ref); -static void get_cfa_from_loc_descr (dw_cfa_location *, - struct dw_loc_descr_struct *); -static struct dw_loc_descr_struct *build_cfa_loc - (dw_cfa_location *, HOST_WIDE_INT); -static struct dw_loc_descr_struct *build_cfa_aligned_loc - (HOST_WIDE_INT, HOST_WIDE_INT); -static void def_cfa_1 (const char *, dw_cfa_location *); -static struct dw_loc_descr_struct *mem_loc_descriptor - (rtx, enum machine_mode mode, enum machine_mode mem_mode, - enum var_init_status); - -/* How to start an assembler comment. */ -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START ";#" -#endif + +/* Personality decl of current unit. Used only when assembler does not support + personality CFI. */ +static GTY(()) rtx current_unit_personality; /* Data and reference forms for relocatable data. */ #define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4) @@ -524,23 +262,6 @@ static struct dw_loc_descr_struct *mem_loc_descriptor #define LN_PROLOG_AS_LABEL "LASLTP" #define LN_PROLOG_END_LABEL "LELTP" #define DIE_LABEL_PREFIX "DW" - -/* The DWARF 2 CFA column which tracks the return address. Normally this - is the column for PC, or the first column after all of the hard - registers. */ -#ifndef DWARF_FRAME_RETURN_COLUMN -#ifdef PC_REGNUM -#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM) -#else -#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGISTERS -#endif -#endif - -/* The mapping from gcc register number to DWARF 2 CFA column number. By - default, we just provide columns for all registers. */ -#ifndef DWARF_FRAME_REGNUM -#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) -#endif /* Match the base name of a file to the base name of a compilation unit. */ @@ -625,15 +346,6 @@ should_emit_struct_debug (tree type, enum debug_info_usage usage) return DUMP_GSTRUCT (type, usage, criterion, generic, false, false); } -/* Hook used by __throw. */ - -rtx -expand_builtin_dwarf_sp_column (void) -{ - unsigned int dwarf_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM); - return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1)); -} - /* Return a pointer to a copy of the section string name S with all attributes stripped off, and an asterisk prepended (for assemble_name). */ @@ -652,2975 +364,153 @@ stripattributes (const char *s) return stripped; } -/* MEM is a memory reference for the register size table, each element of - which has mode MODE. Initialize column C as a return address column. */ +/* Switch [BACK] to eh_frame_section. If we don't have an eh_frame_section, + switch to the data section instead, and write out a synthetic start label + for collect2 the first time around. */ static void -init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c) -{ - HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode); - HOST_WIDE_INT size = GET_MODE_SIZE (Pmode); - emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size)); -} - -/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder. */ - -static inline HOST_WIDE_INT -div_data_align (HOST_WIDE_INT off) +switch_to_eh_frame_section (bool back) { - HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT; - gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off); - return r; -} - -/* Return true if we need a signed version of a given opcode - (e.g. DW_CFA_offset_extended_sf vs DW_CFA_offset_extended). */ + tree label; -static inline bool -need_data_align_sf_opcode (HOST_WIDE_INT off) -{ - return DWARF_CIE_DATA_ALIGNMENT < 0 ? off > 0 : off < 0; -} +#ifdef EH_FRAME_SECTION_NAME + if (eh_frame_section == 0) + { + int flags; -/* Generate code to initialize the register size table. */ + if (EH_TABLES_CAN_BE_READ_ONLY) + { + int fde_encoding; + int per_encoding; + int lsda_encoding; -void -expand_builtin_init_dwarf_reg_sizes (tree address) -{ - unsigned int i; - enum machine_mode mode = TYPE_MODE (char_type_node); - rtx addr = expand_normal (address); - rtx mem = gen_rtx_MEM (BLKmode, addr); - bool wrote_return_column = false; + fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, + /*global=*/0); + per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, + /*global=*/1); + lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, + /*global=*/0); + flags = ((! flag_pic + || ((fde_encoding & 0x70) != DW_EH_PE_absptr + && (fde_encoding & 0x70) != DW_EH_PE_aligned + && (per_encoding & 0x70) != DW_EH_PE_absptr + && (per_encoding & 0x70) != DW_EH_PE_aligned + && (lsda_encoding & 0x70) != DW_EH_PE_absptr + && (lsda_encoding & 0x70) != DW_EH_PE_aligned)) + ? 0 : SECTION_WRITE); + } + else + flags = SECTION_WRITE; + eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL); + } +#endif /* EH_FRAME_SECTION_NAME */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (eh_frame_section) + switch_to_section (eh_frame_section); + else { - int rnum = DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), 1); + /* We have no special eh_frame section. Put the information in + the data section and emit special labels to guide collect2. */ + switch_to_section (data_section); - if (rnum < DWARF_FRAME_REGISTERS) + if (!back) { - HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode); - enum machine_mode save_mode = reg_raw_mode[i]; - HOST_WIDE_INT size; - - if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode)) - save_mode = choose_hard_reg_mode (i, 1, true); - if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN) - { - if (save_mode == VOIDmode) - continue; - wrote_return_column = true; - } - size = GET_MODE_SIZE (save_mode); - if (offset < 0) - continue; - - emit_move_insn (adjust_address (mem, mode, offset), - gen_int_mode (size, mode)); + label = get_file_function_name ("F"); + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + targetm.asm_out.globalize_label (asm_out_file, + IDENTIFIER_POINTER (label)); + ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); } } +} - if (!wrote_return_column) - init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN); - -#ifdef DWARF_ALT_FRAME_RETURN_COLUMN - init_return_column_size (mode, mem, DWARF_ALT_FRAME_RETURN_COLUMN); -#endif +/* Switch [BACK] to the eh or debug frame table section, depending on + FOR_EH. */ - targetm.init_dwarf_reg_sizes_extra (address); +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); + } } -/* Convert a DWARF call frame info. operation to its string name */ +/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */ -static const char * -dwarf_cfi_name (unsigned int cfi_opc) +enum dw_cfi_oprnd_type +dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) { - switch (cfi_opc) + switch (cfi) { - case DW_CFA_advance_loc: - return "DW_CFA_advance_loc"; - case DW_CFA_offset: - return "DW_CFA_offset"; - case DW_CFA_restore: - return "DW_CFA_restore"; case DW_CFA_nop: - return "DW_CFA_nop"; + case DW_CFA_GNU_window_save: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + return dw_cfi_oprnd_unused; + case DW_CFA_set_loc: - return "DW_CFA_set_loc"; case DW_CFA_advance_loc1: - return "DW_CFA_advance_loc1"; case DW_CFA_advance_loc2: - return "DW_CFA_advance_loc2"; case DW_CFA_advance_loc4: - return "DW_CFA_advance_loc4"; + case DW_CFA_MIPS_advance_loc8: + return dw_cfi_oprnd_addr; + + case DW_CFA_offset: case DW_CFA_offset_extended: - return "DW_CFA_offset_extended"; + case DW_CFA_def_cfa: + case DW_CFA_offset_extended_sf: + case DW_CFA_def_cfa_sf: + case DW_CFA_restore: case DW_CFA_restore_extended: - return "DW_CFA_restore_extended"; case DW_CFA_undefined: - return "DW_CFA_undefined"; case DW_CFA_same_value: - return "DW_CFA_same_value"; - case DW_CFA_register: - return "DW_CFA_register"; - case DW_CFA_remember_state: - return "DW_CFA_remember_state"; - case DW_CFA_restore_state: - return "DW_CFA_restore_state"; - case DW_CFA_def_cfa: - return "DW_CFA_def_cfa"; case DW_CFA_def_cfa_register: - return "DW_CFA_def_cfa_register"; - case DW_CFA_def_cfa_offset: - return "DW_CFA_def_cfa_offset"; - - /* DWARF 3 */ - case DW_CFA_def_cfa_expression: - return "DW_CFA_def_cfa_expression"; + case DW_CFA_register: case DW_CFA_expression: - return "DW_CFA_expression"; - case DW_CFA_offset_extended_sf: - return "DW_CFA_offset_extended_sf"; - case DW_CFA_def_cfa_sf: - return "DW_CFA_def_cfa_sf"; - case DW_CFA_def_cfa_offset_sf: - return "DW_CFA_def_cfa_offset_sf"; - - /* SGI/MIPS specific */ - case DW_CFA_MIPS_advance_loc8: - return "DW_CFA_MIPS_advance_loc8"; + return dw_cfi_oprnd_reg_num; - /* GNU extensions */ - case DW_CFA_GNU_window_save: - return "DW_CFA_GNU_window_save"; + case DW_CFA_def_cfa_offset: case DW_CFA_GNU_args_size: - return "DW_CFA_GNU_args_size"; - case DW_CFA_GNU_negative_offset_extended: - return "DW_CFA_GNU_negative_offset_extended"; + case DW_CFA_def_cfa_offset_sf: + return dw_cfi_oprnd_offset; + + case DW_CFA_def_cfa_expression: + return dw_cfi_oprnd_loc; default: - return "DW_CFA_"; + gcc_unreachable (); } } -/* Return a pointer to a newly allocated Call Frame Instruction. */ - -static inline dw_cfi_ref -new_cfi (void) -{ - dw_cfi_ref cfi = ggc_alloc_dw_cfi_node (); - - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0; - - return cfi; -} - -/* Add a Call Frame Instruction to list of instructions. */ - -static inline void -add_cfi (cfi_vec *vec, dw_cfi_ref cfi) -{ - dw_fde_ref fde = current_fde (); - - /* When DRAP is used, CFA is defined with an expression. Redefine - CFA may lead to a different CFA value. */ - /* ??? Of course, this heuristic fails when we're annotating epilogues, - because of course we'll always want to redefine the CFA back to the - stack pointer on the way out. Where should we move this check? */ - if (0 && fde && fde->drap_reg != INVALID_REGNUM) - switch (cfi->dw_cfi_opc) - { - case DW_CFA_def_cfa_register: - case DW_CFA_def_cfa_offset: - case DW_CFA_def_cfa_offset_sf: - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - gcc_unreachable (); - - default: - break; - } - - VEC_safe_push (dw_cfi_ref, gc, *vec, cfi); -} - -/* Generate a new label for the CFI info to refer to. FORCE is true - if a label needs to be output even when using .cfi_* directives. */ +/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */ -char * -dwarf2out_cfi_label (bool force) +enum dw_cfi_oprnd_type +dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi) { - static char label[20]; - - if (!force && dwarf2out_do_cfi_asm ()) - { - /* In this case, we will be emitting the asm directive instead of - the label, so just return a placeholder to keep the rest of the - interfaces happy. */ - strcpy (label, ""); - } - else + switch (cfi) { - int num = dwarf2out_cfi_label_num++; - ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", num); - ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI", num); - } - - return label; -} + case DW_CFA_def_cfa: + case DW_CFA_def_cfa_sf: + case DW_CFA_offset: + case DW_CFA_offset_extended_sf: + case DW_CFA_offset_extended: + return dw_cfi_oprnd_offset; -/* True if remember_state should be emitted before following CFI directive. */ -static bool emit_cfa_remember; + case DW_CFA_register: + return dw_cfi_oprnd_reg_num; -/* True if any CFI directives were emitted at the current insn. */ -static bool any_cfis_emitted; - -/* Add CFI to the current fde at the PC value indicated by LABEL if specified, - or to the CIE if LABEL is NULL. */ - -static void -add_fde_cfi (const char *label, dw_cfi_ref cfi) -{ - cfi_vec *vec; - - if (cie_cfi_vec == NULL) - cie_cfi_vec = VEC_alloc (dw_cfi_ref, gc, 20); - - vec = &cie_cfi_vec; - - if (emit_cfa_remember) - { - dw_cfi_ref cfi_remember; - - /* Emit the state save. */ - emit_cfa_remember = false; - cfi_remember = new_cfi (); - cfi_remember->dw_cfi_opc = DW_CFA_remember_state; - add_fde_cfi (label, cfi_remember); - } - - if (dwarf2out_do_cfi_asm ()) - { - if (label) - { - dw_fde_ref fde = current_fde (); - - gcc_assert (fde != NULL); - - /* We still have to add the cfi to the list so that lookup_cfa - works later on. When -g2 and above we even need to force - emitting of CFI labels and add to list a DW_CFA_set_loc for - convert_cfa_to_fb_loc_list purposes. If we're generating - DWARF3 output we use DW_OP_call_frame_cfa and so don't use - convert_cfa_to_fb_loc_list. */ - if (dwarf_version == 2 - && debug_info_level > DINFO_LEVEL_TERSE - && (write_symbols == DWARF2_DEBUG - || write_symbols == VMS_AND_DWARF2_DEBUG)) - { - switch (cfi->dw_cfi_opc) - { - case DW_CFA_def_cfa_offset: - case DW_CFA_def_cfa_offset_sf: - case DW_CFA_def_cfa_register: - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - case DW_CFA_def_cfa_expression: - case DW_CFA_restore_state: - if (*label == 0 || strcmp (label, "") == 0) - label = dwarf2out_cfi_label (true); - - if (fde->dw_fde_current_label == NULL - || strcmp (label, fde->dw_fde_current_label) != 0) - { - dw_cfi_ref xcfi; - - label = xstrdup (label); - - /* Set the location counter to the new label. */ - xcfi = new_cfi (); - /* It doesn't metter whether DW_CFA_set_loc - or DW_CFA_advance_loc4 is added here, those aren't - emitted into assembly, only looked up by - convert_cfa_to_fb_loc_list. */ - xcfi->dw_cfi_opc = DW_CFA_set_loc; - xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; - add_cfi (&fde->dw_fde_cfi, xcfi); - fde->dw_fde_current_label = label; - } - break; - default: - break; - } - } - - output_cfi_directive (cfi); - - vec = &fde->dw_fde_cfi; - any_cfis_emitted = true; - } - /* ??? If this is a CFI for the CIE, we don't emit. This - assumes that the standard CIE contents that the assembler - uses matches the standard CIE contents that the compiler - uses. This is probably a bad assumption. I'm not quite - sure how to address this for now. */ - } - else if (label) - { - dw_fde_ref fde = current_fde (); - - gcc_assert (fde != NULL); - - if (*label == 0) - label = dwarf2out_cfi_label (false); - - if (fde->dw_fde_current_label == NULL - || strcmp (label, fde->dw_fde_current_label) != 0) - { - dw_cfi_ref xcfi; - - label = xstrdup (label); - - /* Set the location counter to the new label. */ - xcfi = new_cfi (); - /* If we have a current label, advance from there, otherwise - set the location directly using set_loc. */ - xcfi->dw_cfi_opc = fde->dw_fde_current_label - ? DW_CFA_advance_loc4 - : DW_CFA_set_loc; - xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; - add_cfi (&fde->dw_fde_cfi, xcfi); - - fde->dw_fde_current_label = label; - } - - vec = &fde->dw_fde_cfi; - any_cfis_emitted = true; - } - - add_cfi (vec, cfi); -} - -/* Subroutine of lookup_cfa. */ - -static void -lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember) -{ - switch (cfi->dw_cfi_opc) - { - case DW_CFA_def_cfa_offset: - case DW_CFA_def_cfa_offset_sf: - loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset; - break; - case DW_CFA_def_cfa_register: - loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; - break; - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; - loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset; - break; - case DW_CFA_def_cfa_expression: - get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc); - break; - - case DW_CFA_remember_state: - gcc_assert (!remember->in_use); - *remember = *loc; - remember->in_use = 1; - break; - case DW_CFA_restore_state: - gcc_assert (remember->in_use); - *loc = *remember; - remember->in_use = 0; - break; - - default: - break; - } -} - -/* Find the previous value for the CFA. */ - -static void -lookup_cfa (dw_cfa_location *loc) -{ - int ix; - dw_cfi_ref cfi; - dw_fde_ref fde; - dw_cfa_location remember; - - memset (loc, 0, sizeof (*loc)); - loc->reg = INVALID_REGNUM; - remember = *loc; - - FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, ix, cfi) - lookup_cfa_1 (cfi, loc, &remember); - - fde = current_fde (); - if (fde) - FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) - lookup_cfa_1 (cfi, loc, &remember); -} - -/* The current rule for calculating the DWARF2 canonical frame address. */ -static dw_cfa_location cfa; - -/* The register used for saving registers to the stack, and its offset - from the CFA. */ -static dw_cfa_location cfa_store; - -/* The current save location around an epilogue. */ -static dw_cfa_location cfa_remember; - -/* The running total of the size of arguments pushed onto the stack. */ -static HOST_WIDE_INT args_size; - -/* The last args_size we actually output. */ -static HOST_WIDE_INT old_args_size; - -/* Entry point to update the canonical frame address (CFA). - LABEL is passed to add_fde_cfi. The value of CFA is now to be - calculated from REG+OFFSET. */ - -void -dwarf2out_def_cfa (const char *label, unsigned int reg, HOST_WIDE_INT offset) -{ - dw_cfa_location loc; - loc.indirect = 0; - loc.base_offset = 0; - loc.reg = reg; - loc.offset = offset; - def_cfa_1 (label, &loc); -} - -/* Determine if two dw_cfa_location structures define the same data. */ - -static bool -cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2) -{ - return (loc1->reg == loc2->reg - && loc1->offset == loc2->offset - && loc1->indirect == loc2->indirect - && (loc1->indirect == 0 - || loc1->base_offset == loc2->base_offset)); -} - -/* This routine does the actual work. The CFA is now calculated from - the dw_cfa_location structure. */ - -static void -def_cfa_1 (const char *label, dw_cfa_location *loc_p) -{ - dw_cfi_ref cfi; - dw_cfa_location old_cfa, loc; - - cfa = *loc_p; - loc = *loc_p; - - if (cfa_store.reg == loc.reg && loc.indirect == 0) - cfa_store.offset = loc.offset; - - loc.reg = DWARF_FRAME_REGNUM (loc.reg); - lookup_cfa (&old_cfa); - - /* If nothing changed, no need to issue any call frame instructions. */ - if (cfa_equal_p (&loc, &old_cfa)) - return; - - cfi = new_cfi (); - - if (loc.reg == old_cfa.reg && !loc.indirect && !old_cfa.indirect) - { - /* Construct a "DW_CFA_def_cfa_offset " instruction, indicating - 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) - cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf; - else - cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; - cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset; - } - -#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ - else if (loc.offset == old_cfa.offset - && old_cfa.reg != INVALID_REGNUM - && !loc.indirect - && !old_cfa.indirect) - { - /* Construct a "DW_CFA_def_cfa_register " instruction, - indicating the CFA register has changed to but the - offset has not changed. */ - cfi->dw_cfi_opc = DW_CFA_def_cfa_register; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; - } -#endif - - else if (loc.indirect == 0) - { - /* Construct a "DW_CFA_def_cfa " instruction, - indicating the CFA register has changed to with - the specified offset. The data factoring for DW_CFA_def_cfa_sf - happens in output_cfi, or in the assembler via the .cfi_def_cfa - directive. */ - if (loc.offset < 0) - cfi->dw_cfi_opc = DW_CFA_def_cfa_sf; - else - cfi->dw_cfi_opc = DW_CFA_def_cfa; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; - cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset; - } - else - { - /* Construct a DW_CFA_def_cfa_expression instruction to - calculate the CFA using a full location expression since no - register-offset pair is available. */ - struct dw_loc_descr_struct *loc_list; - - cfi->dw_cfi_opc = DW_CFA_def_cfa_expression; - loc_list = build_cfa_loc (&loc, 0); - cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list; - } - - add_fde_cfi (label, cfi); -} - -/* Add the CFI for saving a register. REG is the CFA column number. - LABEL is passed to add_fde_cfi. - If SREG is -1, the register is saved at OFFSET from the CFA; - otherwise it is saved in SREG. */ - -static void -reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset) -{ - dw_cfi_ref cfi = new_cfi (); - dw_fde_ref fde = current_fde (); - - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; - - /* When stack is aligned, store REG using DW_CFA_expression with - FP. */ - if (fde - && fde->stack_realign - && sreg == INVALID_REGNUM) - { - cfi->dw_cfi_opc = DW_CFA_expression; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; - cfi->dw_cfi_oprnd2.dw_cfi_loc - = build_cfa_aligned_loc (offset, fde->stack_realignment); - } - else if (sreg == INVALID_REGNUM) - { - if (need_data_align_sf_opcode (offset)) - cfi->dw_cfi_opc = DW_CFA_offset_extended_sf; - else if (reg & ~0x3f) - cfi->dw_cfi_opc = DW_CFA_offset_extended; - else - cfi->dw_cfi_opc = DW_CFA_offset; - cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; - } - else if (sreg == reg) - cfi->dw_cfi_opc = DW_CFA_same_value; - else - { - cfi->dw_cfi_opc = DW_CFA_register; - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg; - } - - add_fde_cfi (label, cfi); -} - -/* Add the CFI for saving a register window. LABEL is passed to reg_save. - This CFI tells the unwinder that it needs to restore the window registers - from the previous frame's window save area. - - ??? Perhaps we should note in the CIE where windows are saved (instead of - assuming 0(cfa)) and what registers are in the window. */ - -void -dwarf2out_window_save (const char *label) -{ - dw_cfi_ref cfi = new_cfi (); - - cfi->dw_cfi_opc = DW_CFA_GNU_window_save; - 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. */ - -void -dwarf2out_reg_save (const char *label, unsigned int reg, HOST_WIDE_INT offset) -{ - reg_save (label, DWARF_FRAME_REGNUM (reg), INVALID_REGNUM, offset); -} - -/* Entry point for saving the return address in the stack. - LABEL and OFFSET are passed to reg_save. */ - -void -dwarf2out_return_save (const char *label, HOST_WIDE_INT offset) -{ - reg_save (label, DWARF_FRAME_RETURN_COLUMN, INVALID_REGNUM, offset); -} - -/* Entry point for saving the return address in a register. - LABEL and SREG are passed to reg_save. */ - -void -dwarf2out_return_reg (const char *label, unsigned int sreg) -{ - reg_save (label, DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM (sreg), 0); -} - -/* Record the initial position of the return address. RTL is - INCOMING_RETURN_ADDR_RTX. */ - -static void -initial_return_save (rtx rtl) -{ - unsigned int reg = INVALID_REGNUM; - HOST_WIDE_INT offset = 0; - - switch (GET_CODE (rtl)) - { - case REG: - /* RA is in a register. */ - reg = DWARF_FRAME_REGNUM (REGNO (rtl)); - break; - - case MEM: - /* RA is on the stack. */ - rtl = XEXP (rtl, 0); - switch (GET_CODE (rtl)) - { - case REG: - gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM); - offset = 0; - break; - - case PLUS: - gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM); - offset = INTVAL (XEXP (rtl, 1)); - break; - - case MINUS: - gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM); - offset = -INTVAL (XEXP (rtl, 1)); - break; - - default: - gcc_unreachable (); - } - - break; - - case PLUS: - /* The return address is at some offset from any value we can - actually load. For instance, on the SPARC it is in %i7+8. Just - ignore the offset for now; it doesn't matter for unwinding frames. */ - gcc_assert (CONST_INT_P (XEXP (rtl, 1))); - initial_return_save (XEXP (rtl, 0)); - return; - - default: - gcc_unreachable (); - } - - if (reg != DWARF_FRAME_RETURN_COLUMN) - reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset); -} - -/* Given a SET, calculate the amount of stack adjustment it - contains. */ - -static HOST_WIDE_INT -stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size, - HOST_WIDE_INT cur_offset) -{ - const_rtx src = SET_SRC (pattern); - const_rtx dest = SET_DEST (pattern); - HOST_WIDE_INT offset = 0; - enum rtx_code code; - - if (dest == stack_pointer_rtx) - { - code = GET_CODE (src); - - /* Assume (set (reg sp) (reg whatever)) sets args_size - level to 0. */ - if (code == REG && src != stack_pointer_rtx) - { - offset = -cur_args_size; -#ifndef STACK_GROWS_DOWNWARD - offset = -offset; -#endif - return offset - cur_offset; - } - - if (! (code == PLUS || code == MINUS) - || XEXP (src, 0) != stack_pointer_rtx - || !CONST_INT_P (XEXP (src, 1))) - return 0; - - /* (set (reg sp) (plus (reg sp) (const_int))) */ - offset = INTVAL (XEXP (src, 1)); - if (code == PLUS) - offset = -offset; - return offset; - } - - if (MEM_P (src) && !MEM_P (dest)) - dest = src; - if (MEM_P (dest)) - { - /* (set (mem (pre_dec (reg sp))) (foo)) */ - src = XEXP (dest, 0); - code = GET_CODE (src); - - switch (code) - { - case PRE_MODIFY: - case POST_MODIFY: - if (XEXP (src, 0) == stack_pointer_rtx) - { - rtx val = XEXP (XEXP (src, 1), 1); - /* We handle only adjustments by constant amount. */ - gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS - && CONST_INT_P (val)); - offset = -INTVAL (val); - break; - } - return 0; - - case PRE_DEC: - case POST_DEC: - if (XEXP (src, 0) == stack_pointer_rtx) - { - offset = GET_MODE_SIZE (GET_MODE (dest)); - break; - } - return 0; - - case PRE_INC: - case POST_INC: - if (XEXP (src, 0) == stack_pointer_rtx) - { - offset = -GET_MODE_SIZE (GET_MODE (dest)); - break; - } - return 0; - - default: - return 0; - } - } - else - return 0; - - return offset; -} - -/* Precomputed args_size for CODE_LABELs and BARRIERs preceeding them, - indexed by INSN_UID. */ - -static HOST_WIDE_INT *barrier_args_size; - -/* Helper function for compute_barrier_args_size. Handle one insn. */ - -static HOST_WIDE_INT -compute_barrier_args_size_1 (rtx insn, HOST_WIDE_INT cur_args_size, - VEC (rtx, heap) **next) -{ - HOST_WIDE_INT offset = 0; - int i; - - if (! RTX_FRAME_RELATED_P (insn)) - { - if (prologue_epilogue_contains (insn)) - /* Nothing */; - else if (GET_CODE (PATTERN (insn)) == SET) - offset = stack_adjust_offset (PATTERN (insn), cur_args_size, 0); - else if (GET_CODE (PATTERN (insn)) == PARALLEL - || GET_CODE (PATTERN (insn)) == SEQUENCE) - { - /* There may be stack adjustments inside compound insns. Search - for them. */ - for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) - if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET) - offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i), - cur_args_size, offset); - } - } - else - { - rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); - - if (expr) - { - expr = XEXP (expr, 0); - if (GET_CODE (expr) == PARALLEL - || GET_CODE (expr) == SEQUENCE) - for (i = 1; i < XVECLEN (expr, 0); i++) - { - rtx elem = XVECEXP (expr, 0, i); - - if (GET_CODE (elem) == SET && !RTX_FRAME_RELATED_P (elem)) - offset += stack_adjust_offset (elem, cur_args_size, offset); - } - } - } - -#ifndef STACK_GROWS_DOWNWARD - offset = -offset; -#endif - - cur_args_size += offset; - if (cur_args_size < 0) - cur_args_size = 0; - - if (JUMP_P (insn)) - { - rtx dest = JUMP_LABEL (insn); - - if (dest) - { - if (barrier_args_size [INSN_UID (dest)] < 0) - { - barrier_args_size [INSN_UID (dest)] = cur_args_size; - VEC_safe_push (rtx, heap, *next, dest); - } - } - } - - return cur_args_size; -} - -/* Walk the whole function and compute args_size on BARRIERs. */ - -static void -compute_barrier_args_size (void) -{ - int max_uid = get_max_uid (), i; - rtx insn; - VEC (rtx, heap) *worklist, *next, *tmp; - - barrier_args_size = XNEWVEC (HOST_WIDE_INT, max_uid); - for (i = 0; i < max_uid; i++) - barrier_args_size[i] = -1; - - worklist = VEC_alloc (rtx, heap, 20); - next = VEC_alloc (rtx, heap, 20); - insn = get_insns (); - barrier_args_size[INSN_UID (insn)] = 0; - VEC_quick_push (rtx, worklist, insn); - for (;;) - { - while (!VEC_empty (rtx, worklist)) - { - rtx prev, body, first_insn; - HOST_WIDE_INT cur_args_size; - - first_insn = insn = VEC_pop (rtx, worklist); - cur_args_size = barrier_args_size[INSN_UID (insn)]; - prev = prev_nonnote_insn (insn); - if (prev && BARRIER_P (prev)) - barrier_args_size[INSN_UID (prev)] = cur_args_size; - - for (; insn; insn = NEXT_INSN (insn)) - { - if (INSN_DELETED_P (insn) || NOTE_P (insn)) - continue; - if (BARRIER_P (insn)) - break; - - if (LABEL_P (insn)) - { - if (insn == first_insn) - continue; - else if (barrier_args_size[INSN_UID (insn)] < 0) - { - barrier_args_size[INSN_UID (insn)] = cur_args_size; - continue; - } - else - { - /* The insns starting with this label have been - already scanned or are in the worklist. */ - break; - } - } - - body = PATTERN (insn); - if (GET_CODE (body) == SEQUENCE) - { - HOST_WIDE_INT dest_args_size = cur_args_size; - for (i = 1; i < XVECLEN (body, 0); i++) - if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0)) - && INSN_FROM_TARGET_P (XVECEXP (body, 0, i))) - dest_args_size - = compute_barrier_args_size_1 (XVECEXP (body, 0, i), - dest_args_size, &next); - else - cur_args_size - = compute_barrier_args_size_1 (XVECEXP (body, 0, i), - cur_args_size, &next); - - if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0))) - compute_barrier_args_size_1 (XVECEXP (body, 0, 0), - dest_args_size, &next); - else - cur_args_size - = compute_barrier_args_size_1 (XVECEXP (body, 0, 0), - cur_args_size, &next); - } - else - cur_args_size - = compute_barrier_args_size_1 (insn, cur_args_size, &next); - } - } - - if (VEC_empty (rtx, next)) - break; - - /* Swap WORKLIST with NEXT and truncate NEXT for next iteration. */ - tmp = next; - next = worklist; - worklist = tmp; - VEC_truncate (rtx, next, 0); - } - - VEC_free (rtx, heap, worklist); - 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. */ - -static void -dwarf2out_notice_stack_adjust (rtx insn, bool after_p) -{ - HOST_WIDE_INT offset; - const char *label; - int i; - - /* Don't handle epilogues at all. Certainly it would be wrong to do so - with this function. Proper support would require all frame-related - insns to be marked, and to be able to handle saving state around - epilogues textually in the middle of the function. */ - if (prologue_epilogue_contains (insn)) - return; - - /* If INSN is an instruction from target of an annulled branch, the - effects are for the target only and so current argument size - shouldn't change at all. */ - if (final_sequence - && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) - && INSN_FROM_TARGET_P (insn)) - return; - - /* If only calls can throw, and we have a frame pointer, - save up adjustments until we see the CALL_INSN. */ - if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM) - { - if (CALL_P (insn) && !after_p) - { - /* Extract the size of the args from the CALL rtx itself. */ - insn = PATTERN (insn); - if (GET_CODE (insn) == PARALLEL) - insn = XVECEXP (insn, 0, 0); - if (GET_CODE (insn) == SET) - insn = SET_SRC (insn); - gcc_assert (GET_CODE (insn) == CALL); - dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); - } - return; - } - - if (CALL_P (insn) && !after_p) - { - if (!flag_asynchronous_unwind_tables) - dwarf2out_args_size ("", args_size); - return; - } - else if (BARRIER_P (insn)) - { - /* Don't call compute_barrier_args_size () if the only - BARRIER is at the end of function. */ - if (barrier_args_size == NULL && next_nonnote_insn (insn)) - compute_barrier_args_size (); - if (barrier_args_size == NULL) - offset = 0; - else - { - offset = barrier_args_size[INSN_UID (insn)]; - if (offset < 0) - offset = 0; - } - - offset -= args_size; -#ifndef STACK_GROWS_DOWNWARD - offset = -offset; -#endif - } - else if (GET_CODE (PATTERN (insn)) == SET) - offset = stack_adjust_offset (PATTERN (insn), args_size, 0); - else if (GET_CODE (PATTERN (insn)) == PARALLEL - || GET_CODE (PATTERN (insn)) == SEQUENCE) - { - /* There may be stack adjustments inside compound insns. Search - for them. */ - for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) - if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET) - offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i), - args_size, offset); - } - else - return; - - if (offset == 0) - return; - - label = dwarf2out_cfi_label (false); - dwarf2out_stack_adjust (offset, label); -} - -/* We delay emitting a register save until either (a) we reach the end - of the prologue or (b) the register is clobbered. This clusters - register saves so that there are fewer pc advances. */ - -struct GTY(()) queued_reg_save { - struct queued_reg_save *next; - rtx reg; - HOST_WIDE_INT cfa_offset; - rtx saved_reg; -}; - -static GTY(()) struct queued_reg_save *queued_reg_saves; - -/* The caller's ORIG_REG is saved in SAVED_IN_REG. */ -struct GTY(()) reg_saved_in_data { - rtx orig_reg; - rtx saved_in_reg; -}; - -/* A list of registers saved in other registers. - The list intentionally has a small maximum capacity of 4; if your - port needs more than that, you might consider implementing a - more efficient data structure. */ -static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4]; -static GTY(()) size_t num_regs_saved_in_regs; - -static const char *last_reg_save_label; - -/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at - SREG, or if SREG is NULL then it is saved at OFFSET to the CFA. */ - -static void -queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset) -{ - struct queued_reg_save *q; - - /* Duplicates waste space, but it's also necessary to remove them - for correctness, since the queue gets output in reverse - order. */ - for (q = queued_reg_saves; q != NULL; q = q->next) - if (REGNO (q->reg) == REGNO (reg)) - break; - - if (q == NULL) - { - q = ggc_alloc_queued_reg_save (); - q->next = queued_reg_saves; - queued_reg_saves = q; - } - - q->reg = reg; - q->cfa_offset = offset; - q->saved_reg = sreg; - - last_reg_save_label = label; -} - -/* Output all the entries in QUEUED_REG_SAVES. */ - -void -dwarf2out_flush_queued_reg_saves (void) -{ - struct queued_reg_save *q; - - for (q = queued_reg_saves; q; q = q->next) - { - size_t i; - unsigned int reg, sreg; - - for (i = 0; i < num_regs_saved_in_regs; i++) - if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg)) - break; - if (q->saved_reg && i == num_regs_saved_in_regs) - { - gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs)); - num_regs_saved_in_regs++; - } - if (i != num_regs_saved_in_regs) - { - regs_saved_in_regs[i].orig_reg = q->reg; - regs_saved_in_regs[i].saved_in_reg = q->saved_reg; - } - - reg = DWARF_FRAME_REGNUM (REGNO (q->reg)); - if (q->saved_reg) - sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg)); - else - sreg = INVALID_REGNUM; - reg_save (last_reg_save_label, reg, sreg, q->cfa_offset); - } - - queued_reg_saves = NULL; - last_reg_save_label = NULL; -} - -/* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved - location for? Or, does it clobber a register which we've previously - said that some other register is saved in, and for which we now - have a new location for? */ - -static bool -clobbers_queued_reg_save (const_rtx insn) -{ - struct queued_reg_save *q; - - for (q = queued_reg_saves; q; q = q->next) - { - size_t i; - if (modified_in_p (q->reg, insn)) - return true; - for (i = 0; i < num_regs_saved_in_regs; i++) - if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg) - && modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn)) - return true; - } - - return false; -} - -/* Entry point for saving the first register into the second. */ - -void -dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg) -{ - size_t i; - unsigned int regno, sregno; - - for (i = 0; i < num_regs_saved_in_regs; i++) - if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg)) - break; - if (i == num_regs_saved_in_regs) - { - gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs)); - num_regs_saved_in_regs++; - } - regs_saved_in_regs[i].orig_reg = reg; - regs_saved_in_regs[i].saved_in_reg = sreg; - - regno = DWARF_FRAME_REGNUM (REGNO (reg)); - sregno = DWARF_FRAME_REGNUM (REGNO (sreg)); - reg_save (label, regno, sregno, 0); -} - -/* What register, if any, is currently saved in REG? */ - -static rtx -reg_saved_in (rtx reg) -{ - unsigned int regn = REGNO (reg); - size_t i; - struct queued_reg_save *q; - - for (q = queued_reg_saves; q; q = q->next) - if (q->saved_reg && regn == REGNO (q->saved_reg)) - return q->reg; - - for (i = 0; i < num_regs_saved_in_regs; i++) - if (regs_saved_in_regs[i].saved_in_reg - && regn == REGNO (regs_saved_in_regs[i].saved_in_reg)) - return regs_saved_in_regs[i].orig_reg; - - return NULL_RTX; -} - - -/* A temporary register holding an integral value used in adjusting SP - or setting up the store_reg. The "offset" field holds the integer - value, not an offset. */ -static dw_cfa_location cfa_temp; - -/* A subroutine of dwarf2out_frame_debug, process a REG_DEF_CFA note. */ - -static void -dwarf2out_frame_debug_def_cfa (rtx pat, const char *label) -{ - memset (&cfa, 0, sizeof (cfa)); - - switch (GET_CODE (pat)) - { - case PLUS: - cfa.reg = REGNO (XEXP (pat, 0)); - cfa.offset = INTVAL (XEXP (pat, 1)); - break; - - case REG: - cfa.reg = REGNO (pat); - break; - - case MEM: - cfa.indirect = 1; - pat = XEXP (pat, 0); - if (GET_CODE (pat) == PLUS) - { - cfa.base_offset = INTVAL (XEXP (pat, 1)); - pat = XEXP (pat, 0); - } - cfa.reg = REGNO (pat); - break; - - default: - /* Recurse and define an expression. */ - gcc_unreachable (); - } - - def_cfa_1 (label, &cfa); -} - -/* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */ - -static void -dwarf2out_frame_debug_adjust_cfa (rtx pat, const char *label) -{ - rtx src, dest; - - gcc_assert (GET_CODE (pat) == SET); - dest = XEXP (pat, 0); - src = XEXP (pat, 1); - - switch (GET_CODE (src)) - { - case PLUS: - gcc_assert (REGNO (XEXP (src, 0)) == cfa.reg); - cfa.offset -= INTVAL (XEXP (src, 1)); - break; - - case REG: - break; - - default: - gcc_unreachable (); - } - - cfa.reg = REGNO (dest); - gcc_assert (cfa.indirect == 0); - - def_cfa_1 (label, &cfa); -} - -/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note. */ - -static void -dwarf2out_frame_debug_cfa_offset (rtx set, const char *label) -{ - HOST_WIDE_INT offset; - rtx src, addr, span; - - src = XEXP (set, 1); - addr = XEXP (set, 0); - gcc_assert (MEM_P (addr)); - addr = XEXP (addr, 0); - - /* As documented, only consider extremely simple addresses. */ - switch (GET_CODE (addr)) - { - case REG: - gcc_assert (REGNO (addr) == cfa.reg); - offset = -cfa.offset; - break; - case PLUS: - gcc_assert (REGNO (XEXP (addr, 0)) == cfa.reg); - offset = INTVAL (XEXP (addr, 1)) - cfa.offset; - break; - default: - gcc_unreachable (); - } - - span = targetm.dwarf_register_span (src); - - /* ??? We'd like to use queue_reg_save, but we need to come up with - a different flushing heuristic for epilogues. */ - if (!span) - reg_save (label, DWARF_FRAME_REGNUM (REGNO (src)), INVALID_REGNUM, offset); - else - { - /* We have a PARALLEL describing where the contents of SRC live. - Queue register saves for each piece of the PARALLEL. */ - int par_index; - int limit; - HOST_WIDE_INT span_offset = offset; - - gcc_assert (GET_CODE (span) == PARALLEL); - - limit = XVECLEN (span, 0); - for (par_index = 0; par_index < limit; par_index++) - { - rtx elem = XVECEXP (span, 0, par_index); - - reg_save (label, DWARF_FRAME_REGNUM (REGNO (elem)), - INVALID_REGNUM, span_offset); - span_offset += GET_MODE_SIZE (GET_MODE (elem)); - } - } -} - -/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_REGISTER note. */ - -static void -dwarf2out_frame_debug_cfa_register (rtx set, const char *label) -{ - rtx src, dest; - unsigned sregno, dregno; - - src = XEXP (set, 1); - dest = XEXP (set, 0); - - if (src == pc_rtx) - sregno = DWARF_FRAME_RETURN_COLUMN; - else - sregno = DWARF_FRAME_REGNUM (REGNO (src)); - - dregno = DWARF_FRAME_REGNUM (REGNO (dest)); - - /* ??? We'd like to use queue_reg_save, but we need to come up with - a different flushing heuristic for epilogues. */ - reg_save (label, sregno, dregno, 0); -} - -/* Helper function to get mode of MEM's address. */ - -static inline enum machine_mode -get_address_mode (rtx mem) -{ - enum machine_mode mode = GET_MODE (XEXP (mem, 0)); - if (mode != VOIDmode) - return mode; - return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); -} - -/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */ - -static void -dwarf2out_frame_debug_cfa_expression (rtx set, const char *label) -{ - rtx src, dest, span; - dw_cfi_ref cfi = new_cfi (); - - dest = SET_DEST (set); - src = SET_SRC (set); - - gcc_assert (REG_P (src)); - gcc_assert (MEM_P (dest)); - - span = targetm.dwarf_register_span (src); - gcc_assert (!span); - - cfi->dw_cfi_opc = DW_CFA_expression; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (REGNO (src)); - cfi->dw_cfi_oprnd2.dw_cfi_loc - = mem_loc_descriptor (XEXP (dest, 0), get_address_mode (dest), - GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED); - - /* ??? We'd like to use queue_reg_save, were the interface different, - and, as above, we could manage flushing for epilogues. */ - add_fde_cfi (label, cfi); -} - -/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */ - -static void -dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label) -{ - dw_cfi_ref cfi = new_cfi (); - unsigned int regno = DWARF_FRAME_REGNUM (REGNO (reg)); - - cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore); - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno; - - add_fde_cfi (label, cfi); -} - -/* Record call frame debugging information for an expression EXPR, - which either sets SP or FP (adjusting how we calculate the frame - address) or saves a register to the stack or another register. - LABEL indicates the address of EXPR. - - This function encodes a state machine mapping rtxes to actions on - cfa, cfa_store, and cfa_temp.reg. We describe these rules so - users need not read the source code. - - The High-Level Picture - - Changes in the register we use to calculate the CFA: Currently we - assume that if you copy the CFA register into another register, we - should take the other one as the new CFA register; this seems to - work pretty well. If it's wrong for some target, it's simple - enough not to set RTX_FRAME_RELATED_P on the insn in question. - - Changes in the register we use for saving registers to the stack: - This is usually SP, but not always. Again, we deduce that if you - copy SP into another register (and SP is not the CFA register), - then the new register is the one we will be using for register - saves. This also seems to work. - - Register saves: There's not much guesswork about this one; if - RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a - register save, and the register used to calculate the destination - had better be the one we think we're using for this purpose. - It's also assumed that a copy from a call-saved register to another - register is saving that register if RTX_FRAME_RELATED_P is set on - that instruction. If the copy is from a call-saved register to - the *same* register, that means that the register is now the same - value as in the caller. - - Except: If the register being saved is the CFA register, and the - offset is nonzero, we are saving the CFA, so we assume we have to - use DW_CFA_def_cfa_expression. If the offset is 0, we assume that - the intent is to save the value of SP from the previous frame. - - In addition, if a register has previously been saved to a different - register, - - Invariants / Summaries of Rules - - cfa current rule for calculating the CFA. It usually - consists of a register and an offset. - cfa_store register used by prologue code to save things to the stack - cfa_store.offset is the offset from the value of - cfa_store.reg to the actual CFA - cfa_temp register holding an integral value. cfa_temp.offset - stores the value, which will be used to adjust the - stack pointer. cfa_temp is also used like cfa_store, - to track stores to the stack via fp or a temp reg. - - Rules 1- 4: Setting a register's value to cfa.reg or an expression - with cfa.reg as the first operand changes the cfa.reg and its - cfa.offset. Rule 1 and 4 also set cfa_temp.reg and - cfa_temp.offset. - - Rules 6- 9: Set a non-cfa.reg register value to a constant or an - expression yielding a constant. This sets cfa_temp.reg - and cfa_temp.offset. - - Rule 5: Create a new register cfa_store used to save items to the - stack. - - Rules 10-14: Save a register to the stack. Define offset as the - difference of the original location and cfa_store's - location (or cfa_temp's location if cfa_temp is used). - - Rules 16-20: If AND operation happens on sp in prologue, we assume - stack is realigned. We will use a group of DW_OP_XXX - expressions to represent the location of the stored - register instead of CFA+offset. - - The Rules - - "{a,b}" indicates a choice of a xor b. - ":cfa.reg" indicates that must equal cfa.reg. - - Rule 1: - (set :cfa.reg) - effects: cfa.reg = - cfa.offset unchanged - cfa_temp.reg = - cfa_temp.offset = cfa.offset - - Rule 2: - (set sp ({minus,plus,losum} {sp,fp}:cfa.reg - {,:cfa_temp.reg})) - effects: cfa.reg = sp if fp used - cfa.offset += {+/- , cfa_temp.offset} if cfa.reg==sp - cfa_store.offset += {+/- , cfa_temp.offset} - if cfa_store.reg==sp - - Rule 3: - (set fp ({minus,plus,losum} :cfa.reg )) - effects: cfa.reg = fp - cfa_offset += +/- - - Rule 4: - (set ({plus,losum} :cfa.reg )) - constraints: != fp - != sp - effects: cfa.reg = - cfa_temp.reg = - cfa_temp.offset = cfa.offset - - Rule 5: - (set (plus :cfa_temp.reg sp:cfa.reg)) - constraints: != fp - != sp - effects: cfa_store.reg = - cfa_store.offset = cfa.offset - cfa_temp.offset - - Rule 6: - (set ) - effects: cfa_temp.reg = - cfa_temp.offset = - - Rule 7: - (set :cfa_temp.reg (ior :cfa_temp.reg )) - effects: cfa_temp.reg = - cfa_temp.offset |= - - Rule 8: - (set (high )) - effects: none - - Rule 9: - (set (lo_sum )) - effects: cfa_temp.reg = - cfa_temp.offset = - - Rule 10: - (set (mem ({pre,post}_modify sp:cfa_store (???? ))) ) - effects: cfa_store.offset -= - cfa.offset = cfa_store.offset if cfa.reg == sp - cfa.reg = sp - cfa.base_offset = -cfa_store.offset - - Rule 11: - (set (mem ({pre_inc,pre_dec,post_dec} sp:cfa_store.reg)) ) - effects: cfa_store.offset += -/+ mode_size(mem) - cfa.offset = cfa_store.offset if cfa.reg == sp - cfa.reg = sp - cfa.base_offset = -cfa_store.offset - - Rule 12: - (set (mem ({minus,plus,losum} :{cfa_store,cfa_temp} )) - - ) - effects: cfa.reg = - cfa.base_offset = -/+ - {cfa_store,cfa_temp}.offset - - Rule 13: - (set (mem :{cfa_store,cfa_temp}) ) - effects: cfa.reg = - cfa.base_offset = -{cfa_store,cfa_temp}.offset - - Rule 14: - (set (mem (post_inc :cfa_temp )) ) - effects: cfa.reg = - cfa.base_offset = -cfa_temp.offset - cfa_temp.offset -= mode_size(mem) - - Rule 15: - (set {unspec, unspec_volatile}) - effects: target-dependent - - Rule 16: - (set sp (and: sp )) - constraints: cfa_store.reg == sp - effects: current_fde.stack_realign = 1 - cfa_store.offset = 0 - fde->drap_reg = cfa.reg if cfa.reg != sp and cfa.reg != fp - - Rule 17: - (set (mem ({pre_inc, pre_dec} sp)) (mem (plus (cfa.reg) (const_int)))) - effects: cfa_store.offset += -/+ mode_size(mem) - - Rule 18: - (set (mem ({pre_inc, pre_dec} sp)) fp) - constraints: fde->stack_realign == 1 - effects: cfa_store.offset = 0 - cfa.reg != HARD_FRAME_POINTER_REGNUM - - Rule 19: - (set (mem ({pre_inc, pre_dec} sp)) cfa.reg) - constraints: fde->stack_realign == 1 - && cfa.offset == 0 - && cfa.indirect == 0 - && cfa.reg != HARD_FRAME_POINTER_REGNUM - effects: Use DW_CFA_def_cfa_expression to define cfa - cfa.reg == fde->drap_reg */ - -static void -dwarf2out_frame_debug_expr (rtx expr, const char *label) -{ - rtx src, dest, span; - HOST_WIDE_INT offset; - dw_fde_ref fde; - - /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of - the PARALLEL independently. The first element is always processed if - it is a SET. This is for backward compatibility. Other elements - are processed only if they are SETs and the RTX_FRAME_RELATED_P - flag is set in them. */ - if (GET_CODE (expr) == PARALLEL || GET_CODE (expr) == SEQUENCE) - { - int par_index; - int limit = XVECLEN (expr, 0); - rtx elem; - - /* PARALLELs have strict read-modify-write semantics, so we - ought to evaluate every rvalue before changing any lvalue. - It's cumbersome to do that in general, but there's an - easy approximation that is enough for all current users: - handle register saves before register assignments. */ - if (GET_CODE (expr) == PARALLEL) - for (par_index = 0; par_index < limit; par_index++) - { - elem = XVECEXP (expr, 0, par_index); - if (GET_CODE (elem) == SET - && MEM_P (SET_DEST (elem)) - && (RTX_FRAME_RELATED_P (elem) || par_index == 0)) - dwarf2out_frame_debug_expr (elem, label); - } - - for (par_index = 0; par_index < limit; par_index++) - { - elem = XVECEXP (expr, 0, par_index); - if (GET_CODE (elem) == SET - && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE) - && (RTX_FRAME_RELATED_P (elem) || par_index == 0)) - dwarf2out_frame_debug_expr (elem, label); - else if (GET_CODE (elem) == SET - && par_index != 0 - && !RTX_FRAME_RELATED_P (elem)) - { - /* Stack adjustment combining might combine some post-prologue - stack adjustment into a prologue stack adjustment. */ - HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0); - - if (offset != 0) - dwarf2out_stack_adjust (offset, label); - } - } - return; - } - - gcc_assert (GET_CODE (expr) == SET); - - src = SET_SRC (expr); - dest = SET_DEST (expr); - - if (REG_P (src)) - { - rtx rsi = reg_saved_in (src); - if (rsi) - src = rsi; - } - - fde = current_fde (); - - switch (GET_CODE (dest)) - { - case REG: - switch (GET_CODE (src)) - { - /* Setting FP from SP. */ - case REG: - if (cfa.reg == (unsigned) REGNO (src)) - { - /* Rule 1 */ - /* Update the CFA rule wrt SP or FP. Make sure src is - relative to the current CFA register. - - We used to require that dest be either SP or FP, but the - ARM copies SP to a temporary register, and from there to - FP. So we just rely on the backends to only set - RTX_FRAME_RELATED_P on appropriate insns. */ - cfa.reg = REGNO (dest); - cfa_temp.reg = cfa.reg; - cfa_temp.offset = cfa.offset; - } - else - { - /* Saving a register in a register. */ - gcc_assert (!fixed_regs [REGNO (dest)] - /* For the SPARC and its register window. */ - || (DWARF_FRAME_REGNUM (REGNO (src)) - == DWARF_FRAME_RETURN_COLUMN)); - - /* After stack is aligned, we can only save SP in FP - if drap register is used. In this case, we have - to restore stack pointer with the CFA value and we - don't generate this DWARF information. */ - if (fde - && fde->stack_realign - && REGNO (src) == STACK_POINTER_REGNUM) - gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM - && fde->drap_reg != INVALID_REGNUM - && cfa.reg != REGNO (src)); - else - queue_reg_save (label, src, dest, 0); - } - break; - - case PLUS: - case MINUS: - case LO_SUM: - if (dest == stack_pointer_rtx) - { - /* Rule 2 */ - /* Adjusting SP. */ - switch (GET_CODE (XEXP (src, 1))) - { - case CONST_INT: - offset = INTVAL (XEXP (src, 1)); - break; - case REG: - gcc_assert ((unsigned) REGNO (XEXP (src, 1)) - == cfa_temp.reg); - offset = cfa_temp.offset; - break; - default: - gcc_unreachable (); - } - - if (XEXP (src, 0) == hard_frame_pointer_rtx) - { - /* Restoring SP from FP in the epilogue. */ - gcc_assert (cfa.reg == (unsigned) HARD_FRAME_POINTER_REGNUM); - cfa.reg = STACK_POINTER_REGNUM; - } - else if (GET_CODE (src) == LO_SUM) - /* Assume we've set the source reg of the LO_SUM from sp. */ - ; - else - gcc_assert (XEXP (src, 0) == stack_pointer_rtx); - - if (GET_CODE (src) != MINUS) - offset = -offset; - if (cfa.reg == STACK_POINTER_REGNUM) - cfa.offset += offset; - if (cfa_store.reg == STACK_POINTER_REGNUM) - cfa_store.offset += offset; - } - else if (dest == hard_frame_pointer_rtx) - { - /* Rule 3 */ - /* Either setting the FP from an offset of the SP, - or adjusting the FP */ - gcc_assert (frame_pointer_needed); - - gcc_assert (REG_P (XEXP (src, 0)) - && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg - && CONST_INT_P (XEXP (src, 1))); - offset = INTVAL (XEXP (src, 1)); - if (GET_CODE (src) != MINUS) - offset = -offset; - cfa.offset += offset; - cfa.reg = HARD_FRAME_POINTER_REGNUM; - } - else - { - gcc_assert (GET_CODE (src) != MINUS); - - /* Rule 4 */ - if (REG_P (XEXP (src, 0)) - && REGNO (XEXP (src, 0)) == cfa.reg - && CONST_INT_P (XEXP (src, 1))) - { - /* Setting a temporary CFA register that will be copied - into the FP later on. */ - offset = - INTVAL (XEXP (src, 1)); - cfa.offset += offset; - cfa.reg = REGNO (dest); - /* Or used to save regs to the stack. */ - cfa_temp.reg = cfa.reg; - cfa_temp.offset = cfa.offset; - } - - /* Rule 5 */ - else if (REG_P (XEXP (src, 0)) - && REGNO (XEXP (src, 0)) == cfa_temp.reg - && XEXP (src, 1) == stack_pointer_rtx) - { - /* Setting a scratch register that we will use instead - of SP for saving registers to the stack. */ - gcc_assert (cfa.reg == STACK_POINTER_REGNUM); - cfa_store.reg = REGNO (dest); - cfa_store.offset = cfa.offset - cfa_temp.offset; - } - - /* Rule 9 */ - else if (GET_CODE (src) == LO_SUM - && CONST_INT_P (XEXP (src, 1))) - { - cfa_temp.reg = REGNO (dest); - cfa_temp.offset = INTVAL (XEXP (src, 1)); - } - else - gcc_unreachable (); - } - break; - - /* Rule 6 */ - case CONST_INT: - cfa_temp.reg = REGNO (dest); - cfa_temp.offset = INTVAL (src); - break; - - /* Rule 7 */ - case IOR: - gcc_assert (REG_P (XEXP (src, 0)) - && (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg - && CONST_INT_P (XEXP (src, 1))); - - if ((unsigned) REGNO (dest) != cfa_temp.reg) - cfa_temp.reg = REGNO (dest); - cfa_temp.offset |= INTVAL (XEXP (src, 1)); - break; - - /* Skip over HIGH, assuming it will be followed by a LO_SUM, - which will fill in all of the bits. */ - /* Rule 8 */ - case HIGH: - break; - - /* Rule 15 */ - case UNSPEC: - case UNSPEC_VOLATILE: - gcc_assert (targetm.dwarf_handle_frame_unspec); - targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1)); - return; - - /* Rule 16 */ - case AND: - /* If this AND operation happens on stack pointer in prologue, - we assume the stack is realigned and we extract the - alignment. */ - if (fde && XEXP (src, 0) == stack_pointer_rtx) - { - /* We interpret reg_save differently with stack_realign set. - Thus we must flush whatever we have queued first. */ - dwarf2out_flush_queued_reg_saves (); - - gcc_assert (cfa_store.reg == REGNO (XEXP (src, 0))); - fde->stack_realign = 1; - fde->stack_realignment = INTVAL (XEXP (src, 1)); - cfa_store.offset = 0; - - if (cfa.reg != STACK_POINTER_REGNUM - && cfa.reg != HARD_FRAME_POINTER_REGNUM) - fde->drap_reg = cfa.reg; - } - return; - - default: - gcc_unreachable (); - } - - def_cfa_1 (label, &cfa); - break; - - case MEM: - - /* Saving a register to the stack. Make sure dest is relative to the - CFA register. */ - switch (GET_CODE (XEXP (dest, 0))) - { - /* Rule 10 */ - /* With a push. */ - case PRE_MODIFY: - case POST_MODIFY: - /* We can't handle variable size modifications. */ - gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1)) - == CONST_INT); - offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1)); - - gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM - && cfa_store.reg == STACK_POINTER_REGNUM); - - cfa_store.offset += offset; - if (cfa.reg == STACK_POINTER_REGNUM) - cfa.offset = cfa_store.offset; - - if (GET_CODE (XEXP (dest, 0)) == POST_MODIFY) - offset -= cfa_store.offset; - else - offset = -cfa_store.offset; - break; - - /* Rule 11 */ - case PRE_INC: - case PRE_DEC: - case POST_DEC: - offset = GET_MODE_SIZE (GET_MODE (dest)); - if (GET_CODE (XEXP (dest, 0)) == PRE_INC) - offset = -offset; - - gcc_assert ((REGNO (XEXP (XEXP (dest, 0), 0)) - == STACK_POINTER_REGNUM) - && cfa_store.reg == STACK_POINTER_REGNUM); - - cfa_store.offset += offset; - - /* Rule 18: If stack is aligned, we will use FP as a - reference to represent the address of the stored - regiser. */ - if (fde - && fde->stack_realign - && src == hard_frame_pointer_rtx) - { - gcc_assert (cfa.reg != HARD_FRAME_POINTER_REGNUM); - cfa_store.offset = 0; - } - - if (cfa.reg == STACK_POINTER_REGNUM) - cfa.offset = cfa_store.offset; - - if (GET_CODE (XEXP (dest, 0)) == POST_DEC) - offset += -cfa_store.offset; - else - offset = -cfa_store.offset; - break; - - /* Rule 12 */ - /* With an offset. */ - case PLUS: - case MINUS: - case LO_SUM: - { - int regno; - - gcc_assert (CONST_INT_P (XEXP (XEXP (dest, 0), 1)) - && REG_P (XEXP (XEXP (dest, 0), 0))); - offset = INTVAL (XEXP (XEXP (dest, 0), 1)); - if (GET_CODE (XEXP (dest, 0)) == MINUS) - offset = -offset; - - regno = REGNO (XEXP (XEXP (dest, 0), 0)); - - if (cfa.reg == (unsigned) regno) - offset -= cfa.offset; - else if (cfa_store.reg == (unsigned) regno) - offset -= cfa_store.offset; - else - { - gcc_assert (cfa_temp.reg == (unsigned) regno); - offset -= cfa_temp.offset; - } - } - break; - - /* Rule 13 */ - /* Without an offset. */ - case REG: - { - int regno = REGNO (XEXP (dest, 0)); - - if (cfa.reg == (unsigned) regno) - offset = -cfa.offset; - else if (cfa_store.reg == (unsigned) regno) - offset = -cfa_store.offset; - else - { - gcc_assert (cfa_temp.reg == (unsigned) regno); - offset = -cfa_temp.offset; - } - } - break; - - /* Rule 14 */ - case POST_INC: - gcc_assert (cfa_temp.reg - == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0))); - offset = -cfa_temp.offset; - cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest)); - break; - - default: - gcc_unreachable (); - } - - /* Rule 17 */ - /* If the source operand of this MEM operation is not a - register, basically the source is return address. Here - we only care how much stack grew and we don't save it. */ - if (!REG_P (src)) - break; - - if (REGNO (src) != STACK_POINTER_REGNUM - && REGNO (src) != HARD_FRAME_POINTER_REGNUM - && (unsigned) REGNO (src) == cfa.reg) - { - /* We're storing the current CFA reg into the stack. */ - - if (cfa.offset == 0) - { - /* Rule 19 */ - /* If stack is aligned, putting CFA reg into stack means - we can no longer use reg + offset to represent CFA. - Here we use DW_CFA_def_cfa_expression instead. The - result of this expression equals to the original CFA - value. */ - if (fde - && fde->stack_realign - && cfa.indirect == 0 - && cfa.reg != HARD_FRAME_POINTER_REGNUM) - { - dw_cfa_location cfa_exp; - - gcc_assert (fde->drap_reg == cfa.reg); - - cfa_exp.indirect = 1; - cfa_exp.reg = HARD_FRAME_POINTER_REGNUM; - cfa_exp.base_offset = offset; - cfa_exp.offset = 0; - - fde->drap_reg_saved = 1; - - def_cfa_1 (label, &cfa_exp); - break; - } - - /* If the source register is exactly the CFA, assume - we're saving SP like any other register; this happens - on the ARM. */ - def_cfa_1 (label, &cfa); - queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset); - break; - } - else - { - /* Otherwise, we'll need to look in the stack to - calculate the CFA. */ - rtx x = XEXP (dest, 0); - - if (!REG_P (x)) - x = XEXP (x, 0); - gcc_assert (REG_P (x)); - - cfa.reg = REGNO (x); - cfa.base_offset = offset; - cfa.indirect = 1; - def_cfa_1 (label, &cfa); - break; - } - } - - def_cfa_1 (label, &cfa); - { - span = targetm.dwarf_register_span (src); - - if (!span) - queue_reg_save (label, src, NULL_RTX, offset); - else - { - /* We have a PARALLEL describing where the contents of SRC - live. Queue register saves for each piece of the - PARALLEL. */ - int par_index; - int limit; - HOST_WIDE_INT span_offset = offset; - - gcc_assert (GET_CODE (span) == PARALLEL); - - limit = XVECLEN (span, 0); - for (par_index = 0; par_index < limit; par_index++) - { - rtx elem = XVECEXP (span, 0, par_index); - - queue_reg_save (label, elem, NULL_RTX, span_offset); - span_offset += GET_MODE_SIZE (GET_MODE (elem)); - } - } - } - break; - - default: - gcc_unreachable (); - } -} - -/* Record call frame debugging information for INSN, which either - sets SP or FP (adjusting how we calculate the frame address) or saves a - register to the stack. If INSN is NULL_RTX, initialize our state. - - If AFTER_P is false, we're being called before the insn is emitted, - otherwise after. Call instructions get invoked twice. */ - -void -dwarf2out_frame_debug (rtx insn, bool after_p) -{ - const char *label; - rtx note, n; - bool handled_one = false; - - if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)) - dwarf2out_flush_queued_reg_saves (); - - 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_notice_stack_adjust (insn, after_p); - return; - } - - label = dwarf2out_cfi_label (false); - any_cfis_emitted = false; - - for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) - switch (REG_NOTE_KIND (note)) - { - case REG_FRAME_RELATED_EXPR: - insn = XEXP (note, 0); - goto found; - - case REG_CFA_DEF_CFA: - dwarf2out_frame_debug_def_cfa (XEXP (note, 0), label); - handled_one = true; - break; - - case REG_CFA_ADJUST_CFA: - n = XEXP (note, 0); - if (n == NULL) - { - n = PATTERN (insn); - if (GET_CODE (n) == PARALLEL) - n = XVECEXP (n, 0, 0); - } - dwarf2out_frame_debug_adjust_cfa (n, label); - handled_one = true; - break; - - case REG_CFA_OFFSET: - n = XEXP (note, 0); - if (n == NULL) - n = single_set (insn); - dwarf2out_frame_debug_cfa_offset (n, label); - handled_one = true; - break; - - case REG_CFA_REGISTER: - n = XEXP (note, 0); - if (n == NULL) - { - n = PATTERN (insn); - if (GET_CODE (n) == PARALLEL) - n = XVECEXP (n, 0, 0); - } - dwarf2out_frame_debug_cfa_register (n, label); - handled_one = true; - break; - - case REG_CFA_EXPRESSION: - n = XEXP (note, 0); - if (n == NULL) - n = single_set (insn); - dwarf2out_frame_debug_cfa_expression (n, label); - handled_one = true; - break; - - case REG_CFA_RESTORE: - n = XEXP (note, 0); - if (n == NULL) - { - n = PATTERN (insn); - if (GET_CODE (n) == PARALLEL) - n = XVECEXP (n, 0, 0); - n = XEXP (n, 0); - } - dwarf2out_frame_debug_cfa_restore (n, label); - handled_one = true; - break; - - case REG_CFA_SET_VDRAP: - n = XEXP (note, 0); - if (REG_P (n)) - { - dw_fde_ref fde = current_fde (); - if (fde) - { - gcc_assert (fde->vdrap_reg == INVALID_REGNUM); - if (REG_P (n)) - fde->vdrap_reg = REGNO (n); - } - } - handled_one = true; - break; - - default: - break; - } - if (handled_one) - { - if (any_cfis_emitted) - dwarf2out_flush_queued_reg_saves (); - return; - } - - insn = PATTERN (insn); - found: - dwarf2out_frame_debug_expr (insn, label); - - /* Check again. A parallel can save and update the same register. - We could probably check just once, here, but this is safer than - removing the check above. */ - if (any_cfis_emitted || clobbers_queued_reg_save (insn)) - dwarf2out_flush_queued_reg_saves (); -} - -/* Called once at the start of final to initialize some data for the - current function. */ -void -dwarf2out_frame_debug_init (void) -{ - size_t i; - - /* Flush any queued register saves. */ - dwarf2out_flush_queued_reg_saves (); - - /* Set up state for generating call frame debug info. */ - lookup_cfa (&cfa); - gcc_assert (cfa.reg - == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)); - - cfa.reg = STACK_POINTER_REGNUM; - cfa_store = cfa; - cfa_temp.reg = -1; - cfa_temp.offset = 0; - - for (i = 0; i < num_regs_saved_in_regs; i++) - { - regs_saved_in_regs[i].orig_reg = NULL_RTX; - regs_saved_in_regs[i].saved_in_reg = NULL_RTX; - } - num_regs_saved_in_regs = 0; - - if (barrier_args_size) - { - XDELETEVEC (barrier_args_size); - barrier_args_size = NULL; - } -} - -/* Determine if we need to save and restore CFI information around this - epilogue. If SIBCALL is true, then this is a sibcall epilogue. If - we do need to save/restore, then emit the save now, and insert a - NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream. */ - -void -dwarf2out_cfi_begin_epilogue (rtx insn) -{ - bool saw_frp = false; - rtx i; - - /* Scan forward to the return insn, noticing if there are possible - frame related insns. */ - for (i = NEXT_INSN (insn); i ; i = NEXT_INSN (i)) - { - if (!INSN_P (i)) - continue; - - /* Look for both regular and sibcalls to end the block. */ - if (returnjump_p (i)) - break; - if (CALL_P (i) && SIBLING_CALL_P (i)) - break; - - if (GET_CODE (PATTERN (i)) == SEQUENCE) - { - int idx; - rtx seq = PATTERN (i); - - if (returnjump_p (XVECEXP (seq, 0, 0))) - break; - if (CALL_P (XVECEXP (seq, 0, 0)) - && SIBLING_CALL_P (XVECEXP (seq, 0, 0))) - break; - - for (idx = 0; idx < XVECLEN (seq, 0); idx++) - if (RTX_FRAME_RELATED_P (XVECEXP (seq, 0, idx))) - saw_frp = true; - } - - if (RTX_FRAME_RELATED_P (i)) - saw_frp = true; - } - - /* If the port doesn't emit epilogue unwind info, we don't need a - save/restore pair. */ - if (!saw_frp) - return; - - /* Otherwise, search forward to see if the return insn was the last - basic block of the function. If so, we don't need save/restore. */ - gcc_assert (i != NULL); - i = next_real_insn (i); - if (i == NULL) - return; - - /* Insert the restore before that next real insn in the stream, and before - a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be - properly nested. This should be after any label or alignment. This - will be pushed into the CFI stream by the function below. */ - while (1) - { - rtx p = PREV_INSN (i); - if (!NOTE_P (p)) - break; - if (NOTE_KIND (p) == NOTE_INSN_BASIC_BLOCK) - break; - i = p; - } - emit_note_before (NOTE_INSN_CFA_RESTORE_STATE, i); - - emit_cfa_remember = true; - - /* And emulate the state save. */ - gcc_assert (!cfa_remember.in_use); - cfa_remember = cfa; - cfa_remember.in_use = 1; -} - -/* A "subroutine" of dwarf2out_cfi_begin_epilogue. Emit the restore - required. */ - -void -dwarf2out_frame_debug_restore_state (void) -{ - dw_cfi_ref cfi = new_cfi (); - const char *label = dwarf2out_cfi_label (false); - - cfi->dw_cfi_opc = DW_CFA_restore_state; - add_fde_cfi (label, cfi); - - gcc_assert (cfa_remember.in_use); - cfa = cfa_remember; - cfa_remember.in_use = 0; -} - -/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */ -static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc - (enum dwarf_call_frame_info cfi); - -static enum dw_cfi_oprnd_type -dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) -{ - switch (cfi) - { - case DW_CFA_nop: - case DW_CFA_GNU_window_save: - case DW_CFA_remember_state: - case DW_CFA_restore_state: - return dw_cfi_oprnd_unused; - - case DW_CFA_set_loc: - case DW_CFA_advance_loc1: - case DW_CFA_advance_loc2: - case DW_CFA_advance_loc4: - case DW_CFA_MIPS_advance_loc8: - return dw_cfi_oprnd_addr; - - case DW_CFA_offset: - case DW_CFA_offset_extended: - case DW_CFA_def_cfa: - case DW_CFA_offset_extended_sf: - case DW_CFA_def_cfa_sf: - case DW_CFA_restore: - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_def_cfa_register: - case DW_CFA_register: - case DW_CFA_expression: - return dw_cfi_oprnd_reg_num; - - case DW_CFA_def_cfa_offset: - case DW_CFA_GNU_args_size: - case DW_CFA_def_cfa_offset_sf: - return dw_cfi_oprnd_offset; - - case DW_CFA_def_cfa_expression: - return dw_cfi_oprnd_loc; - - default: - gcc_unreachable (); - } -} - -/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */ -static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc - (enum dwarf_call_frame_info cfi); - -static enum dw_cfi_oprnd_type -dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi) -{ - switch (cfi) - { - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - case DW_CFA_offset: - case DW_CFA_offset_extended_sf: - case DW_CFA_offset_extended: - return dw_cfi_oprnd_offset; - - case DW_CFA_register: - return dw_cfi_oprnd_reg_num; - - case DW_CFA_expression: - return dw_cfi_oprnd_loc; - - default: - return dw_cfi_oprnd_unused; - } -} - -/* Switch [BACK] to eh_frame_section. If we don't have an eh_frame_section, - switch to the data section instead, and write out a synthetic start label - for collect2 the first time around. */ - -static void -switch_to_eh_frame_section (bool back) -{ - tree label; - -#ifdef EH_FRAME_SECTION_NAME - if (eh_frame_section == 0) - { - int flags; - - if (EH_TABLES_CAN_BE_READ_ONLY) - { - int fde_encoding; - int per_encoding; - int lsda_encoding; - - fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, - /*global=*/0); - per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, - /*global=*/1); - lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, - /*global=*/0); - flags = ((! flag_pic - || ((fde_encoding & 0x70) != DW_EH_PE_absptr - && (fde_encoding & 0x70) != DW_EH_PE_aligned - && (per_encoding & 0x70) != DW_EH_PE_absptr - && (per_encoding & 0x70) != DW_EH_PE_aligned - && (lsda_encoding & 0x70) != DW_EH_PE_absptr - && (lsda_encoding & 0x70) != DW_EH_PE_aligned)) - ? 0 : SECTION_WRITE); - } - else - flags = SECTION_WRITE; - eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL); - } -#endif /* EH_FRAME_SECTION_NAME */ - - if (eh_frame_section) - switch_to_section (eh_frame_section); - else - { - /* We have no special eh_frame section. Put the information in - the data section and emit special labels to guide collect2. */ - switch_to_section (data_section); - - if (!back) - { - label = get_file_function_name ("F"); - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); - targetm.asm_out.globalize_label (asm_out_file, - IDENTIFIER_POINTER (label)); - ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); - } - } -} - -/* 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 -output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh) -{ - unsigned long r; - HOST_WIDE_INT off; - - if (cfi->dw_cfi_opc == DW_CFA_advance_loc) - dw2_asm_output_data (1, (cfi->dw_cfi_opc - | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)), - "DW_CFA_advance_loc " HOST_WIDE_INT_PRINT_HEX, - ((unsigned HOST_WIDE_INT) - cfi->dw_cfi_oprnd1.dw_cfi_offset)); - else if (cfi->dw_cfi_opc == DW_CFA_offset) - { - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)), - "DW_CFA_offset, column %#lx", r); - off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset); - dw2_asm_output_data_uleb128 (off, NULL); - } - else if (cfi->dw_cfi_opc == DW_CFA_restore) - { - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)), - "DW_CFA_restore, column %#lx", r); - } - else - { - dw2_asm_output_data (1, cfi->dw_cfi_opc, - "%s", dwarf_cfi_name (cfi->dw_cfi_opc)); - - switch (cfi->dw_cfi_opc) - { - case DW_CFA_set_loc: - if (for_eh) - dw2_asm_output_encoded_addr_rtx ( - ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0), - gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr), - false, NULL); - else - dw2_asm_output_addr (DWARF2_ADDR_SIZE, - cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - - case DW_CFA_advance_loc1: - dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label, NULL); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - - case DW_CFA_advance_loc2: - dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label, NULL); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - - case DW_CFA_advance_loc4: - dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label, NULL); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - - case DW_CFA_MIPS_advance_loc8: - dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label, NULL); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - - case DW_CFA_offset_extended: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset); - dw2_asm_output_data_uleb128 (off, NULL); - break; - - case DW_CFA_def_cfa: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL); - break; - - case DW_CFA_offset_extended_sf: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset); - dw2_asm_output_data_sleb128 (off, NULL); - break; - - case DW_CFA_def_cfa_sf: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset); - dw2_asm_output_data_sleb128 (off, NULL); - break; - - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_def_cfa_register: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - break; - - case DW_CFA_register: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, for_eh); - dw2_asm_output_data_uleb128 (r, NULL); - break; - - case DW_CFA_def_cfa_offset: - case DW_CFA_GNU_args_size: - dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL); - break; - - case DW_CFA_def_cfa_offset_sf: - off = div_data_align (cfi->dw_cfi_oprnd1.dw_cfi_offset); - dw2_asm_output_data_sleb128 (off, NULL); - break; - - case DW_CFA_GNU_window_save: - break; - - case DW_CFA_def_cfa_expression: - case DW_CFA_expression: - output_cfa_loc (cfi, for_eh); - break; - - case DW_CFA_GNU_negative_offset_extended: - /* Obsoleted by DW_CFA_offset_extended_sf. */ - gcc_unreachable (); - - default: - break; - } - } -} - -/* Similar, but do it via assembler directives instead. */ - -static void -output_cfi_directive (dw_cfi_ref cfi) -{ - unsigned long r, r2; - - switch (cfi->dw_cfi_opc) - { - case DW_CFA_advance_loc: - case DW_CFA_advance_loc1: - case DW_CFA_advance_loc2: - case DW_CFA_advance_loc4: - case DW_CFA_MIPS_advance_loc8: - case DW_CFA_set_loc: - /* Should only be created by add_fde_cfi in a code path not - followed when emitting via directives. The assembler is - going to take care of this for us. */ - gcc_unreachable (); - - case DW_CFA_offset: - case DW_CFA_offset_extended: - case DW_CFA_offset_extended_sf: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n", - r, cfi->dw_cfi_oprnd2.dw_cfi_offset); - break; - - case DW_CFA_restore: - case DW_CFA_restore_extended: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_restore %lu\n", r); - break; - - case DW_CFA_undefined: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_undefined %lu\n", r); - break; - - case DW_CFA_same_value: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_same_value %lu\n", r); - break; - - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n", - r, cfi->dw_cfi_oprnd2.dw_cfi_offset); - break; - - case DW_CFA_def_cfa_register: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_def_cfa_register %lu\n", r); - break; - - case DW_CFA_register: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_register %lu, %lu\n", r, r2); - break; - - case DW_CFA_def_cfa_offset: - case DW_CFA_def_cfa_offset_sf: - fprintf (asm_out_file, "\t.cfi_def_cfa_offset " - HOST_WIDE_INT_PRINT_DEC"\n", - cfi->dw_cfi_oprnd1.dw_cfi_offset); - break; - - case DW_CFA_remember_state: - fprintf (asm_out_file, "\t.cfi_remember_state\n"); - break; - case DW_CFA_restore_state: - fprintf (asm_out_file, "\t.cfi_restore_state\n"); - break; - - case DW_CFA_GNU_args_size: - fprintf (asm_out_file, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size); - dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC, - ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); - fputc ('\n', asm_out_file); - break; - - case DW_CFA_GNU_window_save: - fprintf (asm_out_file, "\t.cfi_window_save\n"); - break; - - case DW_CFA_def_cfa_expression: - case DW_CFA_expression: - fprintf (asm_out_file, "\t.cfi_escape %#x,", cfi->dw_cfi_opc); - output_cfa_loc_raw (cfi); - fputc ('\n', asm_out_file); - break; - - default: - gcc_unreachable (); - } -} - -/* Output CFIs from VEC, up to index UPTO, to bring current FDE to the - same state as after executing CFIs in CFI chain. DO_CFI_ASM is - true if .cfi_* directives shall be emitted, false otherwise. If it - is false, FDE and FOR_EH are the other arguments to pass to - output_cfi. */ - -static void -output_cfis (cfi_vec vec, int upto, bool do_cfi_asm, - dw_fde_ref fde, bool for_eh) -{ - int ix; - struct dw_cfi_struct cfi_buf; - dw_cfi_ref cfi2; - dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL; - VEC(dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32); - unsigned int len, idx; - - for (ix = 0; ix < upto + 1; ix++) - { - dw_cfi_ref cfi = ix < upto ? VEC_index (dw_cfi_ref, vec, ix) : NULL; - switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop) - { - case DW_CFA_advance_loc: - case DW_CFA_advance_loc1: - case DW_CFA_advance_loc2: - case DW_CFA_advance_loc4: - case DW_CFA_MIPS_advance_loc8: - case DW_CFA_set_loc: - /* All advances should be ignored. */ - break; - case DW_CFA_remember_state: - { - dw_cfi_ref args_size = cfi_args_size; - - /* Skip everything between .cfi_remember_state and - .cfi_restore_state. */ - ix++; - if (ix == upto) - goto flush_all; - - for (; ix < upto; ix++) - { - cfi2 = VEC_index (dw_cfi_ref, vec, ix); - if (cfi2->dw_cfi_opc == DW_CFA_restore_state) - break; - else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size) - args_size = cfi2; - else - gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state); - } - - cfi_args_size = args_size; - break; - } - case DW_CFA_GNU_args_size: - cfi_args_size = cfi; - break; - case DW_CFA_GNU_window_save: - goto flush_all; - case DW_CFA_offset: - case DW_CFA_offset_extended: - case DW_CFA_offset_extended_sf: - case DW_CFA_restore: - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_register: - case DW_CFA_val_offset: - case DW_CFA_val_offset_sf: - case DW_CFA_expression: - case DW_CFA_val_expression: - case DW_CFA_GNU_negative_offset_extended: - if (VEC_length (dw_cfi_ref, regs) - <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num) - VEC_safe_grow_cleared (dw_cfi_ref, heap, regs, - cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1); - VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, - cfi); - break; - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - case DW_CFA_def_cfa_expression: - cfi_cfa = cfi; - cfi_cfa_offset = cfi; - break; - case DW_CFA_def_cfa_register: - cfi_cfa = cfi; - break; - case DW_CFA_def_cfa_offset: - case DW_CFA_def_cfa_offset_sf: - cfi_cfa_offset = cfi; - break; - case DW_CFA_nop: - gcc_assert (cfi == NULL); - flush_all: - len = VEC_length (dw_cfi_ref, regs); - for (idx = 0; idx < len; idx++) - { - cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL); - if (cfi2 != NULL - && cfi2->dw_cfi_opc != DW_CFA_restore - && cfi2->dw_cfi_opc != DW_CFA_restore_extended) - { - if (do_cfi_asm) - output_cfi_directive (cfi2); - else - output_cfi (cfi2, fde, for_eh); - } - } - if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa) - { - gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression); - cfi_buf = *cfi_cfa; - switch (cfi_cfa_offset->dw_cfi_opc) - { - case DW_CFA_def_cfa_offset: - cfi_buf.dw_cfi_opc = DW_CFA_def_cfa; - cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1; - break; - case DW_CFA_def_cfa_offset_sf: - cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf; - cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1; - break; - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc; - cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2; - break; - default: - gcc_unreachable (); - } - cfi_cfa = &cfi_buf; - } - else if (cfi_cfa_offset) - cfi_cfa = cfi_cfa_offset; - if (cfi_cfa) - { - if (do_cfi_asm) - output_cfi_directive (cfi_cfa); - else - output_cfi (cfi_cfa, fde, for_eh); - } - cfi_cfa = NULL; - cfi_cfa_offset = NULL; - if (cfi_args_size - && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset) - { - if (do_cfi_asm) - output_cfi_directive (cfi_args_size); - else - output_cfi (cfi_args_size, fde, for_eh); - } - cfi_args_size = NULL; - if (cfi == NULL) - { - VEC_free (dw_cfi_ref, heap, regs); - return; - } - else if (do_cfi_asm) - output_cfi_directive (cfi); - else - output_cfi (cfi, fde, for_eh); - break; - default: - gcc_unreachable (); - } - } -} + case DW_CFA_expression: + return dw_cfi_oprnd_loc; -/* Like output_cfis, but emit all CFIs in the vector. */ -static void -output_all_cfis (cfi_vec vec, bool do_cfi_asm, - dw_fde_ref fde, bool for_eh) -{ - output_cfis (vec, VEC_length (dw_cfi_ref, vec), do_cfi_asm, fde, for_eh); + default: + return dw_cfi_oprnd_unused; + } } /* Output one FDE. */ @@ -3630,11 +520,9 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, char *section_start_label, int fde_encoding, char *augmentation, bool any_lsda_needed, int lsda_encoding) { - int ix; const char *begin, *end; static unsigned int j; char l1[20], l2[20]; - dw_cfi_ref cfi; targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh, /* empty */ 0); @@ -3714,36 +602,24 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, dw2_asm_output_data_uleb128 (0, "Augmentation size"); } - /* Loop through the Call Frame Instructions associated with - this FDE. */ + /* Loop through the Call Frame Instructions associated with this FDE. */ fde->dw_fde_current_label = begin; - if (fde->dw_fde_second_begin == NULL) - FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) - output_cfi (cfi, fde, for_eh); - else if (!second) - { - if (fde->dw_fde_switch_cfi_index > 0) - FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) - { - if (ix == fde->dw_fde_switch_cfi_index) - break; - output_cfi (cfi, fde, for_eh); - } - } - else - { - int i, from = 0; - int until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); + { + size_t from, until, i; - if (fde->dw_fde_switch_cfi_index > 0) - { - from = fde->dw_fde_switch_cfi_index; - output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh); - } - for (i = from; i < until; i++) - output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), - fde, for_eh); - } + from = 0; + until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); + + if (fde->dw_fde_second_begin == NULL) + ; + else if (!second) + until = fde->dw_fde_switch_cfi_index; + else + from = fde->dw_fde_switch_cfi_index; + + for (i = from; i < until; i++) + output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), fde, for_eh); + } /* If we are to emit a ref/link from function bodies to their frame tables, do it now. This is typically performed to make sure that tables @@ -3810,7 +686,7 @@ output_call_frame_info (int for_eh) int dw_cie_version; /* Don't emit a CIE if there won't be any FDEs. */ - if (fde_table_in_use == 0) + if (fde_vec == NULL) return; /* Nothing to do if the assembler's doing it all. */ @@ -3827,14 +703,15 @@ output_call_frame_info (int for_eh) { bool any_eh_needed = false; - for (i = 0; i < fde_table_in_use; i++) - if (fde_table[i].uses_eh_lsda) - any_eh_needed = any_lsda_needed = true; - else if (fde_needed_for_eh_p (&fde_table[i])) - any_eh_needed = true; - else if (TARGET_USES_WEAK_UNWIND_INFO) - targetm.asm_out.emit_unwind_label (asm_out_file, fde_table[i].decl, - 1, 1); + FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, i, fde) + { + if (fde->uses_eh_lsda) + any_eh_needed = any_lsda_needed = true; + else if (fde_needed_for_eh_p (fde)) + any_eh_needed = true; + else if (TARGET_USES_WEAK_UNWIND_INFO) + targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, 1, 1); + } if (!any_eh_needed) return; @@ -3987,10 +864,9 @@ output_call_frame_info (int for_eh) ASM_OUTPUT_LABEL (asm_out_file, l2); /* Loop through all of the FDE's. */ - for (i = 0; i < fde_table_in_use; i++) + FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, i, fde) { unsigned int k; - fde = &fde_table[i]; /* Don't emit EH unwind info for leaf functions that don't need it. */ if (for_eh && !fde_needed_for_eh_p (fde)) @@ -4061,6 +937,31 @@ dwarf2out_do_cfi_startproc (bool second) } } +/* Allocate CURRENT_FDE. Immediately initialize all we can, noting that + this allocation may be done before pass_final. */ + +dw_fde_ref +dwarf2out_alloc_current_fde (void) +{ + dw_fde_ref fde; + + fde = ggc_alloc_cleared_dw_fde_node (); + fde->decl = current_function_decl; + fde->funcdef_number = current_function_funcdef_no; + fde->fde_index = VEC_length (dw_fde_ref, fde_vec); + fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls; + fde->uses_eh_lsda = crtl->uses_eh_lsda; + fde->nothrow = crtl->nothrow; + fde->drap_reg = INVALID_REGNUM; + fde->vdrap_reg = INVALID_REGNUM; + + /* Record the FDE associated with this function. */ + cfun->fde = fde; + VEC_safe_push (dw_fde_ref, gc, fde_vec, fde); + + return fde; +} + /* Output a marker (i.e. a label) for the beginning of a function, before the prologue. */ @@ -4098,41 +999,19 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, if (!do_frame) return; - /* Expand the fde table if necessary. */ - if (fde_table_in_use == fde_table_allocated) - { - fde_table_allocated += FDE_TABLE_INCREMENT; - fde_table = GGC_RESIZEVEC (dw_fde_node, fde_table, fde_table_allocated); - memset (fde_table + fde_table_in_use, 0, - FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); - } - - /* Record the FDE associated with this function. */ - current_funcdef_fde = fde_table_in_use; + /* Cater to the various TARGET_ASM_OUTPUT_MI_THUNK implementations that + emit insns as rtx but bypass the bulk of rest_of_compilation, which + would include pass_dwarf2_frame. If we've not created the FDE yet, + do so now. */ + fde = cfun->fde; + if (fde == NULL) + fde = dwarf2out_alloc_current_fde (); - /* Add the new FDE at the end of the fde_table. */ - fde = &fde_table[fde_table_in_use++]; - fde->decl = current_function_decl; + /* Initialize the bits of CURRENT_FDE that were not available earlier. */ fde->dw_fde_begin = dup_label; - fde->dw_fde_end = NULL; fde->dw_fde_current_label = dup_label; - fde->dw_fde_second_begin = NULL; - fde->dw_fde_second_end = NULL; - fde->dw_fde_vms_end_prologue = NULL; - fde->dw_fde_vms_begin_epilogue = NULL; - fde->dw_fde_cfi = VEC_alloc (dw_cfi_ref, gc, 20); - fde->dw_fde_switch_cfi_index = 0; - fde->funcdef_number = current_function_funcdef_no; - fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls; - fde->uses_eh_lsda = crtl->uses_eh_lsda; - fde->nothrow = crtl->nothrow; - fde->drap_reg = INVALID_REGNUM; - fde->vdrap_reg = INVALID_REGNUM; fde->in_std_section = (fnsec == text_section || (cold_text_section && fnsec == cold_text_section)); - fde->second_in_std_section = 0; - - args_size = old_args_size = 0; /* We only want to output line number information for the genuine dwarf2 prologue case, not the eh frame case. */ @@ -4166,7 +1045,6 @@ void dwarf2out_vms_end_prologue (unsigned int line ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED) { - dw_fde_ref fde; char label[MAX_ARTIFICIAL_LABEL_BYTES]; /* Output a label to mark the endpoint of the code generated for this @@ -4175,8 +1053,7 @@ dwarf2out_vms_end_prologue (unsigned int line ATTRIBUTE_UNUSED, current_function_funcdef_no); ASM_OUTPUT_DEBUG_LABEL (asm_out_file, PROLOGUE_END_LABEL, current_function_funcdef_no); - fde = &fde_table[fde_table_in_use - 1]; - fde->dw_fde_vms_end_prologue = xstrdup (label); + cfun->fde->dw_fde_vms_end_prologue = xstrdup (label); } /* Output a marker (i.e. a label) for the beginning of the generated code @@ -4187,10 +1064,9 @@ void dwarf2out_vms_begin_epilogue (unsigned int line ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED) { - dw_fde_ref fde; + dw_fde_ref fde = cfun->fde; char label[MAX_ARTIFICIAL_LABEL_BYTES]; - fde = &fde_table[fde_table_in_use - 1]; if (fde->dw_fde_vms_begin_epilogue) return; @@ -4215,6 +1091,7 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, char label[MAX_ARTIFICIAL_LABEL_BYTES]; last_var_location_insn = NULL_RTX; + cached_next_real_insn = NULL_RTX; if (dwarf2out_do_cfi_asm ()) fprintf (asm_out_file, "\t.cfi_endproc\n"); @@ -4224,32 +1101,13 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_function_funcdef_no); ASM_OUTPUT_LABEL (asm_out_file, label); - fde = current_fde (); + fde = cfun->fde; gcc_assert (fde != NULL); if (fde->dw_fde_second_begin == NULL) fde->dw_fde_end = xstrdup (label); } void -dwarf2out_frame_init (void) -{ - /* Allocate the initial hunk of the fde_table. */ - fde_table = ggc_alloc_cleared_vec_dw_fde_node (FDE_TABLE_INCREMENT); - fde_table_allocated = FDE_TABLE_INCREMENT; - fde_table_in_use = 0; - - /* Generate the CFA instructions common to all FDE's. Do it now for the - sake of lookup_cfa. */ - - /* On entry, the Canonical Frame Address is at SP. */ - dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); - - if (targetm.debug_unwind_info () == UI_DWARF2 - || targetm_common.except_unwind_info (&global_options) == UI_DWARF2) - initial_return_save (INCOMING_RETURN_ADDR_RTX); -} - -void dwarf2out_frame_finish (void) { /* Output call frame information. */ @@ -4281,7 +1139,7 @@ void dwarf2out_switch_text_section (void) { section *sect; - dw_fde_ref fde = current_fde (); + dw_fde_ref fde = cfun->fde; gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL); @@ -4299,10 +1157,6 @@ dwarf2out_switch_text_section (void) } have_multiple_function_sections = true; - /* Reset the current label on switching text sections, so that we - don't attempt to advance_loc4 between labels in different sections. */ - fde->dw_fde_current_label = NULL; - /* There is no need to mark used sections when not debugging. */ if (cold_text_section != NULL) dwarf2out_note_section_used (); @@ -4319,16 +1173,12 @@ dwarf2out_switch_text_section (void) || (cold_text_section && sect == cold_text_section)); if (dwarf2out_do_cfi_asm ()) - { - dwarf2out_do_cfi_startproc (true); - /* As this is a different FDE, insert all current CFI instructions - again. */ - output_all_cfis (fde->dw_fde_cfi, true, fde, true); - } - fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); + dwarf2out_do_cfi_startproc (true); + var_location_switch_text_section (); - set_cur_line_info_table (sect); + if (cold_text_section != NULL) + set_cur_line_info_table (sect); } /* And now, the subset of the debugging information support code necessary @@ -4340,12 +1190,6 @@ struct GTY(()) dwarf_file_data { int emitted_number; }; -typedef struct dw_val_struct *dw_val_ref; -typedef struct die_struct *dw_die_ref; -typedef const struct die_struct *const_dw_die_ref; -typedef struct dw_loc_descr_struct *dw_loc_descr_ref; -typedef struct dw_loc_list_struct *dw_loc_list_ref; - typedef struct GTY(()) deferred_locations_struct { tree variable; @@ -4360,95 +1204,6 @@ 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. */ - -enum dw_val_class -{ - dw_val_class_addr, - dw_val_class_offset, - dw_val_class_loc, - dw_val_class_loc_list, - dw_val_class_range_list, - dw_val_class_const, - dw_val_class_unsigned_const, - dw_val_class_const_double, - dw_val_class_vec, - dw_val_class_flag, - dw_val_class_die_ref, - dw_val_class_fde_ref, - dw_val_class_lbl_id, - dw_val_class_lineptr, - dw_val_class_str, - dw_val_class_macptr, - dw_val_class_file, - dw_val_class_data8, - dw_val_class_decl_ref, - dw_val_class_vms_delta -}; - -/* Describe a floating point constant value, or a vector constant value. */ - -typedef struct GTY(()) dw_vec_struct { - unsigned char * GTY((length ("%h.length"))) array; - unsigned length; - unsigned elt_size; -} -dw_vec_const; - -/* The dw_val_node describes an attribute's value, as it is - represented internally. */ - -typedef struct GTY(()) dw_val_struct { - enum dw_val_class val_class; - union dw_val_struct_union - { - rtx GTY ((tag ("dw_val_class_addr"))) val_addr; - unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset; - dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list; - 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; - 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 - { - dw_die_ref die; - int external; - } GTY ((tag ("dw_val_class_die_ref"))) val_die_ref; - unsigned GTY ((tag ("dw_val_class_fde_ref"))) val_fde_index; - struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str; - 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]; - tree GTY ((tag ("dw_val_class_decl_ref"))) val_decl_ref; - struct dw_val_vms_delta_union - { - char * lbl1; - char * lbl2; - } GTY ((tag ("dw_val_class_vms_delta"))) val_vms_delta; - } - GTY ((desc ("%1.val_class"))) v; -} -dw_val_node; - -/* Locations in memory are described using a sequence of stack machine - operations. */ - -typedef struct GTY(()) dw_loc_descr_struct { - dw_loc_descr_ref dw_loc_next; - ENUM_BITFIELD (dwarf_location_atom) dw_loc_opc : 8; - /* Used to distinguish DW_OP_addr with a direct symbol relocation - from DW_OP_addr with a dtp-relative symbol relocation. */ - unsigned int dtprel : 1; - int dw_loc_addr; - dw_val_node dw_loc_oprnd1; - dw_val_node dw_loc_oprnd2; -} -dw_loc_descr_node; - /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over their entire life. */ @@ -4811,6 +1566,8 @@ dwarf_stack_op_name (unsigned int op) return "DW_OP_GNU_convert"; case DW_OP_GNU_reinterpret: return "DW_OP_GNU_reinterpret"; + case DW_OP_GNU_parameter_ref: + return "DW_OP_GNU_parameter_ref"; default: return "OP_"; @@ -4863,6 +1620,109 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr) *d = descr; } +/* Compare two location operands for exact equality. */ + +static bool +dw_val_equal_p (dw_val_node *a, dw_val_node *b) +{ + if (a->val_class != b->val_class) + return false; + switch (a->val_class) + { + case dw_val_class_none: + return true; + case dw_val_class_addr: + return rtx_equal_p (a->v.val_addr, b->v.val_addr); + + case dw_val_class_offset: + case dw_val_class_unsigned_const: + case dw_val_class_const: + case dw_val_class_range_list: + case dw_val_class_lineptr: + case dw_val_class_macptr: + /* These are all HOST_WIDE_INT, signed or unsigned. */ + return a->v.val_unsigned == b->v.val_unsigned; + + case dw_val_class_loc: + return a->v.val_loc == b->v.val_loc; + case dw_val_class_loc_list: + return a->v.val_loc_list == b->v.val_loc_list; + case dw_val_class_die_ref: + return a->v.val_die_ref.die == b->v.val_die_ref.die; + case dw_val_class_fde_ref: + return a->v.val_fde_index == b->v.val_fde_index; + case dw_val_class_lbl_id: + return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0; + case dw_val_class_str: + return a->v.val_str == b->v.val_str; + case dw_val_class_flag: + return a->v.val_flag == b->v.val_flag; + case dw_val_class_file: + return a->v.val_file == b->v.val_file; + case dw_val_class_decl_ref: + return a->v.val_decl_ref == b->v.val_decl_ref; + + case dw_val_class_const_double: + return (a->v.val_double.high == b->v.val_double.high + && a->v.val_double.low == b->v.val_double.low); + + case dw_val_class_vec: + { + size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length; + size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length; + + return (a_len == b_len + && !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len)); + } + + case dw_val_class_data8: + return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0; + + case dw_val_class_vms_delta: + return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1) + && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)); + } + gcc_unreachable (); +} + +/* Compare two location atoms for exact equality. */ + +static bool +loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b) +{ + if (a->dw_loc_opc != b->dw_loc_opc) + return false; + + /* ??? This is only ever set for DW_OP_constNu, for N equal to the + address size, but since we always allocate cleared storage it + should be zero for other types of locations. */ + if (a->dtprel != b->dtprel) + return false; + + return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1) + && dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2)); +} + +/* Compare two complete location expressions for exact equality. */ + +bool +loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b) +{ + while (1) + { + if (a == b) + return true; + if (a == NULL || b == NULL) + return false; + if (!loc_descr_equal_p_1 (a, b)) + return false; + + a = a->dw_loc_next; + b = b->dw_loc_next; + } +} + + /* Add a constant OFFSET to a location expression. */ static void @@ -4917,7 +1777,6 @@ loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset) #define DWARF_REF_SIZE \ (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE) -static unsigned long size_of_locs (dw_loc_descr_ref); static unsigned long int get_base_type_offset (dw_die_ref); /* Return the size of a location descriptor. */ @@ -5080,11 +1939,18 @@ size_of_loc_descr (dw_loc_descr_ref loc) break; case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: - { - unsigned long o - = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die); - size += size_of_uleb128 (o); - } + if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const) + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + else + { + unsigned long o + = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die); + size += size_of_uleb128 (o); + } + break; + case DW_OP_GNU_parameter_ref: + size += 4; + break; default: break; } @@ -5094,7 +1960,7 @@ size_of_loc_descr (dw_loc_descr_ref loc) /* Return the size of a series of location descriptors. */ -static unsigned long +unsigned long size_of_locs (dw_loc_descr_ref loc) { dw_loc_descr_ref l; @@ -5122,7 +1988,7 @@ size_of_locs (dw_loc_descr_ref loc) static HOST_WIDE_INT extract_int (const unsigned char *, unsigned); static void get_ref_die_offset_label (char *, dw_die_ref); -static void output_loc_sequence (dw_loc_descr_ref, int); +static unsigned long int get_ref_die_offset (dw_die_ref); /* Output location description stack opcode's operands (if any). The for_eh_or_skip parameter controls whether register numbers are @@ -5460,10 +2326,22 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) break; case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: + if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const) + dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL); + else + { + unsigned long o = get_base_type_offset (val1->v.val_die_ref.die); + gcc_assert (o); + dw2_asm_output_data_uleb128 (o, NULL); + } + break; + + case DW_OP_GNU_parameter_ref: { - unsigned long o = get_base_type_offset (val1->v.val_die_ref.die); - gcc_assert (o); - dw2_asm_output_data_uleb128 (o, NULL); + unsigned long o; + gcc_assert (val1->val_class == dw_val_class_die_ref); + o = get_ref_die_offset (val1->v.val_die_ref.die); + dw2_asm_output_data (4, o, NULL); } break; @@ -5480,7 +2358,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) info). This should be suppressed for the cases that have not been converted (i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */ -static void +void output_loc_sequence (dw_loc_descr_ref loc, int for_eh_or_skip) { for (; loc != NULL; loc = loc->dw_loc_next) @@ -5649,6 +2527,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc) case DW_OP_GNU_deref_type: case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: + case DW_OP_GNU_parameter_ref: gcc_unreachable (); break; @@ -5658,7 +2537,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc) } } -static void +void output_loc_sequence_raw (dw_loc_descr_ref loc) { while (1) @@ -5691,65 +2570,11 @@ output_loc_sequence_raw (dw_loc_descr_ref loc) } } -/* This routine will generate the correct assembly data for a location - description based on a cfi entry with a complex address. */ - -static void -output_cfa_loc (dw_cfi_ref cfi, int for_eh) -{ - dw_loc_descr_ref loc; - unsigned long size; - - if (cfi->dw_cfi_opc == DW_CFA_expression) - { - unsigned r = - DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); - dw2_asm_output_data (1, r, NULL); - loc = cfi->dw_cfi_oprnd2.dw_cfi_loc; - } - else - loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; - - /* Output the size of the block. */ - size = size_of_locs (loc); - dw2_asm_output_data_uleb128 (size, NULL); - - /* Now output the operations themselves. */ - output_loc_sequence (loc, for_eh); -} - -/* Similar, but used for .cfi_escape. */ - -static void -output_cfa_loc_raw (dw_cfi_ref cfi) -{ - dw_loc_descr_ref loc; - unsigned long size; - - if (cfi->dw_cfi_opc == DW_CFA_expression) - { - unsigned r = - DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "%#x,", r); - loc = cfi->dw_cfi_oprnd2.dw_cfi_loc; - } - else - loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; - - /* Output the size of the block. */ - size = size_of_locs (loc); - dw2_asm_output_data_uleb128_raw (size); - fputc (',', asm_out_file); - - /* Now output the operations themselves. */ - output_loc_sequence_raw (loc); -} - /* This function builds a dwarf location descriptor sequence from a dw_cfa_location, adding the given OFFSET to the result of the expression. */ -static struct dw_loc_descr_struct * +struct dw_loc_descr_struct * build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset) { struct dw_loc_descr_struct *head, *tmp; @@ -5778,15 +2603,16 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset) the address at OFFSET from the CFA when stack is aligned to ALIGNMENT byte. */ -static struct dw_loc_descr_struct * -build_cfa_aligned_loc (HOST_WIDE_INT offset, HOST_WIDE_INT alignment) +struct dw_loc_descr_struct * +build_cfa_aligned_loc (dw_cfa_location *cfa, + HOST_WIDE_INT offset, HOST_WIDE_INT alignment) { struct dw_loc_descr_struct *head; unsigned int dwarf_fp = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM); - /* When CFA is defined as FP+OFFSET, emulate stack alignment. */ - if (cfa.reg == HARD_FRAME_POINTER_REGNUM && cfa.indirect == 0) + /* When CFA is defined as FP+OFFSET, emulate stack alignment. */ + if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0) { head = new_reg_loc_descr (dwarf_fp, 0); add_loc_descr (&head, int_loc_descriptor (alignment)); @@ -5797,113 +2623,6 @@ build_cfa_aligned_loc (HOST_WIDE_INT offset, HOST_WIDE_INT alignment) head = new_reg_loc_descr (dwarf_fp, offset); return head; } - -/* This function fills in aa dw_cfa_location structure from a dwarf location - descriptor sequence. */ - -static void -get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_struct *loc) -{ - struct dw_loc_descr_struct *ptr; - cfa->offset = 0; - cfa->base_offset = 0; - cfa->indirect = 0; - cfa->reg = -1; - - for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next) - { - enum dwarf_location_atom op = ptr->dw_loc_opc; - - switch (op) - { - case DW_OP_reg0: - case DW_OP_reg1: - case DW_OP_reg2: - case DW_OP_reg3: - case DW_OP_reg4: - case DW_OP_reg5: - case DW_OP_reg6: - case DW_OP_reg7: - case DW_OP_reg8: - case DW_OP_reg9: - case DW_OP_reg10: - case DW_OP_reg11: - case DW_OP_reg12: - case DW_OP_reg13: - case DW_OP_reg14: - case DW_OP_reg15: - case DW_OP_reg16: - case DW_OP_reg17: - case DW_OP_reg18: - case DW_OP_reg19: - case DW_OP_reg20: - case DW_OP_reg21: - case DW_OP_reg22: - case DW_OP_reg23: - case DW_OP_reg24: - case DW_OP_reg25: - case DW_OP_reg26: - case DW_OP_reg27: - case DW_OP_reg28: - case DW_OP_reg29: - case DW_OP_reg30: - case DW_OP_reg31: - cfa->reg = op - DW_OP_reg0; - break; - case DW_OP_regx: - cfa->reg = ptr->dw_loc_oprnd1.v.val_int; - break; - case DW_OP_breg0: - case DW_OP_breg1: - case DW_OP_breg2: - case DW_OP_breg3: - case DW_OP_breg4: - case DW_OP_breg5: - case DW_OP_breg6: - case DW_OP_breg7: - case DW_OP_breg8: - case DW_OP_breg9: - case DW_OP_breg10: - case DW_OP_breg11: - case DW_OP_breg12: - case DW_OP_breg13: - case DW_OP_breg14: - case DW_OP_breg15: - case DW_OP_breg16: - case DW_OP_breg17: - case DW_OP_breg18: - case DW_OP_breg19: - case DW_OP_breg20: - case DW_OP_breg21: - case DW_OP_breg22: - case DW_OP_breg23: - case DW_OP_breg24: - case DW_OP_breg25: - case DW_OP_breg26: - case DW_OP_breg27: - case DW_OP_breg28: - case DW_OP_breg29: - case DW_OP_breg30: - case DW_OP_breg31: - cfa->reg = op - DW_OP_breg0; - cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int; - break; - case DW_OP_bregx: - cfa->reg = ptr->dw_loc_oprnd1.v.val_int; - cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int; - break; - case DW_OP_deref: - cfa->indirect = 1; - break; - case DW_OP_plus_uconst: - cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned; - break; - default: - internal_error ("DW_LOC_OP %s not implemented", - dwarf_stack_op_name (ptr->dw_loc_opc)); - } - } -} /* And now, the support for symbolic debugging information. */ @@ -6136,7 +2855,7 @@ struct GTY(()) dw_ranges_struct { /* A structure to hold a macinfo entry. */ typedef struct GTY(()) macinfo_struct { - unsigned HOST_WIDE_INT code; + unsigned char code; unsigned HOST_WIDE_INT lineno; const char *info; } @@ -6176,25 +2895,20 @@ typedef struct skeleton_chain_struct } skeleton_chain_node; -/* How to start an assembler comment. */ -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START ";#" -#endif - /* Define a macro which returns nonzero for a TYPE_DECL which was - implicitly generated for a tagged type. + implicitly generated for a type. - Note that unlike the gcc front end (which generates a NULL named - TYPE_DECL node for each complete tagged type, each array type, and - each function type node created) the g++ front end generates a - _named_ TYPE_DECL node for each tagged type node created. + Note that, unlike the C front-end (which generates a NULL named + TYPE_DECL node for each complete tagged type, each array type, + and each function type node created) the C++ front-end generates + a _named_ TYPE_DECL node for each tagged type node created. These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to - generate a DW_TAG_typedef DIE for them. */ + generate a DW_TAG_typedef DIE for them. Likewise with the Ada + front-end, but for each type, tagged or not. */ #define TYPE_DECL_IS_STUB(decl) \ (DECL_NAME (decl) == NULL_TREE \ || (DECL_ARTIFICIAL (decl) \ - && is_tagged_type (TREE_TYPE (decl)) \ && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \ /* This is necessary for stub decls that \ appear in nested inline functions. */ \ @@ -6420,6 +3134,12 @@ static GTY (()) VEC (pubname_entry, gc) * pubtype_table; defines/undefines (and file start/end markers). */ static GTY (()) VEC (macinfo_entry, gc) * macinfo_table; +/* True if .debug_macinfo or .debug_macros section is going to be + emitted. */ +#define have_macinfo \ + (debug_info_level >= DINFO_LEVEL_VERBOSE \ + && !VEC_empty (macinfo_entry, macinfo_table)) + /* Array of dies for which we should generate .debug_ranges info. */ static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table; @@ -6589,11 +3309,12 @@ 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 dw_die_ref 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, 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); @@ -6788,6 +3509,9 @@ static void gen_scheduled_generic_parms_dies (void); #ifndef DEBUG_MACINFO_SECTION #define DEBUG_MACINFO_SECTION ".debug_macinfo" #endif +#ifndef DEBUG_MACRO_SECTION +#define DEBUG_MACRO_SECTION ".debug_macro" +#endif #ifndef DEBUG_LINE_SECTION #define DEBUG_LINE_SECTION ".debug_line" #endif @@ -6845,6 +3569,9 @@ static void gen_scheduled_generic_parms_dies (void); #ifndef DEBUG_MACINFO_SECTION_LABEL #define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo" #endif +#ifndef DEBUG_MACRO_SECTION_LABEL +#define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro" +#endif /* Definitions of defaults for formats and names of various special @@ -6965,6 +3692,15 @@ get_base_type_offset (dw_die_ref ref) return ref->die_offset; } +/* Return die_offset of a DIE reference other than base type. */ + +static unsigned long int +get_ref_die_offset (dw_die_ref ref) +{ + gcc_assert (ref->die_offset); + return ref->die_offset; +} + /* Convert a DIE tag into its string name. */ static const char * @@ -7377,6 +4113,8 @@ dwarf_attr_name (unsigned int attr) return "DW_AT_GNU_all_call_sites"; case DW_AT_GNU_all_source_call_sites: return "DW_AT_GNU_all_source_call_sites"; + case DW_AT_GNU_macros: + return "DW_AT_GNU_macros"; case DW_AT_GNAT_descriptive_type: return "DW_AT_GNAT_descriptive_type"; @@ -10340,16 +7078,18 @@ clone_as_declaration (dw_die_ref die) return clone; } -/* Copy the declaration context to the new compile unit DIE. This includes +/* Copy the declaration context to the new type 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. */ + attached to the specification, and returns a pointer to the original + parent of the declaration DIE. Returns NULL otherwise. */ -static void +static dw_die_ref copy_declaration_context (dw_die_ref unit, dw_die_ref die) { dw_die_ref decl; dw_die_ref new_decl; + dw_die_ref orig_parent = NULL; decl = get_AT_ref (die, DW_AT_specification); if (decl == NULL) @@ -10360,6 +7100,10 @@ copy_declaration_context (dw_die_ref unit, dw_die_ref die) dw_die_ref c; dw_attr_ref a; + /* The original DIE will be changed to a declaration, and must + be moved to be a child of the original declaration DIE. */ + orig_parent = decl->die_parent; + /* 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; @@ -10388,6 +7132,8 @@ copy_declaration_context (dw_die_ref unit, dw_die_ref die) add_AT_specification (die, new_decl); } } + + return orig_parent; } /* Generate the skeleton ancestor tree for the given NODE, then clone @@ -10471,17 +7217,23 @@ generate_skeleton (dw_die_ref die) 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. */ +/* Remove the CHILD DIE from its parent, possibly replacing it with a cloned + declaration. The original DIE is 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) +remove_child_or_replace_with_skeleton (dw_die_ref unit, dw_die_ref child, + dw_die_ref prev) { - dw_die_ref skeleton; + dw_die_ref skeleton, orig_parent; + + /* Copy the declaration context to the type unit DIE. If the returned + ORIG_PARENT is not NULL, the skeleton needs to be added as a child of + that DIE. */ + orig_parent = copy_declaration_context (unit, child); skeleton = generate_skeleton (child); if (skeleton == NULL) @@ -10489,7 +7241,19 @@ remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev) else { skeleton->die_id.die_type_node = child->die_id.die_type_node; - replace_child (child, skeleton, prev); + + /* If the original DIE was a specification, we need to put + the skeleton under the parent DIE of the declaration. + This leaves the original declaration in the tree, but + it will be pruned later since there are no longer any + references to it. */ + if (orig_parent != NULL) + { + remove_child_with_prev (child, prev); + add_child_die (orig_parent, skeleton); + } + else + replace_child (child, skeleton, prev); } return skeleton; @@ -10534,11 +7298,9 @@ break_out_comdat_types (dw_die_ref die) 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); + declaration into the new type unit DIE, then remove this DIE + from the main CU (or replace it with a skeleton if necessary). */ + replacement = remove_child_or_replace_with_skeleton (unit, c, prev); /* Break out nested types into their own type units. */ break_out_comdat_types (c); @@ -10651,6 +7413,32 @@ copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table) return copy; } +/* Like clone_tree, but additionally enter all the children into + the hash table decl_table. */ + +static dw_die_ref +clone_tree_hash (dw_die_ref die, htab_t decl_table) +{ + dw_die_ref c; + dw_die_ref clone = clone_die (die); + struct decl_table_entry *entry; + void **slot = htab_find_slot_with_hash (decl_table, die, + htab_hash_pointer (die), INSERT); + /* Assert that DIE isn't in the hash table yet. If it would be there + before, the ancestors would be necessarily there as well, therefore + clone_tree_hash wouldn't be called. */ + gcc_assert (*slot == HTAB_EMPTY_ENTRY); + entry = XCNEW (struct decl_table_entry); + entry->orig = die; + entry->copy = clone; + *slot = entry; + + FOR_EACH_CHILD (die, c, + add_child_die (clone, clone_tree_hash (c, decl_table))); + + return clone; +} + /* 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). */ @@ -10687,11 +7475,7 @@ copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table) 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); + dw_die_ref copy = clone_die (targ); /* Record in DECL_TABLE that TARG has been copied. Need to do this now, before the recursive call, @@ -10702,6 +7486,14 @@ copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table) entry->copy = copy; *slot = entry; + FOR_EACH_CHILD (targ, c, + add_child_die (copy, + clone_tree_hash (c, decl_table))); + + /* Make sure the cloned tree is marked as part of the + type unit. */ + mark_dies (copy); + /* If TARG has surrounding context, copy its ancestor tree into the new type unit. */ if (targ->die_parent != NULL @@ -10924,7 +7716,15 @@ size_of_die (dw_die_ref die) size += size_of_sleb128 (AT_int (a)); break; case dw_val_class_unsigned_const: - size += constant_size (AT_unsigned (a)); + { + int csize = constant_size (AT_unsigned (a)); + if (dwarf_version == 3 + && a->dw_attr == DW_AT_data_member_location + && csize >= 4) + size += size_of_uleb128 (AT_unsigned (a)); + else + size += csize; + } break; case dw_val_class_const_double: size += 2 * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; @@ -11138,12 +7938,11 @@ size_of_aranges (void) size += 2 * DWARF2_ADDR_SIZE; if (have_multiple_function_sections) { - unsigned fde_idx = 0; + unsigned fde_idx; + dw_fde_ref fde; - for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++) + FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde) { - dw_fde_ref fde = &fde_table[fde_idx]; - if (!fde->in_std_section) size += 2 * DWARF2_ADDR_SIZE; if (fde->dw_fde_second_begin && !fde->second_in_std_section) @@ -11213,6 +8012,8 @@ value_format (dw_attr_ref a) return DW_FORM_block1; case 2: return DW_FORM_block2; + case 4: + return DW_FORM_block4; default: gcc_unreachable (); } @@ -11226,8 +8027,16 @@ value_format (dw_attr_ref a) case 2: return DW_FORM_data2; case 4: + /* In DWARF3 DW_AT_data_member_location with + DW_FORM_data4 or DW_FORM_data8 is a loclistptr, not + constant, so we need to use DW_FORM_udata if we need + a large constant. */ + if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location) + return DW_FORM_udata; return DW_FORM_data4; case 8: + if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location) + return DW_FORM_udata; return DW_FORM_data8; default: gcc_unreachable (); @@ -11324,9 +8133,6 @@ output_abbrev_section (void) { unsigned long abbrev_id; - if (abbrev_die_table_in_use == 1) - return; - for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) { dw_die_ref abbrev = abbrev_die_table[abbrev_id]; @@ -11424,6 +8230,13 @@ output_loc_list (dw_loc_list_ref list_head) /* Don't output an entry that starts and ends at the same address. */ if (strcmp (curr->begin, curr->end) == 0 && !curr->force) continue; + size = size_of_locs (curr->expr); + /* If the expression is too large, drop it on the floor. We could + perhaps put it into DW_TAG_dwarf_procedure and refer to that + in the expression, but >= 64KB expressions for a single value + in a single range are unlikely very useful. */ + if (size > 0xffff) + continue; if (!have_multiple_function_sections) { dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section, @@ -11442,7 +8255,6 @@ output_loc_list (dw_loc_list_ref list_head) "Location list end address (%s)", list_head->ll_symbol); } - size = size_of_locs (curr->expr); /* Output the block length for this list of location operations. */ gcc_assert (size <= 0xffff); @@ -11537,8 +8349,15 @@ output_die (dw_die_ref die) break; case dw_val_class_unsigned_const: - dw2_asm_output_data (constant_size (AT_unsigned (a)), - AT_unsigned (a), "%s", name); + { + int csize = constant_size (AT_unsigned (a)); + if (dwarf_version == 3 + && a->dw_attr == DW_AT_data_member_location + && csize >= 4) + dw2_asm_output_data_uleb128 (AT_unsigned (a), "%s", name); + else + dw2_asm_output_data (csize, AT_unsigned (a), "%s", name); + } break; case dw_val_class_const_double: @@ -12034,12 +8853,11 @@ output_aranges (unsigned long aranges_length) if (have_multiple_function_sections) { - unsigned fde_idx = 0; + unsigned fde_idx; + dw_fde_ref fde; - for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++) + FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde) { - dw_fde_ref fde = &fde_table[fde_idx]; - if (!fde->in_std_section) { dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin, @@ -12974,6 +9792,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, tree item_type = NULL; tree qualified_type; tree name, low, high; + dw_die_ref mod_scope; if (code == ERROR_MARK) return NULL; @@ -13034,6 +9853,8 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, /* Else cv-qualified version of named type; fall through. */ } + mod_scope = scope_die_for (type, context_die); + if (is_const_type /* If both is_const_type and is_volatile_type, prefer the path which leads to a qualified type. */ @@ -13041,17 +9862,17 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, || get_qualified_type (type, TYPE_QUAL_CONST) == NULL_TREE || get_qualified_type (type, TYPE_QUAL_VOLATILE) != NULL_TREE)) { - mod_type_die = new_die (DW_TAG_const_type, comp_unit_die (), type); + mod_type_die = new_die (DW_TAG_const_type, mod_scope, type); sub_die = modified_type_die (type, 0, is_volatile_type, context_die); } else if (is_volatile_type) { - mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die (), type); + mod_type_die = new_die (DW_TAG_volatile_type, mod_scope, type); sub_die = modified_type_die (type, is_const_type, 0, context_die); } else if (code == POINTER_TYPE) { - mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die (), type); + mod_type_die = new_die (DW_TAG_pointer_type, mod_scope, 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); @@ -13062,10 +9883,10 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, else if (code == REFERENCE_TYPE) { if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4) - mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die (), + mod_type_die = new_die (DW_TAG_rvalue_reference_type, mod_scope, type); else - mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die (), type); + mod_type_die = new_die (DW_TAG_reference_type, mod_scope, 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); @@ -13119,11 +9940,17 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, useful source coordinates anyway. */ name = DECL_NAME (name); add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name)); - add_gnat_descriptive_type_attribute (mod_type_die, type, context_die); } /* This probably indicates a bug. */ else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type) - add_name_attribute (mod_type_die, "__unknown__"); + { + name = TYPE_NAME (type); + if (name + && TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + add_name_attribute (mod_type_die, + name ? IDENTIFIER_POINTER (name) : "__unknown__"); + } if (qualified_type) equate_type_number_to_die (qualified_type, mod_type_die); @@ -13141,6 +9968,10 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, if (sub_die != NULL) add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); + add_gnat_descriptive_type_attribute (mod_type_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (mod_type_die, DW_AT_artificial, 1); + return mod_type_die; } @@ -13500,6 +10331,21 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs, return loc_result; } +static unsigned long size_of_int_loc_descriptor (HOST_WIDE_INT); + +/* Return a location descriptor that designates a constant i, + as a compound operation from constant (i >> shift), constant shift + and DW_OP_shl. */ + +static dw_loc_descr_ref +int_shift_loc_descriptor (HOST_WIDE_INT i, int shift) +{ + dw_loc_descr_ref ret = int_loc_descriptor (i >> shift); + add_loc_descr (&ret, int_loc_descriptor (shift)); + add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0)); + return ret; +} + /* Return a location descriptor that designates a constant. */ static dw_loc_descr_ref @@ -13511,15 +10357,45 @@ int_loc_descriptor (HOST_WIDE_INT i) defaulting to the LEB encoding. */ if (i >= 0) { + int clz = clz_hwi (i); + int ctz = ctz_hwi (i); if (i <= 31) op = (enum dwarf_location_atom) (DW_OP_lit0 + i); else if (i <= 0xff) op = DW_OP_const1u; else if (i <= 0xffff) op = DW_OP_const2u; - else if (HOST_BITS_PER_WIDE_INT == 32 - || i <= 0xffffffff) + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5 + && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT) + /* DW_OP_litX DW_OP_litY DW_OP_shl takes just 3 bytes and + DW_OP_litX DW_OP_const1u Y DW_OP_shl takes just 4 bytes, + while DW_OP_const4u is 5 bytes. */ + return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 5); + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8 + && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT) + /* DW_OP_const1u X DW_OP_litY DW_OP_shl takes just 4 bytes, + while DW_OP_const4u is 5 bytes. */ + return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8); + else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff) op = DW_OP_const4u; + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8 + && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT) + /* DW_OP_const1u X DW_OP_const1u Y DW_OP_shl takes just 5 bytes, + while DW_OP_constu of constant >= 0x100000000 takes at least + 6 bytes. */ + return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8); + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16 + && clz + 16 + (size_of_uleb128 (i) > 5 ? 255 : 31) + >= HOST_BITS_PER_WIDE_INT) + /* DW_OP_const2u X DW_OP_litY DW_OP_shl takes just 5 bytes, + DW_OP_const2u X DW_OP_const1u Y DW_OP_shl takes 6 bytes, + while DW_OP_constu takes in this case at least 6 bytes. */ + return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 16); + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32 + && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT + && size_of_uleb128 (i) > 6) + /* DW_OP_const4u X DW_OP_litY DW_OP_shl takes just 7 bytes. */ + return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 32); else op = DW_OP_constu; } @@ -13529,54 +10405,132 @@ int_loc_descriptor (HOST_WIDE_INT i) op = DW_OP_const1s; else if (i >= -0x8000) op = DW_OP_const2s; - else if (HOST_BITS_PER_WIDE_INT == 32 - || i >= -0x80000000) - op = DW_OP_const4s; + else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000) + { + if (size_of_int_loc_descriptor (i) < 5) + { + dw_loc_descr_ref ret = int_loc_descriptor (-i); + add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0)); + return ret; + } + op = DW_OP_const4s; + } else - op = DW_OP_consts; + { + if (size_of_int_loc_descriptor (i) + < (unsigned long) 1 + size_of_sleb128 (i)) + { + dw_loc_descr_ref ret = int_loc_descriptor (-i); + add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0)); + return ret; + } + op = DW_OP_consts; + } } return new_loc_descr (op, i, 0); } -/* Return loc description representing "address" of integer value. - This can appear only as toplevel expression. */ +/* Return size_of_locs (int_shift_loc_descriptor (i, shift)) + without actually allocating it. */ -static dw_loc_descr_ref -address_of_int_loc_descriptor (int size, HOST_WIDE_INT i) +static unsigned long +size_of_int_shift_loc_descriptor (HOST_WIDE_INT i, int shift) { - int litsize; - dw_loc_descr_ref loc_result = NULL; + return size_of_int_loc_descriptor (i >> shift) + + size_of_int_loc_descriptor (shift) + + 1; +} - if (!(dwarf_version >= 4 || !dwarf_strict)) - return NULL; +/* Return size_of_locs (int_loc_descriptor (i)) without + actually allocating it. */ + +static unsigned long +size_of_int_loc_descriptor (HOST_WIDE_INT i) +{ + unsigned long s; if (i >= 0) { + int clz, ctz; if (i <= 31) - litsize = 1; + return 1; else if (i <= 0xff) - litsize = 2; + return 2; else if (i <= 0xffff) - litsize = 3; - else if (HOST_BITS_PER_WIDE_INT == 32 - || i <= 0xffffffff) - litsize = 5; + return 3; + clz = clz_hwi (i); + ctz = ctz_hwi (i); + if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5 + && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT) + return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT + - clz - 5); + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8 + && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT) + return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT + - clz - 8); + else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff) + return 5; + s = size_of_uleb128 ((unsigned HOST_WIDE_INT) i); + if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8 + && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT) + return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT + - clz - 8); + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16 + && clz + 16 + (s > 5 ? 255 : 31) >= HOST_BITS_PER_WIDE_INT) + return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT + - clz - 16); + else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32 + && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT + && s > 6) + return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT + - clz - 32); else - litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i); + return 1 + s; } else { if (i >= -0x80) - litsize = 2; + return 2; else if (i >= -0x8000) - litsize = 3; - else if (HOST_BITS_PER_WIDE_INT == 32 - || i >= -0x80000000) - litsize = 5; + return 3; + else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000) + { + if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i) + { + s = size_of_int_loc_descriptor (-i) + 1; + if (s < 5) + return s; + } + return 5; + } else - litsize = 1 + size_of_sleb128 (i); + { + unsigned long r = 1 + size_of_sleb128 (i); + if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i) + { + s = size_of_int_loc_descriptor (-i) + 1; + if (s < r) + return s; + } + return r; + } } +} + +/* 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; + + litsize = size_of_int_loc_descriptor (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) @@ -13605,7 +10559,7 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset, { unsigned int regno; dw_loc_descr_ref result; - dw_fde_ref fde = current_fde (); + dw_fde_ref fde = cfun->fde; /* We only use "frame base" when we're sure we're talking about the post-prologue local stack frame. We do this by *not* running @@ -13648,10 +10602,20 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset, return new_loc_descr (DW_OP_fbreg, offset, 0); } } - else if (!optimize - && fde - && (fde->drap_reg == REGNO (reg) - || fde->vdrap_reg == REGNO (reg))) + + regno = REGNO (reg); +#ifdef LEAF_REG_REMAP + if (current_function_uses_only_leaf_regs) + { + int leaf_reg = LEAF_REG_REMAP (regno); + if (leaf_reg != -1) + regno = (unsigned) leaf_reg; + } +#endif + regno = DWARF_FRAME_REGNUM (regno); + + if (!optimize && fde + && (fde->drap_reg == regno || fde->vdrap_reg == regno)) { /* Use cfa+offset to represent the location of arguments passed on the stack when drap is used to align stack. @@ -13662,7 +10626,6 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset, return new_loc_descr (DW_OP_fbreg, offset, 0); } - regno = dbx_reg_number (reg); if (regno <= 31) result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno), offset, 0); @@ -13695,7 +10658,7 @@ tls_mem_loc_descriptor (rtx mem) tree base; dw_loc_descr_ref loc_result; - if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX) + if (MEM_EXPR (mem) == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem)) return NULL; base = get_base_address (MEM_EXPR (mem)); @@ -13708,8 +10671,8 @@ tls_mem_loc_descriptor (rtx mem) if (loc_result == NULL) return NULL; - if (INTVAL (MEM_OFFSET (mem))) - loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem))); + if (MEM_OFFSET (mem)) + loc_descr_plus_const (&loc_result, MEM_OFFSET (mem)); return loc_result; } @@ -13772,6 +10735,13 @@ const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED) return 1; } + if (targetm.const_not_ok_for_debug_p (rtl)) + { + expansion_failed (NULL_TREE, rtl, + "Expression rejected for debug by the backend.\n"); + return 1; + } + if (GET_CODE (rtl) != SYMBOL_REF) return 0; @@ -13855,27 +10825,24 @@ base_type_for_mode (enum machine_mode mode, bool unsignedp) return type_die; } -/* For OP descriptor assumed to be in unsigned MODE, convert it to a signed - type matching MODE, or, if MODE is narrower than DWARF2_ADDR_SIZE, signed - type matching DWARF2_ADDR_SIZE. Return NULL if the conversion is not +/* For OP descriptor assumed to be in unsigned MODE, convert it to a unsigned + type matching MODE, or, if MODE is narrower than or as wide as + DWARF2_ADDR_SIZE, untyped. Return NULL if the conversion is not possible. */ static dw_loc_descr_ref -convert_descriptor_to_signed (enum machine_mode mode, dw_loc_descr_ref op) +convert_descriptor_to_mode (enum machine_mode mode, dw_loc_descr_ref op) { enum machine_mode outer_mode = mode; dw_die_ref type_die; dw_loc_descr_ref cvt; - if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE) + if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE) { - outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT, - MODE_INT, 0); - if (outer_mode == BLKmode - || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE) - return NULL; + add_loc_descr (&op, new_loc_descr (DW_OP_GNU_convert, 0, 0)); + return op; } - type_die = base_type_for_mode (outer_mode, 0); + type_die = base_type_for_mode (outer_mode, 1); if (type_die == NULL) return NULL; cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); @@ -13932,9 +10899,29 @@ scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl, return NULL; if (GET_MODE_CLASS (op_mode) != MODE_INT - || GET_MODE_SIZE (op_mode) >= DWARF2_ADDR_SIZE) + || GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE) return compare_loc_descriptor (op, op0, op1); + if (GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE) + { + dw_die_ref type_die = base_type_for_mode (op_mode, 0); + dw_loc_descr_ref cvt; + + if (type_die == NULL) + return NULL; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op1, cvt); + return compare_loc_descriptor (op, op0, op1); + } + shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode)) * BITS_PER_UNIT; /* For eq/ne, if the operands are known to be zero-extended, there is no need to do the fancy shifting up. */ @@ -13958,6 +10945,28 @@ scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl, && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 1)) == (INTVAL (XEXP (rtl, 1)) & GET_MODE_MASK (op_mode))))) return compare_loc_descriptor (op, op0, op1); + + /* EQ/NE comparison against constant in narrower type than + DWARF2_ADDR_SIZE can be performed either as + DW_OP_const1u DW_OP_shl DW_OP_const* + DW_OP_{eq,ne} + or + DW_OP_const*u DW_OP_and DW_OP_const* + DW_OP_{eq,ne}. Pick whatever is shorter. */ + if (CONST_INT_P (XEXP (rtl, 1)) + && GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT + && (size_of_int_loc_descriptor (shift) + 1 + + size_of_int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift) + >= size_of_int_loc_descriptor (GET_MODE_MASK (op_mode)) + 1 + + size_of_int_loc_descriptor (INTVAL (XEXP (rtl, 1)) + & GET_MODE_MASK (op_mode)))) + { + add_loc_descr (&op0, int_loc_descriptor (GET_MODE_MASK (op_mode))); + add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0)); + op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) + & GET_MODE_MASK (op_mode)); + return compare_loc_descriptor (op, op0, op1); + } } add_loc_descr (&op0, int_loc_descriptor (shift)); add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0)); @@ -13990,9 +10999,6 @@ ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl, if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE) return NULL; - if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT) - return NULL; - op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode, @@ -14040,24 +11046,6 @@ ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl, add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0)); } - else - { - dw_die_ref type_die = base_type_for_mode (op_mode, 1); - dw_loc_descr_ref cvt; - - if (type_die == NULL) - return NULL; - cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); - cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; - cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; - cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; - add_loc_descr (&op0, cvt); - cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); - cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; - cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; - cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; - add_loc_descr (&op1, cvt); - } return compare_loc_descriptor (op, op0, op1); } @@ -14104,23 +11092,6 @@ minmax_loc_descriptor (rtx rtl, enum machine_mode mode, 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 - { - dw_die_ref type_die = base_type_for_mode (mode, 1); - dw_loc_descr_ref cvt; - if (type_die == NULL) - return NULL; - cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); - cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; - cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; - cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; - add_loc_descr (&op0, cvt); - cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); - cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; - cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; - cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; - add_loc_descr (&op1, cvt); - } } else if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE) @@ -14131,6 +11102,24 @@ minmax_loc_descriptor (rtx rtl, enum machine_mode mode, add_loc_descr (&op1, int_loc_descriptor (shift)); add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); } + else if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + { + dw_die_ref type_die = base_type_for_mode (mode, 0); + dw_loc_descr_ref cvt; + if (type_die == NULL) + return NULL; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op1, cvt); + } if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN) op = DW_OP_lt; @@ -14146,9 +11135,46 @@ minmax_loc_descriptor (rtx rtl, enum machine_mode mode, add_loc_descr (&ret, drop_node); bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc; bra_node->dw_loc_oprnd1.v.val_loc = drop_node; + if ((GET_CODE (rtl) == SMIN || GET_CODE (rtl) == SMAX) + && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + ret = convert_descriptor_to_mode (mode, ret); return ret; } +/* Helper function for mem_loc_descriptor. Perform OP binary op, + but after converting arguments to type_die, afterwards + convert back to unsigned. */ + +static dw_loc_descr_ref +typed_binop (enum dwarf_location_atom op, rtx rtl, dw_die_ref type_die, + enum machine_mode mode, enum machine_mode mem_mode) +{ + dw_loc_descr_ref cvt, op0, op1; + + if (type_die == NULL) + return NULL; + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + if (op0 == NULL || op1 == NULL) + return NULL; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op1, cvt); + add_loc_descr (&op0, op1); + add_loc_descr (&op0, new_loc_descr (op, 0, 0)); + return convert_descriptor_to_mode (mode, op0); +} + /* CLZ (where constV is CLZ_DEFINED_VALUE_AT_ZERO computed value, const0 is DW_OP_lit0 or corresponding typed constant, const1 is DW_OP_lit1 or corresponding typed constant @@ -14507,6 +11533,45 @@ rotate_loc_descriptor (rtx rtl, enum machine_mode mode, return ret; } +/* Helper function for mem_loc_descriptor. Return DW_OP_GNU_parameter_ref + for DEBUG_PARAMETER_REF RTL. */ + +static dw_loc_descr_ref +parameter_ref_descriptor (rtx rtl) +{ + dw_loc_descr_ref ret; + dw_die_ref ref; + + if (dwarf_strict) + return NULL; + gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL); + ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl)); + ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0); + if (ref) + { + ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + ret->dw_loc_oprnd1.v.val_die_ref.die = ref; + ret->dw_loc_oprnd1.v.val_die_ref.external = 0; + } + else + { + ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref; + ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_PARAMETER_REF_DECL (rtl); + } + return ret; +} + +/* Helper function to get mode of MEM's address. */ + +enum machine_mode +get_address_mode (rtx mem) +{ + enum machine_mode mode = GET_MODE (XEXP (mem, 0)); + if (mode != VOIDmode) + return mode; + return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); +} + /* 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 @@ -14524,7 +11589,7 @@ rotate_loc_descriptor (rtx rtl, enum machine_mode mode, Return 0 if we can't represent the location. */ -static dw_loc_descr_ref +dw_loc_descr_ref mem_loc_descriptor (rtx rtl, enum machine_mode mode, enum machine_mode mem_mode, enum var_init_status initialized) @@ -14593,7 +11658,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, mem_mode, initialized); if (mem_loc_result == NULL) break; - type_die = base_type_for_mode (mode, 0); + type_die = base_type_for_mode (mode, + GET_MODE_CLASS (mode) == MODE_INT); if (type_die == NULL) { mem_loc_result = NULL; @@ -14625,7 +11691,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, break; if (REGNO (rtl) > FIRST_PSEUDO_REGISTER) break; - type_die = base_type_for_mode (mode, 0); + type_die = base_type_for_mode (mode, + GET_MODE_CLASS (mode) == MODE_INT); if (type_die == NULL) break; mem_loc_result = new_loc_descr (DW_OP_GNU_regval_type, @@ -14664,7 +11731,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case SIGN_EXTEND: case ZERO_EXTEND: - gcc_assert (GET_MODE_CLASS (mode) == MODE_INT); + if (GET_MODE_CLASS (mode) != MODE_INT) + break; op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)), mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0) @@ -14708,7 +11776,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, GET_CODE (rtl) == ZERO_EXTEND); if (type_die1 == NULL) break; - type_die2 = base_type_for_mode (mode, 0); + type_die2 = base_type_for_mode (mode, 1); if (type_die2 == NULL) break; mem_loc_result = op0; @@ -14726,12 +11794,22 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, break; case MEM: + { + rtx new_rtl = avoid_constant_pool_reference (rtl); + if (new_rtl != rtl) + { + mem_loc_result = mem_loc_descriptor (new_rtl, mode, mem_mode, + initialized); + if (mem_loc_result != NULL) + return mem_loc_result; + } + } mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl), mode, VAR_INIT_STATUS_INITIALIZED); if (mem_loc_result == NULL) mem_loc_result = tls_mem_loc_descriptor (rtl); - if (mem_loc_result != 0) + if (mem_loc_result != NULL) { if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE || GET_MODE_CLASS (mode) != MODE_INT) @@ -14741,7 +11819,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (dwarf_strict) return NULL; - type_die = base_type_for_mode (mode, 0); + type_die + = base_type_for_mode (mode, GET_MODE_CLASS (mode) == MODE_INT); if (type_die == NULL) return NULL; deref = new_loc_descr (DW_OP_GNU_deref_type, @@ -14758,12 +11837,6 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, new_loc_descr (DW_OP_deref_size, GET_MODE_SIZE (mode), 0)); } - else - { - rtx new_rtl = avoid_constant_pool_reference (rtl); - if (new_rtl != rtl) - return mem_loc_descriptor (new_rtl, mode, mem_mode, initialized); - } break; case LO_SUM: @@ -14853,7 +11926,11 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0); mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc; mem_loc_result->dw_loc_oprnd1.v.val_loc = op0; - return mem_loc_result; + break; + + case DEBUG_PARAMETER_REF: + mem_loc_result = parameter_ref_descriptor (rtl); + break; case PRE_MODIFY: /* Extract the PLUS expression nested inside and fall into @@ -14892,12 +11969,11 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1))); else { - dw_loc_descr_ref mem_loc_result2 - = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, - VAR_INIT_STATUS_INITIALIZED); - if (mem_loc_result2 == 0) + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + if (op1 == 0) break; - add_loc_descr (&mem_loc_result, mem_loc_result2); + add_loc_descr (&mem_loc_result, op1); add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); } @@ -14915,6 +11991,15 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_binop; case DIV: + if (!dwarf_strict + && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + { + mem_loc_result = typed_binop (DW_OP_div, rtl, + base_type_for_mode (mode, 0), + mode, mem_mode); + break; + } op = DW_OP_div; goto do_binop; @@ -14986,12 +12071,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case MOD: if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE && !dwarf_strict) { - /* If MODE is wider than DWARF2_ADDR_SIZE, mem_loc_descriptor - should return signed typed values and therefore DW_OP_mod - won't be unsigned as it defaults for untyped stack values, - but signed. */ - op = DW_OP_mod; - goto do_binop; + mem_loc_result = typed_binop (DW_OP_mod, rtl, + base_type_for_mode (mode, 0), + mode, mem_mode); + break; } op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, @@ -15014,32 +12097,14 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case UDIV: if (!dwarf_strict && GET_MODE_CLASS (mode) == MODE_INT) { - dw_die_ref type_die; - dw_loc_descr_ref cvt; - - type_die = base_type_for_mode (mode, 1); - if (type_die == NULL) - break; - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, - VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, - VAR_INIT_STATUS_INITIALIZED); - if (op0 == 0 || op1 == 0) - break; - cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); - cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; - cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; - cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; - add_loc_descr (&op0, cvt); - cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); - cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; - cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; - cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; - add_loc_descr (&op1, cvt); - mem_loc_result = op0; - add_loc_descr (&mem_loc_result, op1); - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0)); - mem_loc_result = convert_descriptor_to_signed (mode, mem_loc_result); + if (GET_MODE_CLASS (mode) > DWARF2_ADDR_SIZE) + { + op = DW_OP_div; + goto do_binop; + } + mem_loc_result = typed_binop (DW_OP_div, rtl, + base_type_for_mode (mode, 1), + mode, mem_mode); } break; @@ -15082,9 +12147,28 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, && (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT || GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT)) { - dw_die_ref type_die = base_type_for_mode (mode, 0); + dw_die_ref type_die = base_type_for_mode (mode, 1); + enum machine_mode amode; if (type_die == NULL) return NULL; + amode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT, + MODE_INT, 0); + if (INTVAL (rtl) >= 0 + && amode != BLKmode + && trunc_int_for_mode (INTVAL (rtl), amode) == INTVAL (rtl) + /* const DW_OP_GNU_convert vs. + DW_OP_GNU_const_type . */ + && size_of_int_loc_descriptor (INTVAL (rtl)) + 1 + 1 + < (unsigned long) 1 + 1 + 1 + GET_MODE_SIZE (mode)) + { + mem_loc_result = int_loc_descriptor (INTVAL (rtl)); + op0 = new_loc_descr (DW_OP_GNU_convert, 0, 0); + op0->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + op0->dw_loc_oprnd1.v.val_die_ref.die = type_die; + op0->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&mem_loc_result, op0); + return mem_loc_result; + } mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, INTVAL (rtl)); mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref; @@ -15115,7 +12199,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, || (GET_MODE (rtl) == VOIDmode && GET_MODE_BITSIZE (mode) != 2 * HOST_BITS_PER_WIDE_INT)) break; - type_die = base_type_for_mode (mode, 0); + type_die = base_type_for_mode (mode, + GET_MODE_CLASS (mode) == MODE_INT); if (type_die == NULL) return NULL; mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0); @@ -15279,7 +12364,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (op0 == NULL) break; if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) == MODE_INT - && (GET_CODE (rtl) == UNSIGNED_FLOAT + && (GET_CODE (rtl) == FLOAT || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)) { @@ -15302,10 +12387,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; add_loc_descr (&op0, cvt); if (GET_MODE_CLASS (mode) == MODE_INT - && (GET_CODE (rtl) == UNSIGNED_FIX + && (GET_CODE (rtl) == FIX || GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)) { - op0 = convert_descriptor_to_signed (mode, op0); + op0 = convert_descriptor_to_mode (mode, op0); if (op0 == NULL) break; } @@ -15377,6 +12462,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case STRICT_LOW_PART: case CONST_VECTOR: case CONST_FIXED: + case CLRSB: /* 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. */ @@ -15515,7 +12601,8 @@ loc_descriptor (rtx rtl, enum machine_mode mode, legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ if (REG_P (SUBREG_REG (rtl)) && subreg_lowpart_p (rtl)) - loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized); + loc_result = loc_descriptor (SUBREG_REG (rtl), + GET_MODE (SUBREG_REG (rtl)), initialized); else goto do_default; break; @@ -16006,7 +13093,7 @@ dw_sra_loc_expr (tree decl, rtx loc) if (MEM_P (varloc)) { unsigned HOST_WIDE_INT memsize - = INTVAL (MEM_SIZE (varloc)) * BITS_PER_UNIT; + = MEM_SIZE (varloc) * BITS_PER_UNIT; if (memsize != bitsize) { if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN @@ -16099,7 +13186,7 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) && (node != loc_list->first || loc_list->first->next) && current_function_decl) { - endname = current_fde ()->dw_fde_end; + endname = cfun->fde->dw_fde_end; range_across_switch = true; } /* The variable has a location between NODE->LABEL and @@ -16142,9 +13229,9 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) if (node->next) endname = node->next->label; else - endname = current_fde ()->dw_fde_second_end; + endname = cfun->fde->dw_fde_second_end; *listp = new_loc_list (descr, - current_fde ()->dw_fde_second_begin, + cfun->fde->dw_fde_second_begin, endname, secname); listp = &(*listp)->dw_loc_next; } @@ -18250,7 +15337,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) const char *start_label, *last_label, *section; dw_cfa_location remember; - fde = current_fde (); + fde = cfun->fde; gcc_assert (fde != NULL); section = secname_for_decl (current_function_decl); @@ -19006,10 +16093,36 @@ pop_decl_scope (void) VEC_pop (tree, decl_scope_table); } +/* walk_tree helper function for uses_local_type, below. */ + +static tree +uses_local_type_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + if (!TYPE_P (*tp)) + *walk_subtrees = 0; + else + { + tree name = TYPE_NAME (*tp); + if (name && DECL_P (name) && decl_function_context (name)) + return *tp; + } + return NULL_TREE; +} + +/* If TYPE involves a function-local type (including a local typedef to a + non-local type), returns that type; otherwise returns NULL_TREE. */ + +static tree +uses_local_type (tree type) +{ + tree used = walk_tree_without_duplicates (&type, uses_local_type_r, NULL); + return used; +} + /* Return the DIE for the scope that immediately contains this type. - Non-named types get global scope. Named types nested in other - types get their containing scope if it's open, or global scope - otherwise. All other types (i.e. function-local named types) get + Non-named types that do not involve a function-local type get global + scope. Named types nested in namespaces or other types get their + containing scope. All other types (i.e. function-local named types) get the current active scope. */ static dw_die_ref @@ -19017,18 +16130,24 @@ scope_die_for (tree t, dw_die_ref context_die) { dw_die_ref scope_die = NULL; tree containing_scope; - int i; /* Non-types always go in the current scope. */ gcc_assert (TYPE_P (t)); - containing_scope = TYPE_CONTEXT (t); + /* Use the scope of the typedef, rather than the scope of the type + it refers to. */ + if (TYPE_NAME (t) && DECL_P (TYPE_NAME (t))) + containing_scope = DECL_CONTEXT (TYPE_NAME (t)); + else + containing_scope = TYPE_CONTEXT (t); - /* Use the containing namespace if it was passed in (for a declaration). */ + /* Use the containing namespace if there is one. */ if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL) { if (context_die == lookup_decl_die (containing_scope)) /* OK */; + else if (debug_info_level > DINFO_LEVEL_TERSE) + context_die = get_context_die (containing_scope); else containing_scope = NULL_TREE; } @@ -19040,30 +16159,25 @@ scope_die_for (tree t, dw_die_ref context_die) containing_scope = NULL_TREE; if (SCOPE_FILE_SCOPE_P (containing_scope)) - scope_die = comp_unit_die (); + { + /* If T uses a local type keep it local as well, to avoid references + to function-local DIEs from outside the function. */ + if (current_function_decl && uses_local_type (t)) + scope_die = context_die; + else + scope_die = comp_unit_die (); + } else if (TYPE_P (containing_scope)) { - /* For types, we can just look up the appropriate DIE. But - first we check to see if we're in the middle of emitting it - so we know where the new DIE should go. */ - for (i = VEC_length (tree, decl_scope_table) - 1; i >= 0; --i) - if (VEC_index (tree, decl_scope_table, i) == containing_scope) - break; - - if (i < 0) + /* For types, we can just look up the appropriate DIE. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + scope_die = get_context_die (containing_scope); + else { - gcc_assert (debug_info_level <= DINFO_LEVEL_TERSE - || TREE_ASM_WRITTEN (containing_scope)); - /*We are not in the middle of emitting the type - CONTAINING_SCOPE. Let's see if it's emitted already. */ - scope_die = lookup_type_die (containing_scope); - - /* If none of the current dies are suitable, we get file scope. */ + scope_die = lookup_type_die_strip_naming_typedef (containing_scope); if (scope_die == NULL) scope_die = comp_unit_die (); } - else - scope_die = lookup_type_die_strip_naming_typedef (containing_scope); } else scope_die = context_die; @@ -19314,7 +16428,6 @@ gen_array_type_die (tree type, dw_die_ref context_die) array_die = new_die (DW_TAG_array_type, scope_die, type); add_name_attribute (array_die, type_tag (type)); - add_gnat_descriptive_type_attribute (array_die, type, context_die); equate_type_number_to_die (type, array_die); if (TREE_CODE (type) == VECTOR_TYPE) @@ -19374,6 +16487,10 @@ gen_array_type_die (tree type, dw_die_ref context_die) add_type_attribute (array_die, element_type, 0, 0, context_die); + add_gnat_descriptive_type_attribute (array_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (array_die, DW_AT_artificial, 1); + if (get_AT (array_die, DW_AT_name)) add_pubtype (type, array_die); } @@ -19617,7 +16734,6 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die) scope_die_for (type, context_die), type); equate_type_number_to_die (type, type_die); add_name_attribute (type_die, type_tag (type)); - add_gnat_descriptive_type_attribute (type_die, type, context_die); if (dwarf_version >= 4 || !dwarf_strict) { if (ENUM_IS_SCOPED (type)) @@ -19673,6 +16789,10 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die) add_AT_int (enum_die, DW_AT_const_value, tree_low_cst (value, tree_int_cst_sgn (value) > 0)); } + + add_gnat_descriptive_type_attribute (type_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (type_die, DW_AT_artificial, 1); } else add_AT_flag (type_die, DW_AT_declaration, 1); @@ -20270,7 +17390,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (!flag_reorder_blocks_and_partition) { - dw_fde_ref fde = &fde_table[current_funcdef_fde]; + dw_fde_ref fde = cfun->fde; if (fde->dw_fde_begin) { /* We have already generated the labels. */ @@ -20316,9 +17436,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) add_pubname (decl, subr_die); } else - { /* Generate pubnames entries for the split function code - ranges. */ - dw_fde_ref fde = &fde_table[current_funcdef_fde]; + { + /* Generate pubnames entries for the split function code ranges. */ + dw_fde_ref fde = cfun->fde; if (fde->dw_fde_second_begin) { @@ -20399,7 +17519,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) #ifdef MIPS_DEBUGGING_INFO /* Add a reference to the FDE for this routine. */ - add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde); + add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, cfun->fde->fde_index); #endif cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl); @@ -20570,7 +17690,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) { dw_loc_descr_ref reg, val; enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1)); - dw_die_ref cdie; + dw_die_ref cdie, tdie = NULL; next_arg = XEXP (arg, 1); if (REG_P (XEXP (XEXP (arg, 0), 0)) @@ -20601,6 +17721,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) tlocc = XEXP (XEXP (arg, 0), 1); continue; } + reg = NULL; if (REG_P (XEXP (XEXP (arg, 0), 0))) reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0), VAR_INIT_STATUS_INITIALIZED); @@ -20612,9 +17733,20 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) GET_MODE (mem), VAR_INIT_STATUS_INITIALIZED); } + else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) + == DEBUG_PARAMETER_REF) + { + tree tdecl + = DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0)); + tdie = lookup_decl_die (tdecl); + if (tdie == NULL) + continue; + } else continue; - if (reg == NULL) + if (reg == NULL + && GET_CODE (XEXP (XEXP (arg, 0), 0)) + != DEBUG_PARAMETER_REF) continue; val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode, VOIDmode, @@ -20624,8 +17756,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (die == NULL) die = gen_call_site_die (decl, subr_die, ca_loc); cdie = new_die (DW_TAG_GNU_call_site_parameter, die, - NULL_TREE); - add_AT_loc (cdie, DW_AT_location, reg); + NULL_TREE); + if (reg != NULL) + add_AT_loc (cdie, DW_AT_location, reg); + else if (tdie != NULL) + add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie); add_AT_loc (cdie, DW_AT_GNU_call_site_value, val); if (next_arg != XEXP (arg, 1)) { @@ -21007,6 +18142,14 @@ gen_label_die (tree decl, dw_die_ref context_die) ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn)); add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); } + else if (insn + && NOTE_P (insn) + && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL + && CODE_LABEL_NUMBER (insn) != -1) + { + ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn)); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + } } } @@ -21219,13 +18362,124 @@ gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die) add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); } +typedef const char *dchar_p; /* For DEF_VEC_P. */ +DEF_VEC_P(dchar_p); +DEF_VEC_ALLOC_P(dchar_p,heap); + +static char *producer_string; + +/* Return a heap allocated producer string including command line options + if -grecord-gcc-switches. */ + +static char * +gen_producer_string (void) +{ + size_t j; + VEC(dchar_p, heap) *switches = NULL; + const char *language_string = lang_hooks.name; + char *producer, *tail; + const char *p; + size_t len = dwarf_record_gcc_switches ? 0 : 3; + size_t plen = strlen (language_string) + 1 + strlen (version_string); + + for (j = 1; dwarf_record_gcc_switches && j < save_decoded_options_count; j++) + switch (save_decoded_options[j].opt_index) + { + case OPT_o: + case OPT_d: + case OPT_dumpbase: + case OPT_dumpdir: + case OPT_auxbase: + case OPT_auxbase_strip: + case OPT_quiet: + case OPT_version: + case OPT_v: + case OPT_w: + case OPT_L: + case OPT_D: + case OPT_I: + case OPT_U: + case OPT_SPECIAL_unknown: + case OPT_SPECIAL_ignore: + case OPT_SPECIAL_program_name: + case OPT_SPECIAL_input_file: + case OPT_grecord_gcc_switches: + case OPT_gno_record_gcc_switches: + case OPT__output_pch_: + case OPT_fdiagnostics_show_location_: + case OPT_fdiagnostics_show_option: + case OPT_fverbose_asm: + case OPT____: + case OPT__sysroot_: + case OPT_nostdinc: + case OPT_nostdinc__: + /* Ignore these. */ + continue; + default: + gcc_checking_assert (save_decoded_options[j].canonical_option[0][0] + == '-'); + switch (save_decoded_options[j].canonical_option[0][1]) + { + case 'M': + case 'i': + case 'W': + continue; + case 'f': + if (strncmp (save_decoded_options[j].canonical_option[0] + 2, + "dump", 4) == 0) + continue; + break; + default: + break; + } + VEC_safe_push (dchar_p, heap, switches, + save_decoded_options[j].orig_option_with_args_text); + len += strlen (save_decoded_options[j].orig_option_with_args_text) + 1; + break; + } + + producer = XNEWVEC (char, plen + 1 + len + 1); + tail = producer; + sprintf (tail, "%s %s", language_string, version_string); + tail += plen; + + if (!dwarf_record_gcc_switches) + { +#ifdef MIPS_DEBUGGING_INFO + /* The MIPS/SGI compilers place the 'cc' command line options in the + producer string. The SGI debugger looks for -g, -g1, -g2, or -g3; + if they do not appear in the producer string, the debugger reaches + the conclusion that the object file is stripped and has no debugging + information. To get the MIPS/SGI debugger to believe that there is + debugging information in the object file, we add a -g to the producer + string. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + { + memcpy (tail, " -g", 3); + tail += 3; + } +#endif + } + + FOR_EACH_VEC_ELT (dchar_p, switches, j, p) + { + len = strlen (p); + *tail = ' '; + memcpy (tail + 1, p, len); + tail += len + 1; + } + + *tail = '\0'; + VEC_free (dchar_p, heap, switches); + return producer; +} + /* Generate the DIE for the compilation unit. */ static dw_die_ref gen_compile_unit_die (const char *filename) { dw_die_ref die; - char producer[250]; const char *language_string = lang_hooks.name; int language; @@ -21239,20 +18493,9 @@ gen_compile_unit_die (const char *filename) add_comp_dir_attribute (die); } - sprintf (producer, "%s %s", language_string, version_string); - -#ifdef MIPS_DEBUGGING_INFO - /* The MIPS/SGI compilers place the 'cc' command line options in the producer - string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do - not appear in the producer string, the debugger reaches the conclusion - that the object file is stripped and has no debugging information. - To get the MIPS/SGI debugger to believe that there is debugging - information in the object file, we add a -g to the producer string. */ - if (debug_info_level > DINFO_LEVEL_TERSE) - strcat (producer, " -g"); -#endif - - add_AT_string (die, DW_AT_producer, producer); + if (producer_string == NULL) + producer_string = gen_producer_string (); + add_AT_string (die, DW_AT_producer, producer_string); /* If our producer is LTO try to figure out a common language to use from the global list of translation units. */ @@ -21305,6 +18548,11 @@ gen_compile_unit_die (const char *filename) language = DW_LANG_ObjC; else if (strcmp (language_string, "GNU Objective-C++") == 0) language = DW_LANG_ObjC_plus_plus; + else if (dwarf_version >= 5 || !dwarf_strict) + { + if (strcmp (language_string, "GNU Go") == 0) + language = DW_LANG_Go; + } } add_AT_unsigned (die, DW_AT_language, language); @@ -21457,10 +18705,7 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, if (old_die) add_AT_specification (type_die, old_die); else - { - add_name_attribute (type_die, type_tag (type)); - add_gnat_descriptive_type_attribute (type_die, type, context_die); - } + add_name_attribute (type_die, type_tag (type)); } else remove_AT (type_die, DW_AT_declaration); @@ -21493,6 +18738,10 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, gen_member_die (type, type_die); pop_decl_scope (); + add_gnat_descriptive_type_attribute (type_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (type_die, DW_AT_artificial, 1); + /* GNU extension: Record what type our vtable lives in. */ if (TYPE_VFIELD (type)) { @@ -21717,11 +18966,8 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, /* Prevent broken recursion; we can't hand off to the same type. */ gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type); - /* Use the DIE of the containing namespace as the parent DIE of - the type description DIE we want to generate. */ - if (DECL_CONTEXT (TYPE_NAME (type)) - && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL) - context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type))); + /* Give typedefs the right scope. */ + context_die = scope_die_for (type, context_die); TREE_ASM_WRITTEN (type) = 1; @@ -22686,7 +19932,9 @@ dwarf2out_decl (tree decl) return; /* For local statics lookup proper context die. */ - if (TREE_STATIC (decl) && decl_function_context (decl)) + if (TREE_STATIC (decl) + && DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) context_die = lookup_decl_die (DECL_CONTEXT (decl)); /* If we are in terse mode, don't generate any DIEs to represent any @@ -23014,10 +20262,11 @@ dwarf2out_var_location (rtx loc_note) { char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2]; struct var_loc_node *newloc; - rtx next_real; + rtx next_real, next_note; static const char *last_label; static const char *last_postcall_label; static bool last_in_cold_section_p; + static rtx expected_next_loc_note; tree decl; bool var_loc_p; @@ -23036,7 +20285,35 @@ dwarf2out_var_location (rtx loc_note) if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note))) return; - next_real = next_real_insn (loc_note); + /* Optimize processing a large consecutive sequence of location + notes so we don't spend too much time in next_real_insn. If the + next insn is another location note, remember the next_real_insn + calculation for next time. */ + next_real = cached_next_real_insn; + if (next_real) + { + if (expected_next_loc_note != loc_note) + next_real = NULL_RTX; + } + + next_note = NEXT_INSN (loc_note); + if (! next_note + || INSN_DELETED_P (next_note) + || GET_CODE (next_note) != NOTE + || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION + && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION)) + next_note = NULL_RTX; + + if (! next_real) + next_real = next_real_insn (loc_note); + + if (next_note) + { + expected_next_loc_note = next_note; + cached_next_real_insn = next_real; + } + else + cached_next_real_insn = NULL_RTX; /* If there are no instructions which would be affected by this note, don't do anything. */ @@ -23219,6 +20496,10 @@ set_cur_line_info_table (section *sec) VEC_safe_push (dw_line_info_table_p, gc, separate_line_info, table); } + if (DWARF2_ASM_LINE_DEBUG_INFO) + table->is_stmt = (cur_line_info_table + ? cur_line_info_table->is_stmt + : DWARF_LINE_DEFAULT_IS_STMT_START); cur_line_info_table = table; } @@ -23316,12 +20597,27 @@ dwarf2out_source_line (unsigned int line, const char *filename, if (DWARF2_ASM_LINE_DEBUG_INFO) { /* Emit the .loc directive understood by GNU as. */ - fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line); + /* "\t.loc %u %u 0 is_stmt %u discriminator %u", + file_num, line, is_stmt, discriminator */ + fputs ("\t.loc ", asm_out_file); + fprint_ul (asm_out_file, file_num); + putc (' ', asm_out_file); + fprint_ul (asm_out_file, line); + putc (' ', asm_out_file); + putc ('0', asm_out_file); + if (is_stmt != table->is_stmt) - fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0); + { + fputs (" is_stmt ", asm_out_file); + putc (is_stmt ? '1' : '0', asm_out_file); + } if (SUPPORTS_DISCRIMINATOR && discriminator != 0) - fprintf (asm_out_file, " discriminator %d", discriminator); - fputc ('\n', asm_out_file); + { + gcc_assert (discriminator > 0); + fputs (" discriminator ", asm_out_file); + fprint_ul (asm_out_file, (unsigned long) discriminator); + } + putc ('\n', asm_out_file); } else { @@ -23365,7 +20661,7 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename) macinfo_entry e; e.code = DW_MACINFO_start_file; e.lineno = lineno; - e.info = xstrdup (filename); + e.info = ggc_strdup (filename); VEC_safe_push (macinfo_entry, gc, macinfo_table, &e); } } @@ -23400,9 +20696,18 @@ dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED, if (debug_info_level >= DINFO_LEVEL_VERBOSE) { macinfo_entry e; + /* Insert a dummy first entry to be able to optimize the whole + predefined macro block using DW_MACRO_GNU_transparent_include. */ + if (VEC_empty (macinfo_entry, macinfo_table) && lineno <= 1) + { + e.code = 0; + e.lineno = 0; + e.info = NULL; + VEC_safe_push (macinfo_entry, gc, macinfo_table, &e); + } e.code = DW_MACINFO_define; e.lineno = lineno; - e.info = xstrdup (buffer);; + e.info = ggc_strdup (buffer); VEC_safe_push (macinfo_entry, gc, macinfo_table, &e); } } @@ -23418,58 +20723,376 @@ dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED, if (debug_info_level >= DINFO_LEVEL_VERBOSE) { macinfo_entry e; + /* Insert a dummy first entry to be able to optimize the whole + predefined macro block using DW_MACRO_GNU_transparent_include. */ + if (VEC_empty (macinfo_entry, macinfo_table) && lineno <= 1) + { + e.code = 0; + e.lineno = 0; + e.info = NULL; + VEC_safe_push (macinfo_entry, gc, macinfo_table, &e); + } e.code = DW_MACINFO_undef; e.lineno = lineno; - e.info = xstrdup (buffer);; + e.info = ggc_strdup (buffer); VEC_safe_push (macinfo_entry, gc, macinfo_table, &e); } } +/* Routines to manipulate hash table of CUs. */ + +static hashval_t +htab_macinfo_hash (const void *of) +{ + const macinfo_entry *const entry = + (const macinfo_entry *) of; + + return htab_hash_string (entry->info); +} + +static int +htab_macinfo_eq (const void *of1, const void *of2) +{ + const macinfo_entry *const entry1 = (const macinfo_entry *) of1; + const macinfo_entry *const entry2 = (const macinfo_entry *) of2; + + return !strcmp (entry1->info, entry2->info); +} + +/* Output a single .debug_macinfo entry. */ + +static void +output_macinfo_op (macinfo_entry *ref) +{ + int file_num; + size_t len; + struct indirect_string_node *node; + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + struct dwarf_file_data *fd; + + switch (ref->code) + { + case DW_MACINFO_start_file: + fd = lookup_filename (ref->info); + file_num = maybe_emit_file (fd); + dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file"); + dw2_asm_output_data_uleb128 (ref->lineno, + "Included from line number %lu", + (unsigned long) ref->lineno); + dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info); + break; + case DW_MACINFO_end_file: + dw2_asm_output_data (1, DW_MACINFO_end_file, "End file"); + break; + case DW_MACINFO_define: + case DW_MACINFO_undef: + len = strlen (ref->info) + 1; + if (!dwarf_strict + && len > DWARF_OFFSET_SIZE + && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET + && (debug_str_section->common.flags & SECTION_MERGE) != 0) + { + ref->code = ref->code == DW_MACINFO_define + ? DW_MACRO_GNU_define_indirect + : DW_MACRO_GNU_undef_indirect; + output_macinfo_op (ref); + return; + } + dw2_asm_output_data (1, ref->code, + ref->code == DW_MACINFO_define + ? "Define macro" : "Undefine macro"); + dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", + (unsigned long) ref->lineno); + dw2_asm_output_nstring (ref->info, -1, "The macro"); + break; + case DW_MACRO_GNU_define_indirect: + case DW_MACRO_GNU_undef_indirect: + node = find_AT_string (ref->info); + if (node->form != DW_FORM_strp) + { + char label[32]; + ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); + ++dw2_string_counter; + node->label = xstrdup (label); + node->form = DW_FORM_strp; + } + dw2_asm_output_data (1, ref->code, + ref->code == DW_MACRO_GNU_define_indirect + ? "Define macro indirect" + : "Undefine macro indirect"); + dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", + (unsigned long) ref->lineno); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_str_section, "The macro: \"%s\"", + ref->info); + break; + case DW_MACRO_GNU_transparent_include: + dw2_asm_output_data (1, ref->code, "Transparent include"); + ASM_GENERATE_INTERNAL_LABEL (label, + DEBUG_MACRO_SECTION_LABEL, ref->lineno); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL); + break; + default: + fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n", + ASM_COMMENT_START, (unsigned long) ref->code); + break; + } +} + +/* Attempt to make a sequence of define/undef macinfo ops shareable with + other compilation unit .debug_macinfo sections. IDX is the first + index of a define/undef, return the number of ops that should be + emitted in a comdat .debug_macinfo section and emit + a DW_MACRO_GNU_transparent_include entry referencing it. + If the define/undef entry should be emitted normally, return 0. */ + +static unsigned +optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files, + htab_t *macinfo_htab) +{ + macinfo_entry *first, *second, *cur, *inc; + char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1]; + unsigned char checksum[16]; + struct md5_ctx ctx; + char *grp_name, *tail; + const char *base; + unsigned int i, count, encoded_filename_len, linebuf_len; + void **slot; + + first = VEC_index (macinfo_entry, macinfo_table, idx); + second = VEC_index (macinfo_entry, macinfo_table, idx + 1); + + /* Optimize only if there are at least two consecutive define/undef ops, + and either all of them are before first DW_MACINFO_start_file + with lineno {0,1} (i.e. predefined macro block), or all of them are + in some included header file. */ + if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef) + return 0; + if (VEC_empty (macinfo_entry, files)) + { + if (first->lineno > 1 || second->lineno > 1) + return 0; + } + else if (first->lineno == 0) + return 0; + + /* Find the last define/undef entry that can be grouped together + with first and at the same time compute md5 checksum of their + codes, linenumbers and strings. */ + md5_init_ctx (&ctx); + for (i = idx; VEC_iterate (macinfo_entry, macinfo_table, i, cur); i++) + if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef) + break; + else if (VEC_empty (macinfo_entry, files) && cur->lineno > 1) + break; + else + { + unsigned char code = cur->code; + md5_process_bytes (&code, 1, &ctx); + checksum_uleb128 (cur->lineno, &ctx); + md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx); + } + md5_finish_ctx (&ctx, checksum); + count = i - idx; + + /* From the containing include filename (if any) pick up just + usable characters from its basename. */ + if (VEC_empty (macinfo_entry, files)) + base = ""; + else + base = lbasename (VEC_last (macinfo_entry, files)->info); + for (encoded_filename_len = 0, i = 0; base[i]; i++) + if (ISIDNUM (base[i]) || base[i] == '.') + encoded_filename_len++; + /* Count . at the end. */ + if (encoded_filename_len) + encoded_filename_len++; + + sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno); + linebuf_len = strlen (linebuf); + + /* The group name format is: wmN.[.]. */ + grp_name = XALLOCAVEC (char, 4 + encoded_filename_len + linebuf_len + 1 + + 16 * 2 + 1); + memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4); + tail = grp_name + 4; + if (encoded_filename_len) + { + for (i = 0; base[i]; i++) + if (ISIDNUM (base[i]) || base[i] == '.') + *tail++ = base[i]; + *tail++ = '.'; + } + memcpy (tail, linebuf, linebuf_len); + tail += linebuf_len; + *tail++ = '.'; + for (i = 0; i < 16; i++) + sprintf (tail + i * 2, "%02x", checksum[i] & 0xff); + + /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include + in the empty vector entry before the first define/undef. */ + inc = VEC_index (macinfo_entry, macinfo_table, idx - 1); + inc->code = DW_MACRO_GNU_transparent_include; + inc->lineno = 0; + inc->info = ggc_strdup (grp_name); + if (*macinfo_htab == NULL) + *macinfo_htab = htab_create (10, htab_macinfo_hash, htab_macinfo_eq, NULL); + /* Avoid emitting duplicates. */ + slot = htab_find_slot (*macinfo_htab, inc, INSERT); + if (*slot != NULL) + { + inc->code = 0; + inc->info = NULL; + /* If such an entry has been used before, just emit + a DW_MACRO_GNU_transparent_include op. */ + inc = (macinfo_entry *) *slot; + output_macinfo_op (inc); + /* And clear all macinfo_entry in the range to avoid emitting them + in the second pass. */ + for (i = idx; + VEC_iterate (macinfo_entry, macinfo_table, i, cur) + && i < idx + count; + i++) + { + cur->code = 0; + cur->info = NULL; + } + } + else + { + *slot = inc; + inc->lineno = htab_elements (*macinfo_htab); + output_macinfo_op (inc); + } + return count; +} + +/* Output macinfo section(s). */ + static void output_macinfo (void) { unsigned i; unsigned long length = VEC_length (macinfo_entry, macinfo_table); macinfo_entry *ref; + VEC (macinfo_entry, gc) *files = NULL; + htab_t macinfo_htab = NULL; if (! length) return; + /* output_macinfo* uses these interchangeably. */ + gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define + && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef + && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file + && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file); + + /* For .debug_macro emit the section header. */ + if (!dwarf_strict) + { + dw2_asm_output_data (2, 4, "DWARF macro version number"); + if (DWARF_OFFSET_SIZE == 8) + dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present"); + else + dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_section_label, + debug_line_section, NULL); + } + + /* In the first loop, it emits the primary .debug_macinfo section + and after each emitted op the macinfo_entry is cleared. + If a longer range of define/undef ops can be optimized using + DW_MACRO_GNU_transparent_include, the + DW_MACRO_GNU_transparent_include op is emitted and kept in + the vector before the first define/undef in the range and the + whole range of define/undef ops is not emitted and kept. */ for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++) { switch (ref->code) { - case DW_MACINFO_start_file: + case DW_MACINFO_start_file: + VEC_safe_push (macinfo_entry, gc, files, ref); + break; + case DW_MACINFO_end_file: + if (!VEC_empty (macinfo_entry, files)) + VEC_pop (macinfo_entry, files); + break; + case DW_MACINFO_define: + case DW_MACINFO_undef: + if (!dwarf_strict + && HAVE_COMDAT_GROUP + && VEC_length (macinfo_entry, files) != 1 + && i > 0 + && i + 1 < length + && VEC_index (macinfo_entry, macinfo_table, i - 1)->code == 0) { - int file_num = maybe_emit_file (lookup_filename (ref->info)); - dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file"); - dw2_asm_output_data_uleb128 - (ref->lineno, "Included from line number %lu", - (unsigned long)ref->lineno); - dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info); + unsigned count = optimize_macinfo_range (i, files, &macinfo_htab); + if (count) + { + i += count - 1; + continue; + } } - break; - case DW_MACINFO_end_file: - dw2_asm_output_data (1, DW_MACINFO_end_file, "End file"); - break; - case DW_MACINFO_define: - dw2_asm_output_data (1, DW_MACINFO_define, "Define macro"); - dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", - (unsigned long)ref->lineno); - dw2_asm_output_nstring (ref->info, -1, "The macro"); - break; - case DW_MACINFO_undef: - dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro"); - dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", - (unsigned long)ref->lineno); - dw2_asm_output_nstring (ref->info, -1, "The macro"); - break; - default: - fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n", - ASM_COMMENT_START, (unsigned long)ref->code); + break; + case 0: + /* A dummy entry may be inserted at the beginning to be able + to optimize the whole block of predefined macros. */ + if (i == 0) + continue; + default: break; } + output_macinfo_op (ref); + ref->info = NULL; + ref->code = 0; } + + if (macinfo_htab == NULL) + return; + + htab_delete (macinfo_htab); + + /* If any DW_MACRO_GNU_transparent_include were used, on those + DW_MACRO_GNU_transparent_include entries terminate the + current chain and switch to a new comdat .debug_macinfo + section and emit the define/undef entries within it. */ + for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++) + switch (ref->code) + { + case 0: + continue; + case DW_MACRO_GNU_transparent_include: + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + tree comdat_key = get_identifier (ref->info); + /* Terminate the previous .debug_macinfo section. */ + dw2_asm_output_data (1, 0, "End compilation unit"); + targetm.asm_out.named_section (DEBUG_MACRO_SECTION, + SECTION_DEBUG + | SECTION_LINKONCE, + comdat_key); + ASM_GENERATE_INTERNAL_LABEL (label, + DEBUG_MACRO_SECTION_LABEL, + ref->lineno); + ASM_OUTPUT_LABEL (asm_out_file, label); + ref->code = 0; + ref->info = NULL; + dw2_asm_output_data (2, 4, "DWARF macro version number"); + if (DWARF_OFFSET_SIZE == 8) + dw2_asm_output_data (1, 1, "Flags: 64-bit"); + else + dw2_asm_output_data (1, 0, "Flags: 32-bit"); + } + break; + case DW_MACINFO_define: + case DW_MACINFO_undef: + output_macinfo_op (ref); + ref->code = 0; + ref->info = NULL; + break; + default: + gcc_unreachable (); + } } /* Set up for Dwarf output at the start of compilation. */ @@ -23518,7 +21141,9 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) SECTION_DEBUG, NULL); debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, SECTION_DEBUG, NULL); - debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION, + debug_macinfo_section = get_section (dwarf_strict + ? DEBUG_MACINFO_SECTION + : DEBUG_MACRO_SECTION, SECTION_DEBUG, NULL); debug_line_section = get_section (DEBUG_LINE_SECTION, SECTION_DEBUG, NULL); @@ -23550,7 +21175,9 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, DEBUG_RANGES_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label, - DEBUG_MACINFO_SECTION_LABEL, 0); + dwarf_strict + ? DEBUG_MACINFO_SECTION_LABEL + : DEBUG_MACRO_SECTION_LABEL, 0); if (debug_info_level >= DINFO_LEVEL_VERBOSE) macinfo_table = VEC_alloc (macinfo_entry, gc, 64); @@ -24041,9 +21668,12 @@ mark_base_types (dw_loc_descr_ref loc) case DW_OP_GNU_deref_type: base_type = loc->dw_loc_oprnd2.v.val_die_ref.die; break; - case DW_OP_GNU_const_type: case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: + if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const) + continue; + /* FALLTHRU */ + case DW_OP_GNU_const_type: base_type = loc->dw_loc_oprnd1.v.val_die_ref.die; break; case DW_OP_GNU_entry_value: @@ -24201,12 +21831,26 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL)) return false; break; + case DW_OP_plus_uconst: + if (size_of_loc_descr (loc) + > size_of_int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned) + + 1 + && loc->dw_loc_oprnd1.v.val_unsigned > 0) + { + dw_loc_descr_ref repl + = int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned); + add_loc_descr (&repl, new_loc_descr (DW_OP_plus, 0, 0)); + add_loc_descr (&repl, loc->dw_loc_next); + *loc = *repl; + } + break; case DW_OP_implicit_value: if (loc->dw_loc_oprnd2.val_class == dw_val_class_addr && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)) return false; break; case DW_OP_GNU_implicit_pointer: + case DW_OP_GNU_parameter_ref: if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref) { dw_die_ref ref @@ -24231,8 +21875,14 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) if (loc->dw_loc_opc == DW_OP_GNU_regval_type || loc->dw_loc_opc == DW_OP_GNU_deref_type) base1 = loc->dw_loc_oprnd2.v.val_die_ref.die; + else if (loc->dw_loc_oprnd1.val_class + == dw_val_class_unsigned_const) + break; else base1 = loc->dw_loc_oprnd1.v.val_die_ref.die; + if (loc->dw_loc_next->dw_loc_oprnd1.val_class + == dw_val_class_unsigned_const) + break; base2 = loc->dw_loc_next->dw_loc_oprnd1.v.val_die_ref.die; gcc_assert (base1->die_tag == DW_TAG_base_type && base2->die_tag == DW_TAG_base_type); @@ -24259,7 +21909,7 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) /* Don't change integer DW_OP_GNU_convert after e.g. floating point typed stack entry. */ else if (enc1 != DW_ATE_unsigned && enc1 != DW_ATE_signed) - keep = loc; + keep = loc->dw_loc_next; break; } break; @@ -24337,13 +21987,26 @@ resolve_addr (dw_die_ref die) } break; case dw_val_class_loc: - if (!resolve_addr_in_expr (AT_loc (a))) - { - remove_AT (die, a->dw_attr); - ix--; - } - else - mark_base_types (AT_loc (a)); + { + dw_loc_descr_ref l = AT_loc (a); + /* For -gdwarf-2 don't attempt to optimize + DW_AT_data_member_location containing + DW_OP_plus_uconst - older consumers might + rely on it being that op instead of a more complex, + but shorter, location description. */ + if ((dwarf_version > 2 + || a->dw_attr != DW_AT_data_member_location + || l == NULL + || l->dw_loc_opc != DW_OP_plus_uconst + || l->dw_loc_next != NULL) + && !resolve_addr_in_expr (l)) + { + remove_AT (die, a->dw_attr); + ix--; + } + else + mark_base_types (l); + } break; case dw_val_class_addr: if (a->dw_attr == DW_AT_const_value @@ -24525,6 +22188,12 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash) break; case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: + if (val1->val_class == dw_val_class_unsigned_const) + { + hash = iterative_hash_object (val1->v.val_unsigned, hash); + break; + } + /* FALLTHRU */ case DW_OP_GNU_const_type: { unsigned int byte_size @@ -24746,7 +22415,15 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y) && valx2->v.val_die_ref.die == valy2->v.val_die_ref.die; case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: + if (valx1->val_class != valy1->val_class) + return false; + if (valx1->val_class == dw_val_class_unsigned_const) + return valx1->v.val_unsigned == valy1->v.val_unsigned; return valx1->v.val_die_ref.die == valy1->v.val_die_ref.die; + case DW_OP_GNU_parameter_ref: + return valx1->val_class == dw_val_class_die_ref + && valx1->val_class == valy1->val_class + && valx1->v.val_die_ref.die == valy1->v.val_die_ref.die; default: /* Other codes have no operands. */ return true; @@ -24846,13 +22523,22 @@ dwarf2out_finish (const char *filename) htab_t comdat_type_table; unsigned int i; + /* PCH might result in DW_AT_producer string being restored from the + header compilation, fix it up if needed. */ + dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer); + if (strcmp (AT_string (producer), producer_string) != 0) + { + struct indirect_string_node *node = find_AT_string (producer_string); + producer->dw_attr_val.v.val_str = node; + } + gen_scheduled_generic_parms_dies (); gen_remaining_tmpl_value_param_die_attribute (); /* Add the name for the main input file now. We delayed this from dwarf2out_init to avoid complications with PCH. */ add_name_attribute (comp_unit_die (), remap_debug_filename (filename)); - if (!IS_ABSOLUTE_PATH (filename)) + if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir) add_comp_dir_attribute (comp_unit_die ()); else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL) { @@ -24885,7 +22571,7 @@ dwarf2out_finish (const char *filename) { dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin); - if (origin) + if (origin && origin->die_parent) add_child_die (origin->die_parent, die); else if (is_cu_die (die)) ; @@ -24904,24 +22590,16 @@ dwarf2out_finish (const char *filename) inlined and optimized out. In that case we are lost and assign the empty child. This should not be big issue as the function is likely unreachable too. */ - tree context = NULL_TREE; - gcc_assert (node->created_for); if (DECL_P (node->created_for)) - context = DECL_CONTEXT (node->created_for); + origin = get_context_die (DECL_CONTEXT (node->created_for)); else if (TYPE_P (node->created_for)) - context = TYPE_CONTEXT (node->created_for); - - gcc_assert (context - && (TREE_CODE (context) == FUNCTION_DECL - || TREE_CODE (context) == NAMESPACE_DECL)); - - origin = lookup_decl_die (context); - if (origin) - add_child_die (origin, die); + origin = scope_die_for (node->created_for, comp_unit_die ()); else - add_child_die (comp_unit_die (), die); + origin = comp_unit_die (); + + add_child_die (origin, die); } } } @@ -24940,7 +22618,11 @@ dwarf2out_finish (const char *filename) for (node = deferred_asm_name; node; node = node->next) { tree decl = node->created_for; - if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) + /* When generating LTO bytecode we can not generate new assembler + names at this point and all important decls got theirs via + free-lang-data. */ + if ((!flag_generate_lto || DECL_ASSEMBLER_NAME_SET_P (decl)) + && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) { add_linkage_attr (node->die, decl); move_linkage_attr (node->die); @@ -25015,7 +22697,8 @@ dwarf2out_finish (const char *filename) } else { - unsigned fde_idx = 0; + unsigned fde_idx; + dw_fde_ref fde; bool range_list_added = false; if (text_section_used) @@ -25025,10 +22708,8 @@ dwarf2out_finish (const char *filename) add_ranges_by_labels (comp_unit_die (), cold_text_section_label, cold_end_label, &range_list_added); - for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++) + FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde) { - dw_fde_ref fde = &fde_table[fde_idx]; - if (!fde->in_std_section) add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin, fde->dw_fde_end, &range_list_added); @@ -25056,8 +22737,10 @@ dwarf2out_finish (const char *filename) add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list, debug_line_section_label); - if (debug_info_level >= DINFO_LEVEL_VERBOSE) - add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label); + if (have_macinfo) + add_AT_macptr (comp_unit_die (), + dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros, + macinfo_section_label); if (have_location_lists) optimize_location_lists (comp_unit_die ()); @@ -25089,13 +22772,16 @@ dwarf2out_finish (const char *filename) htab_delete (comdat_type_table); /* Output the main compilation unit if non-empty or if .debug_macinfo - will be emitted. */ - output_comp_unit (comp_unit_die (), debug_info_level >= DINFO_LEVEL_VERBOSE); + or .debug_macro will be emitted. */ + output_comp_unit (comp_unit_die (), have_macinfo); /* Output the abbreviation table. */ - switch_to_section (debug_abbrev_section); - ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label); - output_abbrev_section (); + if (abbrev_die_table_in_use != 1) + { + switch_to_section (debug_abbrev_section); + ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label); + output_abbrev_section (); + } /* Output location list section if necessary. */ if (have_location_lists) @@ -25166,6 +22852,15 @@ dwarf2out_finish (const char *filename) output_ranges (); } + /* Have to end the macro section. */ + if (have_macinfo) + { + switch_to_section (debug_macinfo_section); + ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label); + output_macinfo (); + dw2_asm_output_data (1, 0, "End compilation unit"); + } + /* Output the source line correspondence table. We must do this even if there is no line information. Otherwise, on an empty translation unit, we will generate a present, but empty, @@ -25177,16 +22872,6 @@ dwarf2out_finish (const char *filename) if (! DWARF2_ASM_LINE_DEBUG_INFO) output_line_info (); - /* Have to end the macro section. */ - if (debug_info_level >= DINFO_LEVEL_VERBOSE) - { - switch_to_section (debug_macinfo_section); - ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label); - if (!VEC_empty (macinfo_entry, macinfo_table)) - output_macinfo (); - dw2_asm_output_data (1, 0, "End compilation unit"); - } - /* If we emitted any DW_FORM_strp form attribute, output the string table too. */ if (debug_str_hash)