/* Standard problems for dataflow support routines.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010 Free Software Foundation, Inc.
+ 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Originally contributed by Michael P. Hayes
(m.hayes@elec.canterbury.ac.nz, mhayes@redhat.com)
Major rewrite contributed by Danny Berlin (dberlin@dberlin.org)
for (; link; link = link->next)
{
fprintf (file, "%c%d(bb %d insn %d) ",
- DF_REF_REG_DEF_P (link->ref) ? 'd' : 'u',
+ DF_REF_REG_DEF_P (link->ref)
+ ? 'd'
+ : (DF_REF_FLAGS (link->ref) & DF_REF_IN_NOTE) ? 'e' : 'u',
DF_REF_ID (link->ref),
DF_REF_BBNO (link->ref),
- DF_REF_IS_ARTIFICIAL (link->ref) ? -1 : DF_REF_INSN_UID (link->ref));
+ DF_REF_IS_ARTIFICIAL (link->ref)
+ ? -1 : DF_REF_INSN_UID (link->ref));
}
fprintf (file, "}");
}
blocks within infinite loops. */
if (!reload_completed)
{
+ unsigned int pic_offset_table_regnum = PIC_OFFSET_TABLE_REGNUM;
/* Any reference to any pseudo before reload is a potential
reference of the frame pointer. */
bitmap_set_bit (&df->hardware_regs_used, FRAME_POINTER_REGNUM);
/* Any constant, or pseudo with constant equivalences, may
require reloading from memory using the pic register. */
- if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
- && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
- bitmap_set_bit (&df->hardware_regs_used, PIC_OFFSET_TABLE_REGNUM);
+ if (pic_offset_table_regnum != INVALID_REGNUM
+ && fixed_regs[pic_offset_table_regnum])
+ bitmap_set_bit (&df->hardware_regs_used, pic_offset_table_regnum);
}
EXECUTE_IF_SET_IN_BITMAP (df_lr->out_of_date_transfer_functions, 0, bb_index, bi)
/* Remove all of the REG_DEAD or REG_UNUSED notes from INSN and add
- them to OLD_DEAD_NOTES and OLD_UNUSED_NOTES. */
+ them to OLD_DEAD_NOTES and OLD_UNUSED_NOTES. Remove also
+ REG_EQUAL/REG_EQUIV notes referring to dead pseudos using LIVE
+ as the bitmap of currently live registers. */
static void
-df_kill_notes (rtx insn)
+df_kill_notes (rtx insn, bitmap live)
{
rtx *pprev = ®_NOTES (insn);
rtx link = *pprev;
}
break;
+ case REG_EQUAL:
+ case REG_EQUIV:
+ {
+ /* Remove the notes that refer to dead registers. As we have at most
+ one REG_EQUAL/EQUIV note, all of EQ_USES will refer to this note
+ so we need to purge the complete EQ_USES vector when removing
+ the note using df_notes_rescan. */
+ df_ref *use_rec;
+ bool deleted = false;
+
+ for (use_rec = DF_INSN_EQ_USES (insn); *use_rec; use_rec++)
+ {
+ df_ref use = *use_rec;
+ if (DF_REF_REGNO (use) > FIRST_PSEUDO_REGISTER
+ && DF_REF_LOC (use)
+ && (DF_REF_FLAGS (use) & DF_REF_IN_NOTE)
+ && ! bitmap_bit_p (live, DF_REF_REGNO (use))
+ && loc_mentioned_in_p (DF_REF_LOC (use), XEXP (link, 0)))
+ {
+ deleted = true;
+ break;
+ }
+ }
+ if (deleted)
+ {
+ rtx next;
+#ifdef REG_DEAD_DEBUGGING
+ df_print_note ("deleting: ", insn, link);
+#endif
+ next = XEXP (link, 1);
+ free_EXPR_LIST_node (link);
+ *pprev = link = next;
+ df_notes_rescan (insn);
+ }
+ else
+ {
+ pprev = &XEXP (link, 1);
+ link = *pprev;
+ }
+ break;
+ }
default:
pprev = &XEXP (link, 1);
link = *pprev;
return true;
}
+
+/* Node of a linked list of uses of dead REGs in debug insns. */
+struct dead_debug_use
+{
+ df_ref use;
+ struct dead_debug_use *next;
+};
+
+/* Linked list of the above, with a bitmap of the REGs in the
+ list. */
+struct dead_debug
+{
+ struct dead_debug_use *head;
+ bitmap used;
+ bitmap to_rescan;
+};
+
+static void dead_debug_reset (struct dead_debug *, unsigned int);
+
+
/* Set the REG_UNUSED notes for the multiword hardreg defs in INSN
based on the bits in LIVE. Do not generate notes for registers in
artificial uses. DO_NOT_GEN is updated so that REG_DEAD notes are
static void
df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws,
bitmap live, bitmap do_not_gen,
- bitmap artificial_uses)
+ bitmap artificial_uses,
+ struct dead_debug *debug)
{
unsigned int r;
{
unsigned int regno = mws->start_regno;
df_set_note (REG_UNUSED, insn, mws->mw_reg);
+ dead_debug_reset (debug, regno);
#ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 1: ", insn, REG_NOTES (insn));
&& !bitmap_bit_p (artificial_uses, r))
{
df_set_note (REG_UNUSED, insn, regno_reg_rtx[r]);
+ dead_debug_reset (debug, r);
#ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 2: ", insn, REG_NOTES (insn));
#endif
static void
df_create_unused_note (rtx insn, df_ref def,
- bitmap live, bitmap artificial_uses)
+ bitmap live, bitmap artificial_uses,
+ struct dead_debug *debug)
{
unsigned int dregno = DF_REF_REGNO (def);
rtx reg = (DF_REF_LOC (def))
? *DF_REF_REAL_LOC (def): DF_REF_REG (def);
df_set_note (REG_UNUSED, insn, reg);
+ dead_debug_reset (debug, dregno);
#ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 3: ", insn, REG_NOTES (insn));
#endif
return;
}
-/* Node of a linked list of uses of dead REGs in debug insns. */
-struct dead_debug_use
-{
- df_ref use;
- struct dead_debug_use *next;
-};
-
-/* Linked list of the above, with a bitmap of the REGs in the
- list. */
-struct dead_debug
-{
- struct dead_debug_use *head;
- bitmap used;
- bitmap to_rescan;
-};
/* Initialize DEBUG to an empty list, and clear USED, if given. */
static inline void
}
}
+/* Reset DEBUG_INSNs with pending uses of DREGNO. */
+static void
+dead_debug_reset (struct dead_debug *debug, unsigned int dregno)
+{
+ struct dead_debug_use **tailp = &debug->head;
+ struct dead_debug_use **insnp = &debug->head;
+ struct dead_debug_use *cur;
+ rtx insn;
+
+ if (!debug->used || !bitmap_clear_bit (debug->used, dregno))
+ return;
+
+ while ((cur = *tailp))
+ {
+ if (DF_REF_REGNO (cur->use) == dregno)
+ {
+ *tailp = cur->next;
+ insn = DF_REF_INSN (cur->use);
+ INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+ if (debug->to_rescan == NULL)
+ debug->to_rescan = BITMAP_ALLOC (NULL);
+ bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
+ XDELETE (cur);
+ /* If the current use isn't the first one attached to INSN, go back
+ to this first use. We assume that the uses attached to an insn
+ are adjacent. */
+ if (tailp != insnp && DF_REF_INSN ((*insnp)->use) == insn)
+ tailp = insnp;
+ /* Then remove all the other uses attached to INSN. */
+ while ((cur = *tailp) && DF_REF_INSN (cur->use) == insn)
+ {
+ *tailp = cur->next;
+ XDELETE (cur);
+ }
+ insnp = tailp;
+ }
+ else
+ {
+ if (DF_REF_INSN ((*insnp)->use) != DF_REF_INSN (cur->use))
+ insnp = tailp;
+ tailp = &(*tailp)->next;
+ }
+ }
+}
+
/* Add USE to DEBUG. It must be a dead reference to UREGNO in a debug
insn. Create a bitmap for DEBUG as needed. */
static inline void
tailp = &(*tailp)->next;
}
- gcc_assert (reg);
+ /* We may have dangling bits in debug->used for registers that were part
+ of a multi-register use, one component of which has been reset. */
+ if (reg == NULL)
+ return;
/* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */
dval = make_debug_expr_from_rtl (reg);
debug_insn = DEBUG_INSN_P (insn);
bitmap_clear (do_not_gen);
- df_kill_notes (insn);
+ df_kill_notes (insn, live);
/* Process the defs. */
if (CALL_P (insn))
&& !df_ignore_stack_reg (mws->start_regno))
df_set_unused_notes_for_mw (insn,
mws, live, do_not_gen,
- artificial_uses);
+ artificial_uses, &debug);
mws_rec++;
}
if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))
{
df_create_unused_note (insn,
- def, live, artificial_uses);
+ def, live, artificial_uses, &debug);
bitmap_set_bit (do_not_gen, dregno);
}
if (DF_MWS_REG_DEF_P (mws))
df_set_unused_notes_for_mw (insn,
mws, live, do_not_gen,
- artificial_uses);
+ artificial_uses, &debug);
mws_rec++;
}
df_ref def = *def_rec;
unsigned int dregno = DF_REF_REGNO (def);
df_create_unused_note (insn,
- def, live, artificial_uses);
+ def, live, artificial_uses, &debug);
if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))
bitmap_set_bit (do_not_gen, dregno);
while (*mws_rec)
{
struct df_mw_hardreg *mws = *mws_rec;
- if ((DF_MWS_REG_DEF_P (mws))
+ if (DF_MWS_REG_USE_P (mws)
&& !df_ignore_stack_reg (mws->start_regno))
{
bool really_add_notes = debug_insn != 0;
{
rtx reg = XEXP (link, 0);
int regno = REGNO (reg);
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- int n = hard_regno_nregs[regno][GET_MODE (reg)];
- while (--n >= 0)
- bitmap_clear_bit (live, regno + n);
- }
+ if (HARD_REGISTER_NUM_P (regno))
+ bitmap_clear_range (live, regno,
+ hard_regno_nregs[regno][GET_MODE (reg)]);
else
bitmap_clear_bit (live, regno);
}
for (insn = across_to; ; insn = next)
{
+ if (CALL_P (insn))
+ {
+ if (RTL_CONST_OR_PURE_CALL_P (insn))
+ /* Pure functions can read from memory. Const functions can
+ read from arguments that the ABI has forced onto the stack.
+ Neither sort of read can be volatile. */
+ memrefs_in_across |= MEMREF_NORMAL;
+ else
+ {
+ memrefs_in_across |= MEMREF_VOLATILE;
+ mem_sets_in_across |= MEMREF_VOLATILE;
+ }
+ }
if (NONDEBUG_INSN_P (insn))
{
memrefs_in_across |= for_each_rtx (&PATTERN (insn), find_memory,
{
if (CALL_P (insn))
break;
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG)
+ break;
if (NONDEBUG_INSN_P (insn))
{
- if (may_trap_p (PATTERN (insn))
+ if (may_trap_or_fault_p (PATTERN (insn))
&& (trapping_insns_in_across || other_branch_live != NULL))
break;
if (bitmap_intersect_p (merge_set, test_use)
|| bitmap_intersect_p (merge_use, test_set))
break;
- max_to = insn;
+#ifdef HAVE_cc0
+ if (!sets_cc0_p (insn))
+#endif
+ max_to = insn;
}
next = NEXT_INSN (insn);
if (insn == to)
{
if (NONDEBUG_INSN_P (insn))
{
- if (!bitmap_intersect_p (test_set, local_merge_live))
+ if (!bitmap_intersect_p (test_set, local_merge_live)
+#ifdef HAVE_cc0
+ && !sets_cc0_p (insn)
+#endif
+ )
{
max_to = insn;
break;