X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frecog.c;h=7303b2a86f30b7b2ccf4b8ded290eaddea47e22a;hb=9fa14f444ba21e181ad487986800b3e1dad74e0c;hp=e3cdfd799148e65cb7e9a2811db024b1dc0a9b88;hpb=026d38685a306238520bd2dc743b94e66ecf450f;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/recog.c b/gcc/recog.c index e3cdfd79914..7303b2a86f3 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -1,12 +1,13 @@ /* Subroutines used by or related to instruction recognition. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" @@ -31,6 +31,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "hard-reg-set.h" #include "recog.h" #include "regs.h" +#include "addresses.h" #include "expr.h" #include "function.h" #include "flags.h" @@ -41,6 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "reload.h" #include "timevar.h" #include "tree-pass.h" +#include "df.h" #ifndef STACK_PUSH_CODE #ifdef STACK_GROWS_DOWNWARD @@ -59,7 +61,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #endif static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx); -static rtx *find_single_use_1 (rtx, rtx *); static void validate_replace_src_1 (rtx *, void *); static rtx split_insn (rtx); @@ -139,7 +140,7 @@ check_asm_operands (rtx x) operands = alloca (noperands * sizeof (rtx)); constraints = alloca (noperands * sizeof (char *)); - decode_asm_operands (x, operands, NULL, constraints, NULL); + decode_asm_operands (x, operands, NULL, constraints, NULL, NULL); for (i = 0; i < noperands; i++) { @@ -164,6 +165,7 @@ typedef struct change_t int old_code; rtx *loc; rtx old; + bool unshare; } change_t; static change_t *changes; @@ -189,8 +191,8 @@ static int num_changes = 0; is not valid for the machine, suppress the change and return zero. Otherwise, perform the change and return 1. */ -int -validate_change (rtx object, rtx *loc, rtx new, int in_group) +static bool +validate_change_1 (rtx object, rtx *loc, rtx new, bool in_group, bool unshare) { rtx old = *loc; @@ -217,6 +219,7 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) changes[num_changes].object = object; changes[num_changes].loc = loc; changes[num_changes].old = old; + changes[num_changes].unshare = unshare; if (object && !MEM_P (object)) { @@ -237,45 +240,47 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) return apply_change_group (); } +/* Wrapper for validate_change_1 without the UNSHARE argument defaulting + UNSHARE to false. */ -/* Function to be passed to for_each_rtx to test whether a piece of - RTL contains any mem/v. */ -static int -volatile_mem_p (rtx *x, void *data ATTRIBUTE_UNUSED) +bool +validate_change (rtx object, rtx *loc, rtx new, bool in_group) { - return (MEM_P (*x) && MEM_VOLATILE_P (*x)); + return validate_change_1 (object, loc, new, in_group, false); } -/* Same as validate_change, but doesn't support groups, and it accepts - volatile mems if they're already present in the original insn. */ +/* Wrapper for validate_change_1 without the UNSHARE argument defaulting + UNSHARE to true. */ -int -validate_change_maybe_volatile (rtx object, rtx *loc, rtx new) +bool +validate_unshare_change (rtx object, rtx *loc, rtx new, bool in_group) { - int result; - - if (validate_change (object, loc, new, 0)) - return 1; - - if (volatile_ok - /* If there isn't a volatile MEM, there's nothing we can do. */ - || !for_each_rtx (&PATTERN (object), volatile_mem_p, 0) - /* Make sure we're not adding or removing volatile MEMs. */ - || for_each_rtx (loc, volatile_mem_p, 0) - || for_each_rtx (&new, volatile_mem_p, 0) - || !insn_invalid_p (object)) - return 0; - - volatile_ok = 1; - - gcc_assert (!insn_invalid_p (object)); + return validate_change_1 (object, loc, new, in_group, true); +} - result = validate_change (object, loc, new, 0); - volatile_ok = 0; +/* Keep X canonicalized if some changes have made it non-canonical; only + modifies the operands of X, not (for example) its code. Simplifications + are not the job of this routine. - return result; + Return true if anything was changed. */ +bool +canonicalize_change_group (rtx insn, rtx x) +{ + if (COMMUTATIVE_P (x) + && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))) + { + /* Oops, the caller has made X no longer canonical. + Let's redo the changes in the correct order. */ + rtx tem = XEXP (x, 0); + validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1); + validate_change (insn, &XEXP (x, 1), tem, 1); + return true; + } + else + return false; } + /* This subroutine of apply_change_group verifies whether the changes to INSN were valid; i.e. whether INSN can still be recognized. */ @@ -421,22 +426,35 @@ verify_changes (int num) return (i == num_changes); } -/* A group of changes has previously been issued with validate_change and - verified with verify_changes. Update the BB_DIRTY flags of the affected - blocks, and clear num_changes. */ +/* A group of changes has previously been issued with validate_change + and verified with verify_changes. Call df_insn_rescan for each of + the insn changed and clear num_changes. */ void confirm_change_group (void) { int i; - basic_block bb; + rtx last_object = NULL; for (i = 0; i < num_changes; i++) - if (changes[i].object - && INSN_P (changes[i].object) - && (bb = BLOCK_FOR_INSN (changes[i].object))) - bb->flags |= BB_DIRTY; + { + rtx object = changes[i].object; + if (changes[i].unshare) + *changes[i].loc = copy_rtx (*changes[i].loc); + + /* Avoid unnecesary rescanning when multiple changes to same instruction + are made. */ + if (object) + { + if (object != last_object && last_object && INSN_P (last_object)) + df_insn_rescan (last_object); + last_object = object; + } + } + + if (last_object && INSN_P (last_object)) + df_insn_rescan (last_object); num_changes = 0; } @@ -519,7 +537,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) && rtx_equal_p (x, from))) { - validate_change (object, loc, to, 1); + validate_unshare_change (object, loc, to, 1); return; } @@ -736,6 +754,46 @@ validate_replace_src_group (rtx from, rtx to, rtx insn) d.insn = insn; note_uses (&PATTERN (insn), validate_replace_src_1, &d); } + +/* Try simplify INSN. + Invoke simplify_rtx () on every SET_SRC and SET_DEST inside the INSN's + pattern and return true if something was simplified. */ + +bool +validate_simplify_insn (rtx insn) +{ + int i; + rtx pat = NULL; + rtx newpat = NULL; + + pat = PATTERN (insn); + + if (GET_CODE (pat) == SET) + { + newpat = simplify_rtx (SET_SRC (pat)); + if (newpat && !rtx_equal_p (SET_SRC (pat), newpat)) + validate_change (insn, &SET_SRC (pat), newpat, 1); + newpat = simplify_rtx (SET_DEST (pat)); + if (newpat && !rtx_equal_p (SET_DEST (pat), newpat)) + validate_change (insn, &SET_DEST (pat), newpat, 1); + } + else if (GET_CODE (pat) == PARALLEL) + for (i = 0; i < XVECLEN (pat, 0); i++) + { + rtx s = XVECEXP (pat, 0, i); + + if (GET_CODE (XVECEXP (pat, 0, i)) == SET) + { + newpat = simplify_rtx (SET_SRC (s)); + if (newpat && !rtx_equal_p (SET_SRC (s), newpat)) + validate_change (insn, &SET_SRC (s), newpat, 1); + newpat = simplify_rtx (SET_DEST (s)); + if (newpat && !rtx_equal_p (SET_DEST (s), newpat)) + validate_change (insn, &SET_DEST (s), newpat, 1); + } + } + return ((num_changes_pending () > 0) && (apply_change_group () > 0)); +} #ifdef HAVE_cc0 /* Return 1 if the insn using CC0 set by INSN does not contain @@ -756,168 +814,6 @@ next_insn_tests_no_inequality (rtx insn) } #endif -/* This is used by find_single_use to locate an rtx that contains exactly one - use of DEST, which is typically either a REG or CC0. It returns a - pointer to the innermost rtx expression containing DEST. Appearances of - DEST that are being used to totally replace it are not counted. */ - -static rtx * -find_single_use_1 (rtx dest, rtx *loc) -{ - rtx x = *loc; - enum rtx_code code = GET_CODE (x); - rtx *result = 0; - rtx *this_result; - int i; - const char *fmt; - - switch (code) - { - case CONST_INT: - case CONST: - case LABEL_REF: - case SYMBOL_REF: - case CONST_DOUBLE: - case CONST_VECTOR: - case CLOBBER: - return 0; - - case SET: - /* If the destination is anything other than CC0, PC, a REG or a SUBREG - of a REG that occupies all of the REG, the insn uses DEST if - it is mentioned in the destination or the source. Otherwise, we - need just check the source. */ - if (GET_CODE (SET_DEST (x)) != CC0 - && GET_CODE (SET_DEST (x)) != PC - && !REG_P (SET_DEST (x)) - && ! (GET_CODE (SET_DEST (x)) == SUBREG - && REG_P (SUBREG_REG (SET_DEST (x))) - && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x)))) - + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) - == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x))) - + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))) - break; - - return find_single_use_1 (dest, &SET_SRC (x)); - - case MEM: - case SUBREG: - return find_single_use_1 (dest, &XEXP (x, 0)); - - default: - break; - } - - /* If it wasn't one of the common cases above, check each expression and - vector of this code. Look for a unique usage of DEST. */ - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - if (dest == XEXP (x, i) - || (REG_P (dest) && REG_P (XEXP (x, i)) - && REGNO (dest) == REGNO (XEXP (x, i)))) - this_result = loc; - else - this_result = find_single_use_1 (dest, &XEXP (x, i)); - - if (result == 0) - result = this_result; - else if (this_result) - /* Duplicate usage. */ - return 0; - } - else if (fmt[i] == 'E') - { - int j; - - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - { - if (XVECEXP (x, i, j) == dest - || (REG_P (dest) - && REG_P (XVECEXP (x, i, j)) - && REGNO (XVECEXP (x, i, j)) == REGNO (dest))) - this_result = loc; - else - this_result = find_single_use_1 (dest, &XVECEXP (x, i, j)); - - if (result == 0) - result = this_result; - else if (this_result) - return 0; - } - } - } - - return result; -} - -/* See if DEST, produced in INSN, is used only a single time in the - sequel. If so, return a pointer to the innermost rtx expression in which - it is used. - - If PLOC is nonzero, *PLOC is set to the insn containing the single use. - - This routine will return usually zero either before flow is called (because - there will be no LOG_LINKS notes) or after reload (because the REG_DEAD - note can't be trusted). - - If DEST is cc0_rtx, we look only at the next insn. In that case, we don't - care about REG_DEAD notes or LOG_LINKS. - - Otherwise, we find the single use by finding an insn that has a - LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST. If DEST is - only referenced once in that insn, we know that it must be the first - and last insn referencing DEST. */ - -rtx * -find_single_use (rtx dest, rtx insn, rtx *ploc) -{ - rtx next; - rtx *result; - rtx link; - -#ifdef HAVE_cc0 - if (dest == cc0_rtx) - { - next = NEXT_INSN (insn); - if (next == 0 - || (!NONJUMP_INSN_P (next) && !JUMP_P (next))) - return 0; - - result = find_single_use_1 (dest, &PATTERN (next)); - if (result && ploc) - *ploc = next; - return result; - } -#endif - - if (reload_completed || reload_in_progress || !REG_P (dest)) - return 0; - - for (next = next_nonnote_insn (insn); - next != 0 && !LABEL_P (next); - next = next_nonnote_insn (next)) - if (INSN_P (next) && dead_or_set_p (next, dest)) - { - for (link = LOG_LINKS (next); link; link = XEXP (link, 1)) - if (XEXP (link, 0) == insn) - break; - - if (link) - { - result = find_single_use_1 (dest, &PATTERN (next)); - if (ploc) - *ploc = next; - return result; - } - } - - return 0; -} - /* Return 1 if OP is a valid general operand for machine mode MODE. This is either a register reference, a memory reference, or a constant. In the case of a memory reference, the address @@ -1383,7 +1279,7 @@ comparison_operator (rtx op, enum machine_mode mode) Otherwise return -1. */ int -asm_noperands (rtx body) +asm_noperands (const_rtx body) { switch (GET_CODE (body)) { @@ -1468,15 +1364,16 @@ asm_noperands (rtx body) const char * decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, - const char **constraints, enum machine_mode *modes) + const char **constraints, enum machine_mode *modes, + location_t *loc) { int i; int noperands; - const char *template = 0; + rtx asmop = 0; if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS) { - rtx asmop = SET_SRC (body); + asmop = SET_SRC (body); /* Single output operand: BODY is (set OUTPUT (asm_operands ....)). */ noperands = ASM_OPERANDS_INPUT_LENGTH (asmop) + 1; @@ -1503,11 +1400,10 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, constraints[0] = ASM_OPERANDS_OUTPUT_CONSTRAINT (asmop); if (modes) modes[0] = GET_MODE (SET_DEST (body)); - template = ASM_OPERANDS_TEMPLATE (asmop); } else if (GET_CODE (body) == ASM_OPERANDS) { - rtx asmop = body; + asmop = body; /* No output operands: BODY is (asm_operands ....). */ noperands = ASM_OPERANDS_INPUT_LENGTH (asmop); @@ -1525,17 +1421,18 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, if (modes) modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i); } - template = ASM_OPERANDS_TEMPLATE (asmop); } else if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == SET && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) == ASM_OPERANDS) { - rtx asmop = SET_SRC (XVECEXP (body, 0, 0)); int nparallel = XVECLEN (body, 0); /* Includes CLOBBERs. */ - int nin = ASM_OPERANDS_INPUT_LENGTH (asmop); + int nin; int nout = 0; /* Does not include CLOBBERs. */ + asmop = SET_SRC (XVECEXP (body, 0, 0)); + nin = ASM_OPERANDS_INPUT_LENGTH (asmop); + /* At least one output, plus some CLOBBERs. */ /* The outputs are in the SETs. @@ -1567,16 +1464,16 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, if (modes) modes[i + nout] = ASM_OPERANDS_INPUT_MODE (asmop, i); } - - template = ASM_OPERANDS_TEMPLATE (asmop); } else if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS) { /* No outputs, but some CLOBBERs. */ - rtx asmop = XVECEXP (body, 0, 0); - int nin = ASM_OPERANDS_INPUT_LENGTH (asmop); + int nin; + + asmop = XVECEXP (body, 0, 0); + nin = ASM_OPERANDS_INPUT_LENGTH (asmop); for (i = 0; i < nin; i++) { @@ -1590,10 +1487,12 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i); } - template = ASM_OPERANDS_TEMPLATE (asmop); } - return template; + if (loc) + *loc = ASM_OPERANDS_SOURCE_LOCATION (asmop); + + return ASM_OPERANDS_TEMPLATE (asmop); } /* Check if an asm_operand matches its constraints. @@ -1656,7 +1555,7 @@ asm_operand_ok (rtx op, const char *constraint) break; case '<': - /* ??? Before flow, auto inc/dec insns are not supposed to exist, + /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed to exist, excepting those that expand_call created. Further, on some machines which do not have generalized auto inc/dec, an inc/dec is not a memory_operand. @@ -1959,8 +1858,17 @@ offsettable_address_p (int strictp, enum machine_mode mode, rtx y) because the amount of the increment depends on the mode. */ int -mode_dependent_address_p (rtx addr ATTRIBUTE_UNUSED /* Maybe used in GO_IF_MODE_DEPENDENT_ADDRESS. */) -{ +mode_dependent_address_p (rtx addr) +{ + /* Auto-increment addressing with anything other than post_modify + or pre_modify always introduces a mode dependency. Catch such + cases now instead of deferring to the target. */ + if (GET_CODE (addr) == PRE_INC + || GET_CODE (addr) == POST_INC + || GET_CODE (addr) == PRE_DEC + || GET_CODE (addr) == POST_DEC) + return 1; + GO_IF_MODE_DEPENDENT_ADDRESS (addr, win); return 0; /* Label `win' might (not) be used via GO_IF_MODE_DEPENDENT_ADDRESS. */ @@ -2053,7 +1961,7 @@ extract_insn (rtx insn) decode_asm_operands (body, recog_data.operand, recog_data.operand_loc, recog_data.constraints, - recog_data.operand_mode); + recog_data.operand_mode, NULL); if (noperands > 0) { const char *p = recog_data.constraints[0]; @@ -2196,7 +2104,7 @@ preprocess_constraints (void) case 'p': op_alt[j].is_address = 1; op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]; + [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; break; case 'g': @@ -2217,7 +2125,8 @@ preprocess_constraints (void) op_alt[j].cl = (reg_class_subunion [(int) op_alt[j].cl] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]); + [(int) base_reg_class (VOIDmode, ADDRESS, + SCRATCH)]); break; } @@ -2668,21 +2577,9 @@ reg_fits_class_p (rtx operand, enum reg_class cl, int offset, if (cl == NO_REGS) return 0; - if (regno < FIRST_PSEUDO_REGISTER - && TEST_HARD_REG_BIT (reg_class_contents[(int) cl], - regno + offset)) - { - int sr; - regno += offset; - for (sr = hard_regno_nregs[regno][mode] - 1; - sr > 0; sr--) - if (! TEST_HARD_REG_BIT (reg_class_contents[(int) cl], - regno + sr)) - break; - return sr == 0; - } - - return 0; + return (regno < FIRST_PSEUDO_REGISTER + && in_hard_reg_set_p (reg_class_contents[(int) cl], + mode, regno + offset)); } /* Split single instruction. Helper function for split_all_insns and @@ -2722,7 +2619,7 @@ split_insn (rtx insn) /* Split all insns in the function. If UPD_LIFE, update life info after. */ void -split_all_insns (int upd_life) +split_all_insns (void) { sbitmap blocks; bool changed; @@ -2758,17 +2655,7 @@ split_all_insns (int upd_life) allocation, and there are unlikely to be very many nops then anyways. */ if (reload_completed) - { - /* If the no-op set has a REG_UNUSED note, we need - to update liveness information. */ - if (find_reg_note (insn, REG_UNUSED, NULL_RTX)) - { - SET_BIT (blocks, bb->index); - changed = true; - } - /* ??? Is life info affected by deleting edges? */ delete_insn_and_edges (insn); - } } else { @@ -2790,18 +2677,7 @@ split_all_insns (int upd_life) } if (changed) - { - int old_last_basic_block = last_basic_block; - - find_many_sub_basic_blocks (blocks); - - if (old_last_basic_block != last_basic_block && upd_life) - blocks = sbitmap_resize (blocks, last_basic_block, 1); - } - - if (changed && upd_life) - update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES, - PROP_DEATH_NOTES); + find_many_sub_basic_blocks (blocks); #ifdef ENABLE_CHECKING verify_flow_info (); @@ -2813,7 +2689,7 @@ split_all_insns (int upd_life) /* Same as split_all_insns, but do not expect CFG to be available. Used by machine dependent reorg passes. */ -void +unsigned int split_all_insns_noflow (void) { rtx next, insn; @@ -2843,6 +2719,7 @@ split_all_insns_noflow (void) split_insn (insn); } } + return 0; } #ifdef HAVE_peephole2 @@ -2859,7 +2736,7 @@ int peep2_current_count; /* A non-insn marker indicating the last insn of the block. The live_before regset for this element is correct, indicating - global_live_at_end for the block. */ + DF_LIVE_OUT for the block. */ #define PEEP2_EOB pc_rtx /* Return the Nth non-note insn after `current', or return NULL_RTX if it @@ -2989,7 +2866,7 @@ peep2_find_free_register (int from, int to, const char *class_str, if (! HARD_REGNO_MODE_OK (regno, mode)) continue; /* And that we don't create an extra save/restore. */ - if (! call_used_regs[regno] && ! regs_ever_live[regno]) + if (! call_used_regs[regno] && ! df_regs_ever_live_p (regno)) continue; /* And we don't clobber traceback for noreturn functions. */ if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM) @@ -3008,8 +2885,7 @@ peep2_find_free_register (int from, int to, const char *class_str, } if (success) { - for (j = hard_regno_nregs[regno][mode] - 1; j >= 0; j--) - SET_HARD_REG_BIT (*reg_set, regno + j); + add_to_hard_reg_set (reg_set, mode, regno); /* Start the next search with the next register. */ if (++raw_regno >= FIRST_PSEUDO_REGISTER) @@ -3030,36 +2906,22 @@ static void peephole2_optimize (void) { rtx insn, prev; - regset live; + bitmap live; int i; basic_block bb; -#ifdef HAVE_conditional_execution - sbitmap blocks; - bool changed; -#endif bool do_cleanup_cfg = false; - bool do_global_life_update = false; bool do_rebuild_jump_labels = false; + df_set_flags (DF_LR_RUN_DCE); + df_analyze (); + /* Initialize the regsets we're going to use. */ for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i) - peep2_insn_data[i].live_before = ALLOC_REG_SET (®_obstack); - live = ALLOC_REG_SET (®_obstack); - -#ifdef HAVE_conditional_execution - blocks = sbitmap_alloc (last_basic_block); - sbitmap_zero (blocks); - changed = false; -#else - count_or_remove_death_notes (NULL, 1); -#endif + peep2_insn_data[i].live_before = BITMAP_ALLOC (®_obstack); + live = BITMAP_ALLOC (®_obstack); FOR_EACH_BB_REVERSE (bb) { - struct propagate_block_info *pbi; - reg_set_iterator rsi; - unsigned int j; - /* Indicate that all slots except the last holds invalid data. */ for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i) peep2_insn_data[i].insn = NULL_RTX; @@ -3070,14 +2932,9 @@ peephole2_optimize (void) peep2_current = MAX_INSNS_PER_PEEP2; /* Start up propagation. */ - COPY_REG_SET (live, bb->il.rtl->global_live_at_end); - COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live); - -#ifdef HAVE_conditional_execution - pbi = init_propagate_block_info (bb, live, NULL, NULL, 0); -#else - pbi = init_propagate_block_info (bb, live, NULL, NULL, PROP_DEATH_NOTES); -#endif + bitmap_copy (live, DF_LR_OUT (bb)); + df_simulate_artificial_refs_at_end (bb, live); + bitmap_copy (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live); for (insn = BB_END (bb); ; insn = prev) { @@ -3096,7 +2953,7 @@ peephole2_optimize (void) && peep2_insn_data[peep2_current].insn == NULL_RTX) peep2_current_count++; peep2_insn_data[peep2_current].insn = insn; - propagate_one_insn (pbi, insn); + df_simulate_one_insn_backwards (bb, insn, live); COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live); if (RTX_FRAME_RELATED_P (insn)) @@ -3181,7 +3038,7 @@ peephole2_optimize (void) try = emit_insn_after_setloc (try, peep2_insn_data[i].insn, INSN_LOCATOR (peep2_insn_data[i].insn)); before_try = PREV_INSN (insn); - delete_insn_chain (insn, peep2_insn_data[i].insn); + delete_insn_chain (insn, peep2_insn_data[i].insn, false); /* Re-insert the EH_REGION notes. */ if (note || (was_call && nonlocal_goto_handler_labels)) @@ -3223,10 +3080,6 @@ peephole2_optimize (void) = REG_BR_PROB_BASE - nehe->probability; do_cleanup_cfg |= purge_dead_edges (nfte->dest); -#ifdef HAVE_conditional_execution - SET_BIT (blocks, nfte->dest->index); - changed = true; -#endif bb = nfte->src; eh_edge = nehe; } @@ -3238,14 +3091,6 @@ peephole2_optimize (void) } #ifdef HAVE_conditional_execution - /* With conditional execution, we cannot back up the - live information so easily, since the conditional - death data structures are not so self-contained. - So record that we've made a modification to this - block and update life information at the end. */ - SET_BIT (blocks, bb->index); - changed = true; - for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i) peep2_insn_data[i].insn = NULL_RTX; peep2_insn_data[peep2_current].insn = PEEP2_EOB; @@ -3255,7 +3100,7 @@ peephole2_optimize (void) newly created sequence. */ if (++i >= MAX_INSNS_PER_PEEP2 + 1) i = 0; - COPY_REG_SET (live, peep2_insn_data[i].live_before); + bitmap_copy (live, peep2_insn_data[i].live_before); /* Update life information for the new sequence. */ x = try; @@ -3269,16 +3114,14 @@ peephole2_optimize (void) && peep2_insn_data[i].insn == NULL_RTX) peep2_current_count++; peep2_insn_data[i].insn = x; - propagate_one_insn (pbi, x); - COPY_REG_SET (peep2_insn_data[i].live_before, live); + df_insn_rescan (x); + df_simulate_one_insn_backwards (bb, x, live); + bitmap_copy (peep2_insn_data[i].live_before, live); } x = PREV_INSN (x); } while (x != prev); - /* ??? Should verify that LIVE now matches what we - had before the new sequence. */ - peep2_current = i; #endif @@ -3296,91 +3139,105 @@ peephole2_optimize (void) if (insn == BB_HEAD (bb)) break; } - - /* Some peepholes can decide the don't need one or more of their - inputs. If this happens, local life update is not enough. */ - EXECUTE_IF_AND_COMPL_IN_BITMAP (bb->il.rtl->global_live_at_start, live, - 0, j, rsi) - { - do_global_life_update = true; - break; - } - - free_propagate_block_info (pbi); } for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i) - FREE_REG_SET (peep2_insn_data[i].live_before); - FREE_REG_SET (live); - + BITMAP_FREE (peep2_insn_data[i].live_before); + BITMAP_FREE (live); if (do_rebuild_jump_labels) rebuild_jump_labels (get_insns ()); - - /* If we eliminated EH edges, we may be able to merge blocks. Further, - we've changed global life since exception handlers are no longer - reachable. */ - if (do_cleanup_cfg) - { - cleanup_cfg (0); - do_global_life_update = true; - } - if (do_global_life_update) - update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES); -#ifdef HAVE_conditional_execution - else - { - count_or_remove_death_notes (blocks, 1); - update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES); - } - sbitmap_free (blocks); -#endif } #endif /* HAVE_peephole2 */ /* Common predicates for use with define_bypass. */ /* True if the dependency between OUT_INSN and IN_INSN is on the store - data not the address operand(s) of the store. IN_INSN must be - single_set. OUT_INSN must be either a single_set or a PARALLEL with - SETs inside. */ + data not the address operand(s) of the store. IN_INSN and OUT_INSN + must be either a single_set or a PARALLEL with SETs inside. */ int store_data_bypass_p (rtx out_insn, rtx in_insn) { rtx out_set, in_set; + rtx out_pat, in_pat; + rtx out_exp, in_exp; + int i, j; in_set = single_set (in_insn); - gcc_assert (in_set); - - if (!MEM_P (SET_DEST (in_set))) - return false; - - out_set = single_set (out_insn); - if (out_set) + if (in_set) { - if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_set))) + if (!MEM_P (SET_DEST (in_set))) return false; + + out_set = single_set (out_insn); + if (out_set) + { + if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_set))) + return false; + } + else + { + out_pat = PATTERN (out_insn); + + if (GET_CODE (out_pat) != PARALLEL) + return false; + + for (i = 0; i < XVECLEN (out_pat, 0); i++) + { + out_exp = XVECEXP (out_pat, 0, i); + + if (GET_CODE (out_exp) == CLOBBER) + continue; + + gcc_assert (GET_CODE (out_exp) == SET); + + if (reg_mentioned_p (SET_DEST (out_exp), SET_DEST (in_set))) + return false; + } + } } else { - rtx out_pat; - int i; + in_pat = PATTERN (in_insn); + gcc_assert (GET_CODE (in_pat) == PARALLEL); - out_pat = PATTERN (out_insn); - gcc_assert (GET_CODE (out_pat) == PARALLEL); - - for (i = 0; i < XVECLEN (out_pat, 0); i++) + for (i = 0; i < XVECLEN (in_pat, 0); i++) { - rtx exp = XVECEXP (out_pat, 0, i); + in_exp = XVECEXP (in_pat, 0, i); - if (GET_CODE (exp) == CLOBBER) + if (GET_CODE (in_exp) == CLOBBER) continue; - gcc_assert (GET_CODE (exp) == SET); + gcc_assert (GET_CODE (in_exp) == SET); - if (reg_mentioned_p (SET_DEST (exp), SET_DEST (in_set))) + if (!MEM_P (SET_DEST (in_exp))) return false; - } + + out_set = single_set (out_insn); + if (out_set) + { + if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_exp))) + return false; + } + else + { + out_pat = PATTERN (out_insn); + gcc_assert (GET_CODE (out_pat) == PARALLEL); + + for (j = 0; j < XVECLEN (out_pat, 0); j++) + { + out_exp = XVECEXP (out_pat, 0, j); + + if (GET_CODE (out_exp) == CLOBBER) + continue; + + gcc_assert (GET_CODE (out_exp) == SET); + + if (reg_mentioned_p (SET_DEST (out_exp), SET_DEST (in_exp))) + return false; + } + } + } } return true; @@ -3446,16 +3303,19 @@ gate_handle_peephole2 (void) return (optimize > 0 && flag_peephole2); } -static void +static unsigned int rest_of_handle_peephole2 (void) { #ifdef HAVE_peephole2 peephole2_optimize (); #endif + return 0; } -struct tree_opt_pass pass_peephole2 = +struct rtl_opt_pass pass_peephole2 = { + { + RTL_PASS, "peephole2", /* name */ gate_handle_peephole2, /* gate */ rest_of_handle_peephole2, /* execute */ @@ -3467,18 +3327,22 @@ struct tree_opt_pass pass_peephole2 = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 'z' /* letter */ + TODO_df_finish | TODO_verify_rtl_sharing | + TODO_dump_func /* todo_flags_finish */ + } }; -static void +static unsigned int rest_of_handle_split_all_insns (void) { - split_all_insns (1); + split_all_insns (); + return 0; } -struct tree_opt_pass pass_split_all_insns = +struct rtl_opt_pass pass_split_all_insns = { + { + RTL_PASS, "split1", /* name */ NULL, /* gate */ rest_of_handle_split_all_insns, /* execute */ @@ -3490,40 +3354,40 @@ struct tree_opt_pass pass_split_all_insns = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ + TODO_dump_func /* todo_flags_finish */ + } }; -/* The placement of the splitting that we do for shorten_branches - depends on whether regstack is used by the target or not. */ -static bool -gate_do_final_split (void) +static unsigned int +rest_of_handle_split_after_reload (void) { -#if defined (HAVE_ATTR_length) && !defined (STACK_REGS) - return 1; -#else + /* If optimizing, then go ahead and split insns now. */ +#ifndef STACK_REGS + if (optimize > 0) +#endif + split_all_insns (); return 0; -#endif } -struct tree_opt_pass pass_split_for_shorten_branches = +struct rtl_opt_pass pass_split_after_reload = { - "split3", /* name */ - gate_do_final_split, /* gate */ - split_all_insns_noflow, /* execute */ + { + RTL_PASS, + "split2", /* name */ + NULL, /* gate */ + rest_of_handle_split_after_reload, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - TV_SHORTEN_BRANCH, /* tv_id */ + 0, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ + TODO_dump_func /* todo_flags_finish */ + } }; - static bool gate_handle_split_before_regstack (void) { @@ -3542,19 +3406,100 @@ gate_handle_split_before_regstack (void) #endif } -struct tree_opt_pass pass_split_before_regstack = +static unsigned int +rest_of_handle_split_before_regstack (void) { - "split2", /* name */ + split_all_insns (); + return 0; +} + +struct rtl_opt_pass pass_split_before_regstack = +{ + { + RTL_PASS, + "split3", /* name */ gate_handle_split_before_regstack, /* gate */ - rest_of_handle_split_all_insns, /* execute */ + rest_of_handle_split_before_regstack, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + } +}; + +static bool +gate_handle_split_before_sched2 (void) +{ +#ifdef INSN_SCHEDULING + return optimize > 0 && flag_schedule_insns_after_reload; +#else + return 0; +#endif +} + +static unsigned int +rest_of_handle_split_before_sched2 (void) +{ +#ifdef INSN_SCHEDULING + split_all_insns (); +#endif + return 0; +} + +struct rtl_opt_pass pass_split_before_sched2 = +{ + { + RTL_PASS, + "split4", /* name */ + gate_handle_split_before_sched2, /* gate */ + rest_of_handle_split_before_sched2, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_verify_flow | + TODO_dump_func /* todo_flags_finish */ + } +}; + +/* The placement of the splitting that we do for shorten_branches + depends on whether regstack is used by the target or not. */ +static bool +gate_do_final_split (void) +{ +#if defined (HAVE_ATTR_length) && !defined (STACK_REGS) + return 1; +#else + return 0; +#endif +} + +struct rtl_opt_pass pass_split_for_shorten_branches = +{ + { + RTL_PASS, + "split5", /* name */ + gate_do_final_split, /* gate */ + split_all_insns_noflow, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - TV_SHORTEN_BRANCH, /* tv_id */ + 0, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ + TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */ + } }; + +