mirror of git://gcc.gnu.org/git/gcc.git
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
|
|
@ -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>
|
2010-10-14 Zdenek Dvorak <rakdver@kam.uniff.cz>
|
||||||
|
|
||||||
* et-forest.c (et_nca): Return NULL immediately when
|
* et-forest.c (et_nca): Return NULL immediately when
|
||||||
the dominance forest has disjoint components.
|
the dominance forest has disjoint components.
|
||||||
|
|
||||||
|
|
|
||||||
191
gcc/cse.c
191
gcc/cse.c
|
|
@ -1,6 +1,6 @@
|
||||||
/* Common subexpression elimination for GNU compiler.
|
/* Common subexpression elimination for GNU compiler.
|
||||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
|
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.
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GCC.
|
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
|
static inline int
|
||||||
is_dead_reg (rtx *loc, void *data)
|
is_dead_reg (rtx x, int *counts)
|
||||||
{
|
{
|
||||||
rtx x = *loc;
|
|
||||||
int *counts = (int *)data;
|
|
||||||
|
|
||||||
return (REG_P (x)
|
return (REG_P (x)
|
||||||
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
|
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
|
||||||
&& counts[REGNO (x)] == 0);
|
&& 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))))
|
|| !reg_referenced_p (cc0_rtx, PATTERN (tem))))
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#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)))
|
|| side_effects_p (SET_SRC (set)))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
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))
|
else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return true;
|
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
|
/* 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.
|
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;
|
int *counts;
|
||||||
rtx insn, prev;
|
rtx insn, prev;
|
||||||
|
rtx *replacements = NULL;
|
||||||
int ndead = 0;
|
int ndead = 0;
|
||||||
|
|
||||||
timevar_push (TV_DELETE_TRIVIALLY_DEAD);
|
timevar_push (TV_DELETE_TRIVIALLY_DEAD);
|
||||||
/* First count the number of times each register is used. */
|
/* First count the number of times each register is used. */
|
||||||
counts = XCNEWVEC (int, nreg);
|
if (MAY_HAVE_DEBUG_INSNS)
|
||||||
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
{
|
||||||
if (INSN_P (insn))
|
counts = XCNEWVEC (int, nreg * 3);
|
||||||
count_reg_usage (insn, counts, NULL_RTX, 1);
|
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
|
/* 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
|
registers or copy a register to itself. As we delete an insn, remove
|
||||||
usage counts for registers it uses.
|
usage counts for registers it uses.
|
||||||
|
|
||||||
The first jump optimization pass may leave a real insn as the last
|
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
|
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)
|
for (insn = get_last_insn (); insn; insn = prev)
|
||||||
{
|
{
|
||||||
int live_insn = 0;
|
int live_insn = 0;
|
||||||
|
|
@ -6834,12 +6907,80 @@ delete_trivially_dead_insns (rtx insns, int nreg)
|
||||||
|
|
||||||
if (! live_insn && dbg_cnt (delete_trivial_dead))
|
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);
|
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)
|
if (dump_file && ndead)
|
||||||
fprintf (dump_file, "Deleted %i trivially dead insns\n",
|
fprintf (dump_file, "Deleted %i trivially dead insns\n",
|
||||||
ndead);
|
ndead);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue