diff options
author | Richard Henderson <rth@redhat.com> | 2011-07-23 13:17:54 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2011-07-23 13:17:54 -0700 |
commit | 57e16c9625e094c687dbf8eef226905b48b26541 (patch) | |
tree | b4bce59406cfba4cec2473ceaacbd2e3ea2d99fb | |
parent | f1a0e8300d7ee346adb69555ec4c930c89fb3997 (diff) | |
download | gcc-57e16c9625e094c687dbf8eef226905b48b26541.zip gcc-57e16c9625e094c687dbf8eef226905b48b26541.tar.gz gcc-57e16c9625e094c687dbf8eef226905b48b26541.tar.bz2 |
dwarf2cfi: Implement change_cfi_row.
Add a generic function to adjust cfi state from one row to another.
Use this to implement text section switching. This will also be
usable for arbitrary changes around a cfg for shrink-wrapping.
* dwarf2cfi.c (add_cfi_args_size): Split out from...
(dwarf2out_args_size): ... here.
(add_cfi_restore): Split out from ...
(dwarf2out_frame_debug_cfa_restore): ... here.
(def_cfa_0): Split out from ...
(def_cfa_1): ... here.
(cfi_oprnd_equal_p, cfi_equal_p): New.
(change_cfi_row): New.
(add_cfis_to_fde): Set fde->dw_fde_switch_cfi_index.
(create_cfi_notes): Use change_cfi_row at SWITCH_TEXT note.
(output_cfis): Remove.
* dwarf2out.c (output_fde): Simplify output_cfi loop.
(dwarf2out_switch_text_section): Don't call output_cfis.
(dw_val_equal_p, loc_descr_equal_p_1, loc_descr_equal_p): New.
* dwarf2out.h: Update decls.
(enum dw_val_class): Add dw_val_class_none.
From-SVN: r176700
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/dwarf2cfi.c | 376 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 159 | ||||
-rw-r--r-- | gcc/dwarf2out.h | 3 |
4 files changed, 309 insertions, 248 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6277b1e..89fc46a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,24 @@ 2011-07-23 Richard Henderson <rth@redhat.com> + * dwarf2cfi.c (add_cfi_args_size): Split out from... + (dwarf2out_args_size): ... here. + (add_cfi_restore): Split out from ... + (dwarf2out_frame_debug_cfa_restore): ... here. + (def_cfa_0): Split out from ... + (def_cfa_1): ... here. + (cfi_oprnd_equal_p, cfi_equal_p): New. + (change_cfi_row): New. + (add_cfis_to_fde): Set fde->dw_fde_switch_cfi_index. + (create_cfi_notes): Use change_cfi_row at SWITCH_TEXT note. + (output_cfis): Remove. + * dwarf2out.c (output_fde): Simplify output_cfi loop. + (dwarf2out_switch_text_section): Don't call output_cfis. + (dw_val_equal_p, loc_descr_equal_p_1, loc_descr_equal_p): New. + * dwarf2out.h: Update decls. + (enum dw_val_class): Add dw_val_class_none. + +2011-07-23 Richard Henderson <rth@redhat.com> + * dwarf2cfi.c (update_row_reg_save): New. (dwarf2out_frame_debug_cfa_expression): Use it. (dwarf2out_frame_debug_cfa_restore): Likewise. diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c index 36fa7f8..745e137 100644 --- a/gcc/dwarf2cfi.c +++ b/gcc/dwarf2cfi.c @@ -285,6 +285,28 @@ add_cfi (dw_cfi_ref cfi) VEC_safe_push (dw_cfi_ref, gc, *add_cfi_vec, cfi); } +static void +add_cfi_args_size (HOST_WIDE_INT size) +{ + dw_cfi_ref cfi = new_cfi (); + + cfi->dw_cfi_opc = DW_CFA_GNU_args_size; + cfi->dw_cfi_oprnd1.dw_cfi_offset = size; + + add_cfi (cfi); +} + +static void +add_cfi_restore (unsigned reg) +{ + dw_cfi_ref cfi = new_cfi (); + + cfi->dw_cfi_opc = (reg & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore); + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + + add_cfi (cfi); +} + /* Perform ROW->REG_SAVE[COLUMN] = CFI. CFI may be null, indicating that the register column is no longer saved. */ @@ -474,64 +496,109 @@ cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2) || loc1->base_offset == loc2->base_offset)); } -/* This routine does the actual work. The CFA is now calculated from - the dw_cfa_location structure. */ +/* Determine if two CFI operands are identical. */ -static void -def_cfa_1 (dw_cfa_location *loc_p) +static bool +cfi_oprnd_equal_p (enum dw_cfi_oprnd_type t, dw_cfi_oprnd *a, dw_cfi_oprnd *b) { - dw_cfi_ref cfi; - dw_cfa_location loc = *loc_p; + switch (t) + { + case dw_cfi_oprnd_unused: + return true; + case dw_cfi_oprnd_reg_num: + return a->dw_cfi_reg_num == b->dw_cfi_reg_num; + case dw_cfi_oprnd_offset: + return a->dw_cfi_offset == b->dw_cfi_offset; + case dw_cfi_oprnd_addr: + return (a->dw_cfi_addr == b->dw_cfi_addr + || strcmp (a->dw_cfi_addr, b->dw_cfi_addr) == 0); + case dw_cfi_oprnd_loc: + return loc_descr_equal_p (a->dw_cfi_loc, b->dw_cfi_loc); + } + gcc_unreachable (); +} - if (cfa_store.reg == loc.reg && loc.indirect == 0) - cfa_store.offset = loc.offset; +/* Determine if two CFI entries are identical. */ + +static bool +cfi_equal_p (dw_cfi_ref a, dw_cfi_ref b) +{ + enum dwarf_call_frame_info opc; + + /* Make things easier for our callers, including missing operands. */ + if (a == b) + return true; + if (a == NULL || b == NULL) + return false; + + /* Obviously, the opcodes must match. */ + opc = a->dw_cfi_opc; + if (opc != b->dw_cfi_opc) + return false; + + /* Compare the two operands, re-using the type of the operands as + already exposed elsewhere. */ + return (cfi_oprnd_equal_p (dw_cfi_oprnd1_desc (opc), + &a->dw_cfi_oprnd1, &b->dw_cfi_oprnd1) + && cfi_oprnd_equal_p (dw_cfi_oprnd2_desc (opc), + &a->dw_cfi_oprnd2, &b->dw_cfi_oprnd2)); +} + +/* The CFA is now calculated from NEW_CFA. Consider OLD_CFA in determining + what opcode to emit. Returns the CFI opcode to effect the change, or + NULL if NEW_CFA == OLD_CFA. */ + +static dw_cfi_ref +def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa) +{ + dw_cfi_ref cfi; /* If nothing changed, no need to issue any call frame instructions. */ - if (cfa_equal_p (&loc, &cur_row->cfa)) - return; + if (cfa_equal_p (old_cfa, new_cfa)) + return NULL; cfi = new_cfi (); - if (loc.reg == cur_row->cfa.reg && !loc.indirect && !cur_row->cfa.indirect) + if (new_cfa->reg == old_cfa->reg && !new_cfa->indirect && !old_cfa->indirect) { /* Construct a "DW_CFA_def_cfa_offset <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) + if (new_cfa->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; + cfi->dw_cfi_oprnd1.dw_cfi_offset = new_cfa->offset; } #ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ - else if (loc.offset == cur_row->cfa.offset - && cur_row->cfa.reg != INVALID_REGNUM - && !loc.indirect - && !cur_row->cfa.indirect) + else if (new_cfa->offset == old_cfa->offset + && old_cfa->reg != INVALID_REGNUM + && !new_cfa->indirect + && !old_cfa->indirect) { /* Construct a "DW_CFA_def_cfa_register <register>" instruction, indicating the CFA register has changed to <register> 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; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg; } #endif - else if (loc.indirect == 0) + else if (new_cfa->indirect == 0) { /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction, indicating the CFA register has changed to <register> 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) + if (new_cfa->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; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg; + cfi->dw_cfi_oprnd2.dw_cfi_offset = new_cfa->offset; } else { @@ -541,14 +608,32 @@ def_cfa_1 (dw_cfa_location *loc_p) struct dw_loc_descr_struct *loc_list; cfi->dw_cfi_opc = DW_CFA_def_cfa_expression; - loc_list = build_cfa_loc (&loc, 0); + loc_list = build_cfa_loc (new_cfa, 0); cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list; - - cur_row->cfa_cfi = cfi; } - add_cfi (cfi); - cur_row->cfa = loc; + return cfi; +} + +/* Similarly, but take OLD_CFA from CUR_ROW, and update it after the fact. */ + +static void +def_cfa_1 (dw_cfa_location *new_cfa) +{ + dw_cfi_ref cfi; + + if (cfa_store.reg == new_cfa->reg && new_cfa->indirect == 0) + cfa_store.offset = new_cfa->offset; + + cfi = def_cfa_0 (&cur_row->cfa, new_cfa); + if (cfi) + { + cur_row->cfa = *new_cfa; + if (cfi->dw_cfi_opc == DW_CFA_def_cfa_expression) + cur_row->cfa_cfi = cfi; + + add_cfi (cfi); + } } /* Add the CFI for saving a register. REG is the CFA column number. @@ -871,17 +956,11 @@ compute_barrier_args_size (void) static void dwarf2out_args_size (HOST_WIDE_INT size) { - dw_cfi_ref cfi; - if (size == cur_row->args_size) return; cur_row->args_size = size; - - cfi = new_cfi (); - cfi->dw_cfi_opc = DW_CFA_GNU_args_size; - cfi->dw_cfi_oprnd1.dw_cfi_offset = size; - add_cfi (cfi); + add_cfi_args_size (size); } /* Record a stack adjustment of OFFSET bytes. */ @@ -1385,13 +1464,9 @@ dwarf2out_frame_debug_cfa_expression (rtx set) static void dwarf2out_frame_debug_cfa_restore (rtx reg) { - dw_cfi_ref cfi = new_cfi (); unsigned int regno = dwf_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_cfi (cfi); + add_cfi_restore (regno); update_row_reg_save (cur_row, regno, NULL); } @@ -2238,6 +2313,48 @@ dwarf2out_frame_debug (rtx insn, bool after_p) dwarf2out_flush_queued_reg_saves (); } +/* Emit CFI info to change the state from OLD_ROW to NEW_ROW. */ + +static void +change_cfi_row (dw_cfi_row_ref old_row, dw_cfi_row_ref new_row) +{ + size_t i, n_old, n_new, n_max; + dw_cfi_ref cfi; + + if (new_row->cfa_cfi && !cfi_equal_p (old_row->cfa_cfi, new_row->cfa_cfi)) + add_cfi (new_row->cfa_cfi); + else + { + cfi = def_cfa_0 (&old_row->cfa, &new_row->cfa); + if (cfi) + add_cfi (cfi); + } + + if (old_row->args_size != new_row->args_size) + add_cfi_args_size (new_row->args_size); + + n_old = VEC_length (dw_cfi_ref, old_row->reg_save); + n_new = VEC_length (dw_cfi_ref, new_row->reg_save); + n_max = MAX (n_old, n_new); + + for (i = 0; i < n_max; ++i) + { + dw_cfi_ref r_old = NULL, r_new = NULL; + + if (i < n_old) + r_old = VEC_index (dw_cfi_ref, old_row->reg_save, i); + if (i < n_new) + r_new = VEC_index (dw_cfi_ref, new_row->reg_save, i); + + if (r_old == r_new) + ; + else if (r_new == NULL) + add_cfi_restore (i); + else if (!cfi_equal_p (r_old, r_new)) + add_cfi (r_new); + } +} + /* Examine CFI and return true if a cfi label and set_loc is needed beforehand. Even when generating CFI assembler instructions, we still have to add the cfi to the list so that lookup_cfa_1 works @@ -2291,6 +2408,8 @@ add_cfis_to_fde (void) if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) { + fde->dw_fde_switch_cfi_index + = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); /* Don't attempt to advance_loc4 between labels in different sections. */ first = true; @@ -2370,6 +2489,16 @@ create_cfi_notes (void) add_cfi_insn = insn; dwarf2out_frame_debug_restore_state (); break; + + case NOTE_INSN_SWITCH_TEXT_SECTIONS: + /* In dwarf2out_switch_text_section, we'll begin a new FDE + for the portion of the function in the alternate text + section. The row state at the very beginning of that + new FDE will be exactly the row state from the CIE. + Emit whatever CFIs are necessary to make CUR_ROW current. */ + add_cfi_insn = insn; + change_cfi_row (cie_cfi_row, cur_row); + break; } continue; } @@ -3047,175 +3176,6 @@ dwarf2out_emit_cfi (dw_cfi_ref cfi) if (dwarf2out_do_cfi_asm ()) output_cfi_directive (asm_out_file, cfi); } - -/* 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. */ - -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 (asm_out_file, 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 (asm_out_file, 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 (asm_out_file, 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 (asm_out_file, cfi); - else - output_cfi (cfi, fde, for_eh); - break; - default: - gcc_unreachable (); - } - } -} /* Save the result of dwarf2out_do_frame across PCH. diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 639a383..d430753 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -519,11 +519,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); @@ -603,36 +601,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 @@ -1184,16 +1170,8 @@ dwarf2out_switch_text_section (void) = (sect == text_section || (cold_text_section && sect == cold_text_section)); - fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); - if (dwarf2out_do_cfi_asm ()) - { - dwarf2out_do_cfi_startproc (true); - /* As this is a different FDE, insert all current CFI instructions - again. */ - output_cfis (fde->dw_fde_cfi, fde->dw_fde_switch_cfi_index, - true, fde, true); - } + dwarf2out_do_cfi_startproc (true); var_location_switch_text_section (); @@ -1639,6 +1617,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 diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h index d0e76a7..711e8ab 100644 --- a/gcc/dwarf2out.h +++ b/gcc/dwarf2out.h @@ -134,6 +134,7 @@ typedef struct GTY(()) cfa_loc { enum dw_val_class { + dw_val_class_none, dw_val_class_addr, dw_val_class_offset, dw_val_class_loc, @@ -226,6 +227,7 @@ extern struct dw_loc_descr_struct *build_cfa_aligned_loc extern struct dw_loc_descr_struct *mem_loc_descriptor (rtx, enum machine_mode mode, enum machine_mode mem_mode, enum var_init_status); +extern bool loc_descr_equal_p (dw_loc_descr_ref, dw_loc_descr_ref); extern enum machine_mode get_address_mode (rtx mem); extern dw_fde_ref dwarf2out_alloc_current_fde (void); @@ -239,7 +241,6 @@ extern void lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, extern bool cfa_equal_p (const dw_cfa_location *, const dw_cfa_location *); extern void output_cfi (dw_cfi_ref, dw_fde_ref, int); -extern void output_cfis (cfi_vec, int, bool, dw_fde_ref, bool); extern GTY(()) cfi_vec cie_cfi_vec; |