diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-10-14 07:17:54 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-10-14 07:17:54 +0000 |
commit | a52dfddb5ace2b5f7b9c90ce8a1d306d1b2f936c (patch) | |
tree | 4c0b4bb96185a3d569106623c3fc4e30cfc0e171 /gcc/cse.c | |
parent | 8cb78e283c17b81509565a53ddbf9dacec10c67e (diff) | |
download | gcc-a52dfddb5ace2b5f7b9c90ce8a1d306d1b2f936c.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165452 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cse.c')
-rw-r--r-- | gcc/cse.c | 191 |
1 files changed, 166 insertions, 25 deletions
diff --git a/gcc/cse.c b/gcc/cse.c index 4d10c842e0f..3ab6b37a8ea 100644 --- a/gcc/cse.c +++ b/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); |