Commit 57e16c96 by Richard Henderson Committed by Richard Henderson

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
parent f1a0e830
2011-07-23 Richard Henderson <rth@redhat.com> 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. * dwarf2cfi.c (update_row_reg_save): New.
(dwarf2out_frame_debug_cfa_expression): Use it. (dwarf2out_frame_debug_cfa_expression): Use it.
(dwarf2out_frame_debug_cfa_restore): Likewise. (dwarf2out_frame_debug_cfa_restore): Likewise.
......
...@@ -285,6 +285,28 @@ add_cfi (dw_cfi_ref cfi) ...@@ -285,6 +285,28 @@ add_cfi (dw_cfi_ref cfi)
VEC_safe_push (dw_cfi_ref, gc, *add_cfi_vec, 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 /* Perform ROW->REG_SAVE[COLUMN] = CFI. CFI may be null, indicating
that the register column is no longer saved. */ 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) ...@@ -474,64 +496,109 @@ cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
|| loc1->base_offset == loc2->base_offset)); || loc1->base_offset == loc2->base_offset));
} }
/* This routine does the actual work. The CFA is now calculated from /* Determine if two CFI operands are identical. */
the dw_cfa_location structure. */
static void static bool
def_cfa_1 (dw_cfa_location *loc_p) cfi_oprnd_equal_p (enum dw_cfi_oprnd_type t, dw_cfi_oprnd *a, dw_cfi_oprnd *b)
{ {
dw_cfi_ref cfi; switch (t)
dw_cfa_location loc = *loc_p; {
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) /* Determine if two CFI entries are identical. */
cfa_store.offset = loc.offset;
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 nothing changed, no need to issue any call frame instructions. */
if (cfa_equal_p (&loc, &cur_row->cfa)) if (cfa_equal_p (old_cfa, new_cfa))
return; return NULL;
cfi = new_cfi (); 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 /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
the CFA register did not change but the offset did. The data the CFA register did not change but the offset did. The data
factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
in the assembler via the .cfi_def_cfa_offset directive. */ 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; cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
else else
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; 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. */ #ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
else if (loc.offset == cur_row->cfa.offset else if (new_cfa->offset == old_cfa->offset
&& cur_row->cfa.reg != INVALID_REGNUM && old_cfa->reg != INVALID_REGNUM
&& !loc.indirect && !new_cfa->indirect
&& !cur_row->cfa.indirect) && !old_cfa->indirect)
{ {
/* Construct a "DW_CFA_def_cfa_register <register>" instruction, /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
indicating the CFA register has changed to <register> but the indicating the CFA register has changed to <register> but the
offset has not changed. */ offset has not changed. */
cfi->dw_cfi_opc = DW_CFA_def_cfa_register; 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 #endif
else if (loc.indirect == 0) else if (new_cfa->indirect == 0)
{ {
/* Construct a "DW_CFA_def_cfa <register> <offset>" instruction, /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
indicating the CFA register has changed to <register> with indicating the CFA register has changed to <register> with
the specified offset. The data factoring for DW_CFA_def_cfa_sf 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 happens in output_cfi, or in the assembler via the .cfi_def_cfa
directive. */ directive. */
if (loc.offset < 0) if (new_cfa->offset < 0)
cfi->dw_cfi_opc = DW_CFA_def_cfa_sf; cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
else else
cfi->dw_cfi_opc = DW_CFA_def_cfa; cfi->dw_cfi_opc = DW_CFA_def_cfa;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset; cfi->dw_cfi_oprnd2.dw_cfi_offset = new_cfa->offset;
} }
else else
{ {
...@@ -541,14 +608,32 @@ def_cfa_1 (dw_cfa_location *loc_p) ...@@ -541,14 +608,32 @@ def_cfa_1 (dw_cfa_location *loc_p)
struct dw_loc_descr_struct *loc_list; struct dw_loc_descr_struct *loc_list;
cfi->dw_cfi_opc = DW_CFA_def_cfa_expression; 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; cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
cur_row->cfa_cfi = cfi;
} }
add_cfi (cfi); return cfi;
cur_row->cfa = loc; }
/* 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. /* Add the CFI for saving a register. REG is the CFA column number.
...@@ -871,17 +956,11 @@ compute_barrier_args_size (void) ...@@ -871,17 +956,11 @@ compute_barrier_args_size (void)
static void static void
dwarf2out_args_size (HOST_WIDE_INT size) dwarf2out_args_size (HOST_WIDE_INT size)
{ {
dw_cfi_ref cfi;
if (size == cur_row->args_size) if (size == cur_row->args_size)
return; return;
cur_row->args_size = size; cur_row->args_size = size;
add_cfi_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);
} }
/* Record a stack adjustment of OFFSET bytes. */ /* Record a stack adjustment of OFFSET bytes. */
...@@ -1385,13 +1464,9 @@ dwarf2out_frame_debug_cfa_expression (rtx set) ...@@ -1385,13 +1464,9 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
static void static void
dwarf2out_frame_debug_cfa_restore (rtx reg) dwarf2out_frame_debug_cfa_restore (rtx reg)
{ {
dw_cfi_ref cfi = new_cfi ();
unsigned int regno = dwf_regno (reg); unsigned int regno = dwf_regno (reg);
cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore); add_cfi_restore (regno);
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
add_cfi (cfi);
update_row_reg_save (cur_row, regno, NULL); update_row_reg_save (cur_row, regno, NULL);
} }
...@@ -2238,6 +2313,48 @@ dwarf2out_frame_debug (rtx insn, bool after_p) ...@@ -2238,6 +2313,48 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
dwarf2out_flush_queued_reg_saves (); 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 /* Examine CFI and return true if a cfi label and set_loc is needed
beforehand. Even when generating CFI assembler instructions, we beforehand. Even when generating CFI assembler instructions, we
still have to add the cfi to the list so that lookup_cfa_1 works still have to add the cfi to the list so that lookup_cfa_1 works
...@@ -2291,6 +2408,8 @@ add_cfis_to_fde (void) ...@@ -2291,6 +2408,8 @@ add_cfis_to_fde (void)
if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) 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 /* Don't attempt to advance_loc4 between labels
in different sections. */ in different sections. */
first = true; first = true;
...@@ -2370,6 +2489,16 @@ create_cfi_notes (void) ...@@ -2370,6 +2489,16 @@ create_cfi_notes (void)
add_cfi_insn = insn; add_cfi_insn = insn;
dwarf2out_frame_debug_restore_state (); dwarf2out_frame_debug_restore_state ();
break; 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; continue;
} }
...@@ -3047,175 +3176,6 @@ dwarf2out_emit_cfi (dw_cfi_ref cfi) ...@@ -3047,175 +3176,6 @@ dwarf2out_emit_cfi (dw_cfi_ref cfi)
if (dwarf2out_do_cfi_asm ()) if (dwarf2out_do_cfi_asm ())
output_cfi_directive (asm_out_file, cfi); 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. /* Save the result of dwarf2out_do_frame across PCH.
......
...@@ -519,11 +519,9 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, ...@@ -519,11 +519,9 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
char *section_start_label, int fde_encoding, char *augmentation, char *section_start_label, int fde_encoding, char *augmentation,
bool any_lsda_needed, int lsda_encoding) bool any_lsda_needed, int lsda_encoding)
{ {
int ix;
const char *begin, *end; const char *begin, *end;
static unsigned int j; static unsigned int j;
char l1[20], l2[20]; char l1[20], l2[20];
dw_cfi_ref cfi;
targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh, targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
/* empty */ 0); /* empty */ 0);
...@@ -603,36 +601,24 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, ...@@ -603,36 +601,24 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
dw2_asm_output_data_uleb128 (0, "Augmentation size"); dw2_asm_output_data_uleb128 (0, "Augmentation size");
} }
/* Loop through the Call Frame Instructions associated with /* Loop through the Call Frame Instructions associated with this FDE. */
this FDE. */
fde->dw_fde_current_label = begin; 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) size_t from, until, i;
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);
if (fde->dw_fde_switch_cfi_index > 0) from = 0;
{ until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
from = fde->dw_fde_switch_cfi_index;
output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh); if (fde->dw_fde_second_begin == NULL)
} ;
for (i = from; i < until; i++) else if (!second)
output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), until = fde->dw_fde_switch_cfi_index;
fde, for_eh); 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, /* 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 do it now. This is typically performed to make sure that tables
...@@ -1184,16 +1170,8 @@ dwarf2out_switch_text_section (void) ...@@ -1184,16 +1170,8 @@ dwarf2out_switch_text_section (void)
= (sect == text_section = (sect == text_section
|| (cold_text_section && sect == cold_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 ()) if (dwarf2out_do_cfi_asm ())
{ dwarf2out_do_cfi_startproc (true);
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);
}
var_location_switch_text_section (); var_location_switch_text_section ();
...@@ -1639,6 +1617,109 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr) ...@@ -1639,6 +1617,109 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
*d = 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. */ /* Add a constant OFFSET to a location expression. */
static void static void
......
...@@ -134,6 +134,7 @@ typedef struct GTY(()) cfa_loc { ...@@ -134,6 +134,7 @@ typedef struct GTY(()) cfa_loc {
enum dw_val_class enum dw_val_class
{ {
dw_val_class_none,
dw_val_class_addr, dw_val_class_addr,
dw_val_class_offset, dw_val_class_offset,
dw_val_class_loc, dw_val_class_loc,
...@@ -226,6 +227,7 @@ extern struct dw_loc_descr_struct *build_cfa_aligned_loc ...@@ -226,6 +227,7 @@ extern struct dw_loc_descr_struct *build_cfa_aligned_loc
extern struct dw_loc_descr_struct *mem_loc_descriptor extern struct dw_loc_descr_struct *mem_loc_descriptor
(rtx, enum machine_mode mode, enum machine_mode mem_mode, (rtx, enum machine_mode mode, enum machine_mode mem_mode,
enum var_init_status); 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 enum machine_mode get_address_mode (rtx mem);
extern dw_fde_ref dwarf2out_alloc_current_fde (void); 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, ...@@ -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 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_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; extern GTY(()) cfi_vec cie_cfi_vec;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment