Commit 6699b754 by Jakub Jelinek Committed by Jakub Jelinek

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
parent d2e60b7b
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.
/* 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);
......
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