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
This commit is contained in:
parent
f1a0e8300d
commit
57e16c9625
@ -1,3 +1,22 @@
|
||||
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.
|
||||
|
376
gcc/dwarf2cfi.c
376
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)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
dw_cfa_location loc = *loc_p;
|
||||
|
||||
if (cfa_store.reg == loc.reg && loc.indirect == 0)
|
||||
cfa_store.offset = loc.offset;
|
||||
|
||||
/* 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.
|
||||
|
159
gcc/dwarf2out.c
159
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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user