cse.c (is_dead_reg): Change into inline function that is not called through for_each_rtx.
* cse.c (is_dead_reg): Change into inline function that is not called through for_each_rtx. (set_live_p): Adjust caller. (insn_live_p): Don't reset DEBUG_INSNs here. (struct dead_debug_insn_data): New data. (count_stores, is_dead_debug_insn, replace_dead_reg): New functions. (delete_trivially_dead_insns): If there is just one setter for the dead reg that is referenced by some DEBUG_INSNs, create a DEBUG_EXPR and add DEBUG_INSN for it right before the removed setter and use the DEBUG_EXPR instead of the dead pseudo. From-SVN: r165452
This commit is contained in:
parent
d2e60b7bc2
commit
6699b754e1
2 changed files with 180 additions and 25 deletions
|
@ -1,4 +1,18 @@
|
|||
2010-10-14 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* cse.c (is_dead_reg): Change into inline function that is not
|
||||
called through for_each_rtx.
|
||||
(set_live_p): Adjust caller.
|
||||
(insn_live_p): Don't reset DEBUG_INSNs here.
|
||||
(struct dead_debug_insn_data): New data.
|
||||
(count_stores, is_dead_debug_insn, replace_dead_reg): New functions.
|
||||
(delete_trivially_dead_insns): If there is just one setter for the
|
||||
dead reg that is referenced by some DEBUG_INSNs, create a DEBUG_EXPR
|
||||
and add DEBUG_INSN for it right before the removed setter and
|
||||
use the DEBUG_EXPR instead of the dead pseudo.
|
||||
|
||||
2010-10-14 Zdenek Dvorak <rakdver@kam.uniff.cz>
|
||||
|
||||
* et-forest.c (et_nca): Return NULL immediately when
|
||||
the dominance forest has disjoint components.
|
||||
|
||||
|
|
191
gcc/cse.c
191
gcc/cse.c
|
@ -1,6 +1,6 @@
|
|||
/* Common subexpression elimination for GNU compiler.
|
||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
@ -6698,14 +6698,11 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return true if a register is dead. Can be used in for_each_rtx. */
|
||||
/* Return true if X is a dead register. */
|
||||
|
||||
static int
|
||||
is_dead_reg (rtx *loc, void *data)
|
||||
static inline int
|
||||
is_dead_reg (rtx x, int *counts)
|
||||
{
|
||||
rtx x = *loc;
|
||||
int *counts = (int *)data;
|
||||
|
||||
return (REG_P (x)
|
||||
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
|
||||
&& counts[REGNO (x)] == 0);
|
||||
|
@ -6731,7 +6728,7 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0. */
|
|||
|| !reg_referenced_p (cc0_rtx, PATTERN (tem))))
|
||||
return false;
|
||||
#endif
|
||||
else if (!is_dead_reg (&SET_DEST (set), counts)
|
||||
else if (!is_dead_reg (SET_DEST (set), counts)
|
||||
|| side_effects_p (SET_SRC (set)))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -6775,21 +6772,68 @@ insn_live_p (rtx insn, int *counts)
|
|||
else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
|
||||
return false;
|
||||
|
||||
/* If this debug insn references a dead register, drop the
|
||||
location expression for now. ??? We could try to find the
|
||||
def and see if propagation is possible. */
|
||||
if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn), is_dead_reg, counts))
|
||||
{
|
||||
INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
|
||||
df_insn_rescan (insn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Count the number of stores into pseudo. Callback for note_stores. */
|
||||
|
||||
static void
|
||||
count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data)
|
||||
{
|
||||
int *counts = (int *) data;
|
||||
if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
|
||||
counts[REGNO (x)]++;
|
||||
}
|
||||
|
||||
struct dead_debug_insn_data
|
||||
{
|
||||
int *counts;
|
||||
rtx *replacements;
|
||||
bool seen_repl;
|
||||
};
|
||||
|
||||
/* Return if a DEBUG_INSN needs to be reset because some dead
|
||||
pseudo doesn't have a replacement. Callback for for_each_rtx. */
|
||||
|
||||
static int
|
||||
is_dead_debug_insn (rtx *loc, void *data)
|
||||
{
|
||||
rtx x = *loc;
|
||||
struct dead_debug_insn_data *ddid = (struct dead_debug_insn_data *) data;
|
||||
|
||||
if (is_dead_reg (x, ddid->counts))
|
||||
{
|
||||
if (ddid->replacements && ddid->replacements[REGNO (x)] != NULL_RTX)
|
||||
ddid->seen_repl = true;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
|
||||
Callback for simplify_replace_fn_rtx. */
|
||||
|
||||
static rtx
|
||||
replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
|
||||
{
|
||||
rtx *replacements = (rtx *) data;
|
||||
|
||||
if (REG_P (x)
|
||||
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
|
||||
&& replacements[REGNO (x)] != NULL_RTX)
|
||||
{
|
||||
if (GET_MODE (x) == GET_MODE (replacements[REGNO (x)]))
|
||||
return replacements[REGNO (x)];
|
||||
return lowpart_subreg (GET_MODE (x), replacements[REGNO (x)],
|
||||
GET_MODE (replacements[REGNO (x)]));
|
||||
}
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Scan all the insns and delete any that are dead; i.e., they store a register
|
||||
that is never used or they copy a register to itself.
|
||||
|
||||
|
@ -6803,22 +6847,51 @@ delete_trivially_dead_insns (rtx insns, int nreg)
|
|||
{
|
||||
int *counts;
|
||||
rtx insn, prev;
|
||||
rtx *replacements = NULL;
|
||||
int ndead = 0;
|
||||
|
||||
timevar_push (TV_DELETE_TRIVIALLY_DEAD);
|
||||
/* First count the number of times each register is used. */
|
||||
counts = XCNEWVEC (int, nreg);
|
||||
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
||||
if (INSN_P (insn))
|
||||
count_reg_usage (insn, counts, NULL_RTX, 1);
|
||||
|
||||
if (MAY_HAVE_DEBUG_INSNS)
|
||||
{
|
||||
counts = XCNEWVEC (int, nreg * 3);
|
||||
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
||||
if (DEBUG_INSN_P (insn))
|
||||
count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
|
||||
NULL_RTX, 1);
|
||||
else if (INSN_P (insn))
|
||||
{
|
||||
count_reg_usage (insn, counts, NULL_RTX, 1);
|
||||
note_stores (PATTERN (insn), count_stores, counts + nreg * 2);
|
||||
}
|
||||
/* If there can be debug insns, COUNTS are 3 consecutive arrays.
|
||||
First one counts how many times each pseudo is used outside
|
||||
of debug insns, second counts how many times each pseudo is
|
||||
used in debug insns and third counts how many times a pseudo
|
||||
is stored. */
|
||||
}
|
||||
else
|
||||
{
|
||||
counts = XCNEWVEC (int, nreg);
|
||||
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
||||
if (INSN_P (insn))
|
||||
count_reg_usage (insn, counts, NULL_RTX, 1);
|
||||
/* If no debug insns can be present, COUNTS is just an array
|
||||
which counts how many times each pseudo is used. */
|
||||
}
|
||||
/* Go from the last insn to the first and delete insns that only set unused
|
||||
registers or copy a register to itself. As we delete an insn, remove
|
||||
usage counts for registers it uses.
|
||||
|
||||
The first jump optimization pass may leave a real insn as the last
|
||||
insn in the function. We must not skip that insn or we may end
|
||||
up deleting code that is not really dead. */
|
||||
up deleting code that is not really dead.
|
||||
|
||||
If some otherwise unused register is only used in DEBUG_INSNs,
|
||||
try to create a DEBUG_EXPR temporary and emit a DEBUG_INSN before
|
||||
the setter. Then go through DEBUG_INSNs and if a DEBUG_EXPR
|
||||
has been created for the unused register, replace it with
|
||||
the DEBUG_EXPR, otherwise reset the DEBUG_INSN. */
|
||||
for (insn = get_last_insn (); insn; insn = prev)
|
||||
{
|
||||
int live_insn = 0;
|
||||
|
@ -6834,12 +6907,80 @@ delete_trivially_dead_insns (rtx insns, int nreg)
|
|||
|
||||
if (! live_insn && dbg_cnt (delete_trivial_dead))
|
||||
{
|
||||
count_reg_usage (insn, counts, NULL_RTX, -1);
|
||||
if (DEBUG_INSN_P (insn))
|
||||
count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
|
||||
NULL_RTX, -1);
|
||||
else
|
||||
{
|
||||
rtx set;
|
||||
if (MAY_HAVE_DEBUG_INSNS
|
||||
&& (set = single_set (insn)) != NULL_RTX
|
||||
&& is_dead_reg (SET_DEST (set), counts)
|
||||
/* Used at least once in some DEBUG_INSN. */
|
||||
&& counts[REGNO (SET_DEST (set)) + nreg] > 0
|
||||
/* And set exactly once. */
|
||||
&& counts[REGNO (SET_DEST (set)) + nreg * 2] == 1
|
||||
&& !side_effects_p (SET_SRC (set))
|
||||
&& asm_noperands (PATTERN (insn)) < 0)
|
||||
{
|
||||
rtx dval, bind;
|
||||
|
||||
/* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */
|
||||
dval = make_debug_expr_from_rtl (SET_DEST (set));
|
||||
|
||||
/* Emit a debug bind insn before the insn in which
|
||||
reg dies. */
|
||||
bind = gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)),
|
||||
DEBUG_EXPR_TREE_DECL (dval),
|
||||
SET_SRC (set),
|
||||
VAR_INIT_STATUS_INITIALIZED);
|
||||
count_reg_usage (bind, counts + nreg, NULL_RTX, 1);
|
||||
|
||||
bind = emit_debug_insn_before (bind, insn);
|
||||
df_insn_rescan (bind);
|
||||
|
||||
if (replacements == NULL)
|
||||
replacements = XCNEWVEC (rtx, nreg);
|
||||
replacements[REGNO (SET_DEST (set))] = dval;
|
||||
}
|
||||
|
||||
count_reg_usage (insn, counts, NULL_RTX, -1);
|
||||
ndead++;
|
||||
}
|
||||
delete_insn_and_edges (insn);
|
||||
ndead++;
|
||||
}
|
||||
}
|
||||
|
||||
if (MAY_HAVE_DEBUG_INSNS)
|
||||
{
|
||||
struct dead_debug_insn_data ddid;
|
||||
ddid.counts = counts;
|
||||
ddid.replacements = replacements;
|
||||
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
|
||||
if (DEBUG_INSN_P (insn))
|
||||
{
|
||||
/* If this debug insn references a dead register that wasn't replaced
|
||||
with an DEBUG_EXPR, reset the DEBUG_INSN. */
|
||||
ddid.seen_repl = false;
|
||||
if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn),
|
||||
is_dead_debug_insn, &ddid))
|
||||
{
|
||||
INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
|
||||
df_insn_rescan (insn);
|
||||
}
|
||||
else if (ddid.seen_repl)
|
||||
{
|
||||
INSN_VAR_LOCATION_LOC (insn)
|
||||
= simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
|
||||
NULL_RTX, replace_dead_reg,
|
||||
replacements);
|
||||
df_insn_rescan (insn);
|
||||
}
|
||||
}
|
||||
if (replacements)
|
||||
free (replacements);
|
||||
}
|
||||
|
||||
if (dump_file && ndead)
|
||||
fprintf (dump_file, "Deleted %i trivially dead insns\n",
|
||||
ndead);
|
||||
|
|
Loading…
Add table
Reference in a new issue