X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcse.c;h=3ab6b37a8ea99f51cad920714aa7f161ceff7884;hb=e440a3286bc89368b8d3a8fd6accd47191790bf2;hp=4683c7f779b86e72793fbf60e83f5953ce367e28;hpb=0eaaa1b0662a57628209e48b0cc49da3baa2908b;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cse.c b/gcc/cse.c index 4683c7f779b..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. @@ -29,11 +29,11 @@ along with GCC; see the file COPYING3. If not see #include "regs.h" #include "basic-block.h" #include "flags.h" -#include "real.h" #include "insn-config.h" #include "recog.h" #include "function.h" #include "expr.h" +#include "diagnostic-core.h" #include "toplev.h" #include "output.h" #include "ggc.h" @@ -2286,7 +2286,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode, On all machines, we can't record any global registers. Nor should we record any register that is in a small - class, as defined by CLASS_LIKELY_SPILLED_P. */ + class, as defined by TARGET_CLASS_LIKELY_SPILLED_P. */ bool record; if (regno >= FIRST_PSEUDO_REGISTER) @@ -2305,7 +2305,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode, record = true; else if (targetm.small_register_classes_for_mode_p (GET_MODE (x))) record = false; - else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno))) + else if (targetm.class_likely_spilled_p (REGNO_REG_CLASS (regno))) record = false; else record = true; @@ -2670,26 +2670,16 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse) case MEM: if (for_gcse) { + /* Can't merge two expressions in different alias sets, since we + can decide that the expression is transparent in a block when + it isn't, due to it being set with the different alias set. */ + if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y)) + return 0; + /* A volatile mem should not be considered equivalent to any other. */ if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y)) return 0; - - /* Can't merge two expressions in different alias sets, since we - can decide that the expression is transparent in a block when - it isn't, due to it being set with the different alias set. - - Also, can't merge two expressions with different MEM_ATTRS. - They could e.g. be two different entities allocated into the - same space on the stack (see e.g. PR25130). In that case, the - MEM addresses can be the same, even though the two MEMs are - absolutely not equivalent. - - But because really all MEM attributes should be the same for - equivalent MEMs, we just use the invariant that MEMs that have - the same attributes share the same mem_attrs data structure. */ - if (MEM_ATTRS (x) != MEM_ATTRS (y)) - return 0; } break; @@ -4348,12 +4338,23 @@ cse_insn (rtx insn) if (MEM_P (XEXP (x, 0))) canon_reg (XEXP (x, 0), insn); } - /* Canonicalize a USE of a pseudo register or memory location. */ else if (GET_CODE (x) == USE && ! (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)) - canon_reg (XEXP (x, 0), insn); + canon_reg (x, insn); + else if (GET_CODE (x) == ASM_OPERANDS) + { + for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--) + { + rtx input = ASM_OPERANDS_INPUT (x, i); + if (!(REG_P (input) && REGNO (input) < FIRST_PSEUDO_REGISTER)) + { + input = canon_reg (input, insn); + validate_change (insn, &ASM_OPERANDS_INPUT (x, i), input, 1); + } + } + } else if (GET_CODE (x) == CALL) { /* The result of apply_change_group can be ignored; see canon_reg. */ @@ -5025,7 +5026,7 @@ cse_insn (rtx insn) dest = canon_rtx (SET_DEST (sets[i].rtl)); if (!MEM_P (src) || !MEM_P (dest) - || !nonoverlapping_memrefs_p (src, dest)) + || !nonoverlapping_memrefs_p (src, dest, false)) break; } @@ -6316,9 +6317,9 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data) } } + optimize_this_for_speed_p = optimize_bb_for_speed_p (bb); FOR_BB_INSNS (bb, insn) { - optimize_this_for_speed_p = optimize_bb_for_speed_p (bb); /* If we have processed 1,000 insns, flush the hash table to avoid extreme quadratic behavior. We must not include NOTEs in the count since there may be more of them when generating @@ -6358,29 +6359,31 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data) recorded_label_ref = true; #ifdef HAVE_cc0 - /* If the previous insn set CC0 and this insn no longer - references CC0, delete the previous insn. Here we use - fact that nothing expects CC0 to be valid over an insn, - which is true until the final pass. */ - { - rtx prev_insn, tem; - - prev_insn = PREV_INSN (insn); - if (prev_insn && NONJUMP_INSN_P (prev_insn) - && (tem = single_set (prev_insn)) != 0 - && SET_DEST (tem) == cc0_rtx - && ! reg_mentioned_p (cc0_rtx, PATTERN (insn))) - delete_insn (prev_insn); - } - - /* If this insn is not the last insn in the basic block, - it will be PREV_INSN(insn) in the next iteration. If - we recorded any CC0-related information for this insn, - remember it. */ - if (insn != BB_END (bb)) + if (NONDEBUG_INSN_P (insn)) { - prev_insn_cc0 = this_insn_cc0; - prev_insn_cc0_mode = this_insn_cc0_mode; + /* If the previous insn sets CC0 and this insn no + longer references CC0, delete the previous insn. + Here we use fact that nothing expects CC0 to be + valid over an insn, which is true until the final + pass. */ + rtx prev_insn, tem; + + prev_insn = prev_nonnote_nondebug_insn (insn); + if (prev_insn && NONJUMP_INSN_P (prev_insn) + && (tem = single_set (prev_insn)) != NULL_RTX + && SET_DEST (tem) == cc0_rtx + && ! reg_mentioned_p (cc0_rtx, PATTERN (insn))) + delete_insn (prev_insn); + + /* If this insn is not the last insn in the basic + block, it will be PREV_INSN(insn) in the next + iteration. If we recorded any CC0-related + information for this insn, remember it. */ + if (insn != BB_END (bb)) + { + prev_insn_cc0 = this_insn_cc0; + prev_insn_cc0_mode = this_insn_cc0_mode; + } } #endif } @@ -6389,7 +6392,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data) /* With non-call exceptions, we are not always able to update the CFG properly inside cse_insn. So clean up possibly redundant EH edges here. */ - if (flag_non_call_exceptions && have_eh_succ_edges (bb)) + if (cfun->can_throw_non_call_exceptions && have_eh_succ_edges (bb)) cse_cfg_altered |= purge_dead_edges (bb); /* If we changed a conditional jump, we may have terminated @@ -6695,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); @@ -6723,12 +6723,12 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0. */ #ifdef HAVE_cc0 else if (GET_CODE (SET_DEST (set)) == CC0 && !side_effects_p (SET_SRC (set)) - && ((tem = next_nonnote_insn (insn)) == 0 + && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX || !INSN_P (tem) || !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; @@ -6772,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. @@ -6800,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; @@ -6831,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);