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:
Richard Henderson 2011-07-23 13:17:54 -07:00 committed by Richard Henderson
parent f1a0e8300d
commit 57e16c9625
4 changed files with 309 additions and 248 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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;