Commit 1adbb361 by Alexandre Oliva Committed by Alexandre Oliva

re PR debug/48866 (gcc hangs when -g is set)

PR debug/48866
* df.h (enum debug_temp_where): New.
(dead_debug_init, dead_debug_finish) Declare.
(dead_debug_add, dead_debug_insert_temp): Declare.
(struct dead_debug_use, struct dead_debug): Moved from...
* df-problems.c: ... here.
(df_set_unused_notes_for_mw): Bind debug uses of unused regno
to a debug temp.
(df_create_unused_note): Likewise.
(df_set_dead_notes_for_mw): Move comment where it belongs.
(dead_debug_init): Export.
(dead_debug_reset_uses): New, factored out of...
(dead_debug_finish): ...this.  Export.
(dead_debug_reset): Remove.
(dead_debug_add): Export.
(dead_debug_insert_before): Rename to...
(dead_debug_insert_temp): ... this.  Add where argument.  Export.
Locate stored value for BEFORE_WITH_VALUE.  Avoid repeat inserts.
Return insertion count.
(df_note_bb_compute): Adjust.
* dce.c (word_dce_process_block): Adjust dead debug uses.
(dce_process_block): Likewise.

From-SVN: r186422
parent 6ae1d471
2012-04-13 Alexandre Oliva <aoliva@redhat.com> 2012-04-13 Alexandre Oliva <aoliva@redhat.com>
PR debug/48866
* df.h (enum debug_temp_where): New.
(dead_debug_init, dead_debug_finish) Declare.
(dead_debug_add, dead_debug_insert_temp): Declare.
(struct dead_debug_use, struct dead_debug): Moved from...
* df-problems.c: ... here.
(df_set_unused_notes_for_mw): Bind debug uses of unused regno
to a debug temp.
(df_create_unused_note): Likewise.
(df_set_dead_notes_for_mw): Move comment where it belongs.
(dead_debug_init): Export.
(dead_debug_reset_uses): New, factored out of...
(dead_debug_finish): ...this. Export.
(dead_debug_reset): Remove.
(dead_debug_add): Export.
(dead_debug_insert_before): Rename to...
(dead_debug_insert_temp): ... this. Add where argument. Export.
Locate stored value for BEFORE_WITH_VALUE. Avoid repeat inserts.
Return insertion count.
(df_note_bb_compute): Adjust.
* dce.c (word_dce_process_block): Adjust dead debug uses.
(dce_process_block): Likewise.
2012-04-13 Alexandre Oliva <aoliva@redhat.com>
* df-problems.c (df_note_bb_compute): Do not take note of * df-problems.c (df_note_bb_compute): Do not take note of
debug uses for whose REGs we won't emit DEAD or UNUSED notes. debug uses for whose REGs we won't emit DEAD or UNUSED notes.
......
...@@ -807,6 +807,7 @@ word_dce_process_block (basic_block bb, bool redo_out) ...@@ -807,6 +807,7 @@ word_dce_process_block (basic_block bb, bool redo_out)
bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack); bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack);
rtx insn; rtx insn;
bool block_changed; bool block_changed;
struct dead_debug debug;
if (redo_out) if (redo_out)
{ {
...@@ -828,11 +829,24 @@ word_dce_process_block (basic_block bb, bool redo_out) ...@@ -828,11 +829,24 @@ word_dce_process_block (basic_block bb, bool redo_out)
} }
bitmap_copy (local_live, DF_WORD_LR_OUT (bb)); bitmap_copy (local_live, DF_WORD_LR_OUT (bb));
dead_debug_init (&debug, NULL);
FOR_BB_INSNS_REVERSE (bb, insn) FOR_BB_INSNS_REVERSE (bb, insn)
if (NONDEBUG_INSN_P (insn)) if (DEBUG_INSN_P (insn))
{
df_ref *use_rec;
for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
if (DF_REF_REGNO (*use_rec) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (DF_REF_REAL_REG (*use_rec)))
== 2 * UNITS_PER_WORD)
&& !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec))
&& !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec) + 1))
dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec));
}
else if (INSN_P (insn))
{ {
bool any_changed; bool any_changed;
/* No matter if the instruction is needed or not, we remove /* No matter if the instruction is needed or not, we remove
any regno in the defs from the live set. */ any regno in the defs from the live set. */
any_changed = df_word_lr_simulate_defs (insn, local_live); any_changed = df_word_lr_simulate_defs (insn, local_live);
...@@ -844,6 +858,15 @@ word_dce_process_block (basic_block bb, bool redo_out) ...@@ -844,6 +858,15 @@ word_dce_process_block (basic_block bb, bool redo_out)
if (marked_insn_p (insn)) if (marked_insn_p (insn))
df_word_lr_simulate_uses (insn, local_live); df_word_lr_simulate_uses (insn, local_live);
if (debug.used && !bitmap_empty_p (debug.used))
{
df_ref *def_rec;
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
dead_debug_insert_temp (&debug, DF_REF_REGNO (*def_rec), insn,
DEBUG_TEMP_BEFORE_WITH_VALUE);
}
if (dump_file) if (dump_file)
{ {
fprintf (dump_file, "finished processing insn %d live out = ", fprintf (dump_file, "finished processing insn %d live out = ",
...@@ -856,6 +879,7 @@ word_dce_process_block (basic_block bb, bool redo_out) ...@@ -856,6 +879,7 @@ word_dce_process_block (basic_block bb, bool redo_out)
if (block_changed) if (block_changed)
bitmap_copy (DF_WORD_LR_IN (bb), local_live); bitmap_copy (DF_WORD_LR_IN (bb), local_live);
dead_debug_finish (&debug, NULL);
BITMAP_FREE (local_live); BITMAP_FREE (local_live);
return block_changed; return block_changed;
} }
...@@ -873,6 +897,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au) ...@@ -873,6 +897,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au)
rtx insn; rtx insn;
bool block_changed; bool block_changed;
df_ref *def_rec; df_ref *def_rec;
struct dead_debug debug;
if (redo_out) if (redo_out)
{ {
...@@ -896,22 +921,36 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au) ...@@ -896,22 +921,36 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au)
bitmap_copy (local_live, DF_LR_OUT (bb)); bitmap_copy (local_live, DF_LR_OUT (bb));
df_simulate_initialize_backwards (bb, local_live); df_simulate_initialize_backwards (bb, local_live);
dead_debug_init (&debug, NULL);
FOR_BB_INSNS_REVERSE (bb, insn) FOR_BB_INSNS_REVERSE (bb, insn)
if (INSN_P (insn)) if (DEBUG_INSN_P (insn))
{
df_ref *use_rec;
for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
if (!bitmap_bit_p (local_live, DF_REF_REGNO (*use_rec))
&& !bitmap_bit_p (au, DF_REF_REGNO (*use_rec)))
dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec));
}
else if (INSN_P (insn))
{ {
bool needed = marked_insn_p (insn); bool needed = marked_insn_p (insn);
/* The insn is needed if there is someone who uses the output. */ /* The insn is needed if there is someone who uses the output. */
if (!needed) if (!needed)
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec)) {
|| bitmap_bit_p (au, DF_REF_REGNO (*def_rec))) dead_debug_insert_temp (&debug, DF_REF_REGNO (*def_rec), insn,
{ DEBUG_TEMP_BEFORE_WITH_VALUE);
needed = true;
mark_insn (insn, true); if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec))
break; || bitmap_bit_p (au, DF_REF_REGNO (*def_rec)))
} {
needed = true;
mark_insn (insn, true);
break;
}
}
/* No matter if the instruction is needed or not, we remove /* No matter if the instruction is needed or not, we remove
any regno in the defs from the live set. */ any regno in the defs from the live set. */
...@@ -923,6 +962,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au) ...@@ -923,6 +962,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au)
df_simulate_uses (insn, local_live); df_simulate_uses (insn, local_live);
} }
dead_debug_finish (&debug, NULL);
df_simulate_finalize_backwards (bb, local_live); df_simulate_finalize_backwards (bb, local_live);
block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb)); block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb));
......
...@@ -2886,25 +2886,6 @@ df_whole_mw_reg_unused_p (struct df_mw_hardreg *mws, ...@@ -2886,25 +2886,6 @@ df_whole_mw_reg_unused_p (struct df_mw_hardreg *mws,
} }
/* 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 /* 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 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 artificial uses. DO_NOT_GEN is updated so that REG_DEAD notes are
...@@ -2930,7 +2911,7 @@ df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws, ...@@ -2930,7 +2911,7 @@ df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws,
{ {
unsigned int regno = mws->start_regno; unsigned int regno = mws->start_regno;
df_set_note (REG_UNUSED, insn, mws->mw_reg); df_set_note (REG_UNUSED, insn, mws->mw_reg);
dead_debug_reset (debug, regno); dead_debug_insert_temp (debug, regno, insn, DEBUG_TEMP_AFTER_WITH_REG);
#ifdef REG_DEAD_DEBUGGING #ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 1: ", insn, REG_NOTES (insn)); df_print_note ("adding 1: ", insn, REG_NOTES (insn));
...@@ -2945,7 +2926,7 @@ df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws, ...@@ -2945,7 +2926,7 @@ df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws,
&& !bitmap_bit_p (artificial_uses, r)) && !bitmap_bit_p (artificial_uses, r))
{ {
df_set_note (REG_UNUSED, insn, regno_reg_rtx[r]); df_set_note (REG_UNUSED, insn, regno_reg_rtx[r]);
dead_debug_reset (debug, r); dead_debug_insert_temp (debug, r, insn, DEBUG_TEMP_AFTER_WITH_REG);
#ifdef REG_DEAD_DEBUGGING #ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 2: ", insn, REG_NOTES (insn)); df_print_note ("adding 2: ", insn, REG_NOTES (insn));
#endif #endif
...@@ -3013,12 +2994,12 @@ df_set_dead_notes_for_mw (rtx insn, struct df_mw_hardreg *mws, ...@@ -3013,12 +2994,12 @@ df_set_dead_notes_for_mw (rtx insn, struct df_mw_hardreg *mws,
if (df_whole_mw_reg_dead_p (mws, live, artificial_uses, do_not_gen)) if (df_whole_mw_reg_dead_p (mws, live, artificial_uses, do_not_gen))
{ {
/* Add a dead note for the entire multi word register. */
if (is_debug) if (is_debug)
{ {
*added_notes_p = true; *added_notes_p = true;
return; return;
} }
/* Add a dead note for the entire multi word register. */
df_set_note (REG_DEAD, insn, mws->mw_reg); df_set_note (REG_DEAD, insn, mws->mw_reg);
#ifdef REG_DEAD_DEBUGGING #ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 1: ", insn, REG_NOTES (insn)); df_print_note ("adding 1: ", insn, REG_NOTES (insn));
...@@ -3072,7 +3053,7 @@ df_create_unused_note (rtx insn, df_ref def, ...@@ -3072,7 +3053,7 @@ df_create_unused_note (rtx insn, df_ref def,
rtx reg = (DF_REF_LOC (def)) rtx reg = (DF_REF_LOC (def))
? *DF_REF_REAL_LOC (def): DF_REF_REG (def); ? *DF_REF_REAL_LOC (def): DF_REF_REG (def);
df_set_note (REG_UNUSED, insn, reg); df_set_note (REG_UNUSED, insn, reg);
dead_debug_reset (debug, dregno); dead_debug_insert_temp (debug, dregno, insn, DEBUG_TEMP_AFTER_WITH_REG);
#ifdef REG_DEAD_DEBUGGING #ifdef REG_DEAD_DEBUGGING
df_print_note ("adding 3: ", insn, REG_NOTES (insn)); df_print_note ("adding 3: ", insn, REG_NOTES (insn));
#endif #endif
...@@ -3083,7 +3064,7 @@ df_create_unused_note (rtx insn, df_ref def, ...@@ -3083,7 +3064,7 @@ df_create_unused_note (rtx insn, df_ref def,
/* Initialize DEBUG to an empty list, and clear USED, if given. */ /* Initialize DEBUG to an empty list, and clear USED, if given. */
static inline void void
dead_debug_init (struct dead_debug *debug, bitmap used) dead_debug_init (struct dead_debug *debug, bitmap used)
{ {
debug->head = NULL; debug->head = NULL;
...@@ -3093,32 +3074,83 @@ dead_debug_init (struct dead_debug *debug, bitmap used) ...@@ -3093,32 +3074,83 @@ dead_debug_init (struct dead_debug *debug, bitmap used)
bitmap_clear (used); bitmap_clear (used);
} }
/* Reset all debug insns with pending uses. Release the bitmap in it, /* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of
unless it is USED. USED must be the same bitmap passed to each reset insn. DEBUG is not otherwise modified. If HEAD is
dead_debug_init. */ DEBUG->head, DEBUG->head will be set to NULL at the end.
static inline void Otherwise, entries from DEBUG->head that pertain to reset insns
dead_debug_finish (struct dead_debug *debug, bitmap used) will be removed, and only then rescanned. */
static void
dead_debug_reset_uses (struct dead_debug *debug, struct dead_debug_use *head)
{ {
struct dead_debug_use *head; bool got_head = (debug->head == head);
rtx insn = NULL; bitmap rescan;
struct dead_debug_use **tailp = &debug->head;
struct dead_debug_use *cur;
bitmap_iterator bi;
unsigned int uid;
if (debug->used != used) if (got_head)
BITMAP_FREE (debug->used); rescan = NULL;
else
rescan = BITMAP_ALLOC (NULL);
while ((head = debug->head)) while (head)
{ {
struct dead_debug_use *next = head->next;
rtx insn;
insn = DF_REF_INSN (head->use); insn = DF_REF_INSN (head->use);
if (!head->next || DF_REF_INSN (head->next->use) != insn) if (!next || DF_REF_INSN (next->use) != insn)
{ {
INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
df_insn_rescan_debug_internal (insn); if (got_head)
df_insn_rescan_debug_internal (insn);
else
bitmap_set_bit (rescan, INSN_UID (insn));
if (debug->to_rescan) if (debug->to_rescan)
bitmap_clear_bit (debug->to_rescan, INSN_UID (insn)); bitmap_clear_bit (debug->to_rescan, INSN_UID (insn));
} }
debug->head = head->next;
XDELETE (head); XDELETE (head);
head = next;
}
if (got_head)
{
debug->head = NULL;
return;
}
while ((cur = *tailp))
if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use))))
{
*tailp = cur->next;
XDELETE (cur);
}
else
tailp = &cur->next;
EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi)
{
struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
if (insn_info)
df_insn_rescan_debug_internal (insn_info->insn);
} }
BITMAP_FREE (rescan);
}
/* Reset all debug insns with pending uses. Release the bitmap in it,
unless it is USED. USED must be the same bitmap passed to
dead_debug_init. */
void
dead_debug_finish (struct dead_debug *debug, bitmap used)
{
if (debug->used != used)
BITMAP_FREE (debug->used);
dead_debug_reset_uses (debug, debug->head);
if (debug->to_rescan) if (debug->to_rescan)
{ {
bitmap_iterator bi; bitmap_iterator bi;
...@@ -3134,54 +3166,9 @@ dead_debug_finish (struct dead_debug *debug, bitmap used) ...@@ -3134,54 +3166,9 @@ dead_debug_finish (struct dead_debug *debug, bitmap used)
} }
} }
/* 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 /* Add USE to DEBUG. It must be a dead reference to UREGNO in a debug
insn. Create a bitmap for DEBUG as needed. */ insn. Create a bitmap for DEBUG as needed. */
static inline void void
dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno) dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno)
{ {
struct dead_debug_use *newddu = XNEW (struct dead_debug_use); struct dead_debug_use *newddu = XNEW (struct dead_debug_use);
...@@ -3197,23 +3184,27 @@ dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno) ...@@ -3197,23 +3184,27 @@ dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno)
} }
/* If UREGNO is referenced by any entry in DEBUG, emit a debug insn /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
before INSN that binds the REG to a debug temp, and replace all before or after INSN (depending on WHERE), that binds a debug temp
uses of UREGNO in DEBUG with uses of the debug temp. INSN must be to the widest-mode use of UREGNO, if WHERE is *_WITH_REG, or the
the insn where UREGNO dies. */ value stored in UREGNO by INSN otherwise, and replace all uses of
static inline void UREGNO in DEBUG with uses of the debug temp. INSN must be where
dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, UREGNO dies, if WHERE is *_BEFORE_*, or where it is set otherwise.
rtx insn) Return the number of debug insns emitted. */
int
dead_debug_insert_temp (struct dead_debug *debug, unsigned int uregno,
rtx insn, enum debug_temp_where where)
{ {
struct dead_debug_use **tailp = &debug->head; struct dead_debug_use **tailp = &debug->head;
struct dead_debug_use *cur; struct dead_debug_use *cur;
struct dead_debug_use *uses = NULL; struct dead_debug_use *uses = NULL;
struct dead_debug_use **usesp = &uses; struct dead_debug_use **usesp = &uses;
rtx reg = NULL; rtx reg = NULL;
rtx breg;
rtx dval; rtx dval;
rtx bind; rtx bind;
if (!debug->used || !bitmap_clear_bit (debug->used, uregno)) if (!debug->used || !bitmap_clear_bit (debug->used, uregno))
return; return 0;
/* Move all uses of uregno from debug->head to uses, setting mode to /* Move all uses of uregno from debug->head to uses, setting mode to
the widest referenced mode. */ the widest referenced mode. */
...@@ -3237,17 +3228,114 @@ dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, ...@@ -3237,17 +3228,114 @@ dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno,
/* We may have dangling bits in debug->used for registers that were part /* 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. */ of a multi-register use, one component of which has been reset. */
if (reg == NULL) if (reg == NULL)
return; {
gcc_checking_assert (!uses);
return 0;
}
gcc_checking_assert (uses);
breg = reg;
/* Recover the expression INSN stores in REG. */
if (where == DEBUG_TEMP_BEFORE_WITH_VALUE)
{
rtx set = single_set (insn);
rtx dest, src;
if (set)
{
dest = SET_DEST (set);
src = SET_SRC (set);
/* Lose if the REG-setting insn is a CALL. */
if (GET_CODE (src) == CALL)
{
while (uses)
{
cur = uses->next;
XDELETE (uses);
uses = cur;
}
return 0;
}
}
/* ??? Should we try to extract it from a PARALLEL? */
if (!set)
breg = NULL;
/* Cool, it's the same REG, we can use SRC. */
else if (dest == reg)
breg = copy_rtx (src);
else if (REG_P (dest))
{
/* Hmm... Something's fishy, we should be setting REG here. */
if (REGNO (dest) != REGNO (reg))
breg = NULL;
/* Ok, it's the same (hardware) REG, but with a different
mode, so SUBREG it. */
else
breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src),
GET_MODE (dest));
}
else if (GET_CODE (dest) == SUBREG)
{
/* We should be setting REG here. Lose. */
if (REGNO (SUBREG_REG (dest)) != REGNO (reg))
breg = NULL;
/* Lose if we're setting something other than the lowpart of
REG. */
else if (!subreg_lowpart_p (dest))
breg = NULL;
/* If we're not overwriting all the hardware registers that
setting REG in its mode would, we won't know what to bind
the debug temp to. */
else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
&& (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
!= hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
breg = NULL;
/* Yay, we can use SRC, just adjust its mode. */
else
breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src),
GET_MODE (dest));
}
/* Oh well, we're out of luck. */
else
breg = NULL;
/* We couldn't figure out the value stored in REG, so reset all
of its pending debug uses. */
if (!breg)
{
dead_debug_reset_uses (debug, uses);
return 0;
}
}
/* If there's a single (debug) use of an otherwise unused REG, and
the debug use is not part of a larger expression, then it
probably doesn't make sense to introduce a new debug temp. */
if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
{
rtx next = DF_REF_INSN (uses->use);
if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
{
XDELETE (uses);
return 0;
}
}
/* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */ /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */
dval = make_debug_expr_from_rtl (reg); dval = make_debug_expr_from_rtl (reg);
/* Emit a debug bind insn before the insn in which reg dies. */ /* Emit a debug bind insn before the insn in which reg dies. */
bind = gen_rtx_VAR_LOCATION (GET_MODE (reg), bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
DEBUG_EXPR_TREE_DECL (dval), reg, DEBUG_EXPR_TREE_DECL (dval), breg,
VAR_INIT_STATUS_INITIALIZED); VAR_INIT_STATUS_INITIALIZED);
bind = emit_debug_insn_before (bind, insn); if (where == DEBUG_TEMP_AFTER_WITH_REG)
bind = emit_debug_insn_after (bind, insn);
else
bind = emit_debug_insn_before (bind, insn);
df_insn_rescan (bind); df_insn_rescan (bind);
/* Adjust all uses. */ /* Adjust all uses. */
...@@ -3265,6 +3353,8 @@ dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, ...@@ -3265,6 +3353,8 @@ dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno,
uses = cur->next; uses = cur->next;
XDELETE (cur); XDELETE (cur);
} }
return 1;
} }
/* Recompute the REG_DEAD and REG_UNUSED notes and compute register /* Recompute the REG_DEAD and REG_UNUSED notes and compute register
...@@ -3464,7 +3554,8 @@ df_note_bb_compute (unsigned int bb_index, ...@@ -3464,7 +3554,8 @@ df_note_bb_compute (unsigned int bb_index,
break; break;
} }
else else
dead_debug_insert_before (&debug, uregno, insn); dead_debug_insert_temp (&debug, uregno, insn,
DEBUG_TEMP_BEFORE_WITH_REG);
if ( (!(DF_REF_FLAGS (use) if ( (!(DF_REF_FLAGS (use)
& (DF_REF_MW_HARDREG | DF_REF_READ_WRITE))) & (DF_REF_MW_HARDREG | DF_REF_READ_WRITE)))
......
...@@ -1101,4 +1101,46 @@ extern void union_defs (df_ref, struct web_entry *, ...@@ -1101,4 +1101,46 @@ extern void union_defs (df_ref, struct web_entry *,
unsigned int *used, struct web_entry *, unsigned int *used, struct web_entry *,
bool (*fun) (struct web_entry *, struct web_entry *)); bool (*fun) (struct web_entry *, struct web_entry *));
/* Debug uses of dead regs. */
/* 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;
};
/* This type controls the behavior of dead_debug_insert_temp WRT
UREGNO and INSN. */
enum debug_temp_where
{
/* Bind a newly-created debug temporary to a REG for UREGNO, and
insert the debug insn before INSN. REG is expected to die at
INSN. */
DEBUG_TEMP_BEFORE_WITH_REG = -1,
/* Bind a newly-created debug temporary to the value INSN stores
in REG, and insert the debug insn before INSN. */
DEBUG_TEMP_BEFORE_WITH_VALUE = 0,
/* Bind a newly-created debug temporary to a REG for UREGNO, and
insert the debug insn after INSN. REG is expected to be set at
INSN. */
DEBUG_TEMP_AFTER_WITH_REG = 1
};
extern void dead_debug_init (struct dead_debug *, bitmap);
extern void dead_debug_finish (struct dead_debug *, bitmap);
extern void dead_debug_add (struct dead_debug *, df_ref, unsigned int);
extern int dead_debug_insert_temp (struct dead_debug *,
unsigned int uregno, rtx insn,
enum debug_temp_where);
#endif /* GCC_DF_H */ #endif /* GCC_DF_H */
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