X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frecog.c;h=7ab6a1de4e0d675c22f455c94ad88bcf4f246c5e;hb=abfd653784390498e51dd5b323f66f78a83be734;hp=840f301e92fbf1799debafec8a153fa9ddf7fcde;hpb=8b9ad4fb7aa15424953817b0ace135f6a8056fd1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/recog.c b/gcc/recog.c index 840f301e92f..7ab6a1de4e0 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" @@ -39,8 +40,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "basic-block.h" #include "output.h" #include "reload.h" +#include "target.h" #include "timevar.h" #include "tree-pass.h" +#include "df.h" #ifndef STACK_PUSH_CODE #ifdef STACK_GROWS_DOWNWARD @@ -58,8 +61,15 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #endif #endif -static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx); -static rtx *find_single_use_1 (rtx, rtx *); +#ifndef HAVE_ATTR_enabled +static inline bool +get_attr_enabled (rtx insn ATTRIBUTE_UNUSED) +{ + return true; +} +#endif + +static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx, bool); static void validate_replace_src_1 (rtx *, void *); static rtx split_insn (rtx); @@ -136,10 +146,10 @@ check_asm_operands (rtx x) if (noperands == 0) return 1; - operands = alloca (noperands * sizeof (rtx)); - constraints = alloca (noperands * sizeof (char *)); + operands = XALLOCAVEC (rtx, noperands); + constraints = XALLOCAVEC (const char *, noperands); - 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 +174,7 @@ typedef struct change_t int old_code; rtx *loc; rtx old; + bool unshare; } change_t; static change_t *changes; @@ -172,7 +183,7 @@ static int changes_allocated; static int num_changes = 0; /* Validate a proposed change to OBJECT. LOC is the location in the rtl - at which NEW will be placed. If OBJECT is zero, no validation is done, + at which NEW_RTX will be placed. If OBJECT is zero, no validation is done, the change is simply made. Two types of objects are supported: If OBJECT is a MEM, memory_address_p @@ -189,17 +200,17 @@ 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_rtx, bool in_group, bool unshare) { rtx old = *loc; - if (old == new || rtx_equal_p (old, new)) + if (old == new_rtx || rtx_equal_p (old, new_rtx)) return 1; gcc_assert (in_group != 0 || num_changes == 0); - *loc = new; + *loc = new_rtx; /* Save the information describing this change. */ if (num_changes >= changes_allocated) @@ -211,12 +222,13 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) else changes_allocated *= 2; - changes = xrealloc (changes, sizeof (change_t) * changes_allocated); + changes = XRESIZEVEC (change_t, changes, changes_allocated); } 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 +249,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_rtx, bool in_group) { - return (MEM_P (*x) && MEM_VOLATILE_P (*x)); + return validate_change_1 (object, loc, new_rtx, 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_rtx, 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_rtx, 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 +435,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 unnecessary 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; } @@ -486,96 +513,25 @@ cancel_changes (int num) num_changes = num; } -/* Replace every occurrence of FROM in X with TO. Mark each change with - validate_change passing OBJECT. */ +/* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting + rtx. */ static void -validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) +simplify_while_replacing (rtx *loc, rtx to, rtx object, + enum machine_mode op0_mode) { - int i, j; - const char *fmt; rtx x = *loc; - enum rtx_code code; - enum machine_mode op0_mode = VOIDmode; - int prev_changes = num_changes; - rtx new; - - if (!x) - return; - - code = GET_CODE (x); - fmt = GET_RTX_FORMAT (code); - if (fmt[0] == 'e') - op0_mode = GET_MODE (XEXP (x, 0)); - - /* X matches FROM if it is the same rtx or they are both referring to the - same register in the same mode. Avoid calling rtx_equal_p unless the - operands look similar. */ - - if (x == from - || (REG_P (x) && REG_P (from) - && GET_MODE (x) == GET_MODE (from) - && REGNO (x) == REGNO (from)) - || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) - && rtx_equal_p (x, from))) - { - validate_change (object, loc, to, 1); - return; - } - - /* Call ourself recursively to perform the replacements. - We must not replace inside already replaced expression, otherwise we - get infinite recursion for replacements like (reg X)->(subreg (reg X)) - done by regmove, so we must special case shared ASM_OPERANDS. */ - - if (GET_CODE (x) == PARALLEL) - { - for (j = XVECLEN (x, 0) - 1; j >= 0; j--) - { - if (j && GET_CODE (XVECEXP (x, 0, j)) == SET - && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS) - { - /* Verify that operands are really shared. */ - gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) - == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP - (x, 0, j)))); - validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)), - from, to, object); - } - else - validate_replace_rtx_1 (&XVECEXP (x, 0, j), from, to, object); - } - } - else - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - validate_replace_rtx_1 (&XEXP (x, i), from, to, object); - else if (fmt[i] == 'E') - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object); - } - - /* If we didn't substitute, there is nothing more to do. */ - if (num_changes == prev_changes) - return; - - /* Allow substituted expression to have different mode. This is used by - regmove to change mode of pseudo register. */ - if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode) - op0_mode = GET_MODE (XEXP (x, 0)); - - /* Do changes needed to keep rtx consistent. Don't do any other - simplifications, as it is not our job. */ + enum rtx_code code = GET_CODE (x); + rtx new_rtx; if (SWAPPABLE_OPERANDS_P (x) && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))) { - validate_change (object, loc, - gen_rtx_fmt_ee (COMMUTATIVE_ARITH_P (x) ? code - : swap_condition (code), - GET_MODE (x), XEXP (x, 1), - XEXP (x, 0)), 1); + validate_unshare_change (object, loc, + gen_rtx_fmt_ee (COMMUTATIVE_ARITH_P (x) ? code + : swap_condition (code), + GET_MODE (x), XEXP (x, 1), + XEXP (x, 0)), 1); x = *loc; code = GET_CODE (x); } @@ -606,25 +562,25 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) case SIGN_EXTEND: if (GET_MODE (XEXP (x, 0)) == VOIDmode) { - new = simplify_gen_unary (code, GET_MODE (x), XEXP (x, 0), + new_rtx = simplify_gen_unary (code, GET_MODE (x), XEXP (x, 0), op0_mode); /* If any of the above failed, substitute in something that we know won't be recognized. */ - if (!new) - new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); - validate_change (object, loc, new, 1); + if (!new_rtx) + new_rtx = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + validate_change (object, loc, new_rtx, 1); } break; case SUBREG: /* All subregs possible to simplify should be simplified. */ - new = simplify_subreg (GET_MODE (x), SUBREG_REG (x), op0_mode, + new_rtx = simplify_subreg (GET_MODE (x), SUBREG_REG (x), op0_mode, SUBREG_BYTE (x)); /* Subregs of VOIDmode operands are incorrect. */ - if (!new && GET_MODE (SUBREG_REG (x)) == VOIDmode) - new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); - if (new) - validate_change (object, loc, new, 1); + if (!new_rtx && GET_MODE (SUBREG_REG (x)) == VOIDmode) + new_rtx = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + if (new_rtx) + validate_change (object, loc, new_rtx, 1); break; case ZERO_EXTRACT: case SIGN_EXTRACT: @@ -688,22 +644,132 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) } } +/* Replace every occurrence of FROM in X with TO. Mark each change with + validate_change passing OBJECT. */ + +static void +validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object, + bool simplify) +{ + int i, j; + const char *fmt; + rtx x = *loc; + enum rtx_code code; + enum machine_mode op0_mode = VOIDmode; + int prev_changes = num_changes; + + if (!x) + return; + + code = GET_CODE (x); + fmt = GET_RTX_FORMAT (code); + if (fmt[0] == 'e') + op0_mode = GET_MODE (XEXP (x, 0)); + + /* X matches FROM if it is the same rtx or they are both referring to the + same register in the same mode. Avoid calling rtx_equal_p unless the + operands look similar. */ + + if (x == from + || (REG_P (x) && REG_P (from) + && GET_MODE (x) == GET_MODE (from) + && REGNO (x) == REGNO (from)) + || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) + && rtx_equal_p (x, from))) + { + validate_unshare_change (object, loc, to, 1); + return; + } + + /* Call ourself recursively to perform the replacements. + We must not replace inside already replaced expression, otherwise we + get infinite recursion for replacements like (reg X)->(subreg (reg X)) + done by regmove, so we must special case shared ASM_OPERANDS. */ + + if (GET_CODE (x) == PARALLEL) + { + for (j = XVECLEN (x, 0) - 1; j >= 0; j--) + { + if (j && GET_CODE (XVECEXP (x, 0, j)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS) + { + /* Verify that operands are really shared. */ + gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) + == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP + (x, 0, j)))); + validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)), + from, to, object, simplify); + } + else + validate_replace_rtx_1 (&XVECEXP (x, 0, j), from, to, object, + simplify); + } + } + else + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + validate_replace_rtx_1 (&XEXP (x, i), from, to, object, simplify); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object, + simplify); + } + + /* If we didn't substitute, there is nothing more to do. */ + if (num_changes == prev_changes) + return; + + /* Allow substituted expression to have different mode. This is used by + regmove to change mode of pseudo register. */ + if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode) + op0_mode = GET_MODE (XEXP (x, 0)); + + /* Do changes needed to keep rtx consistent. Don't do any other + simplifications, as it is not our job. */ + if (simplify) + simplify_while_replacing (loc, to, object, op0_mode); +} + /* Try replacing every occurrence of FROM in INSN with TO. After all changes have been made, validate by seeing if INSN is still valid. */ int validate_replace_rtx (rtx from, rtx to, rtx insn) { - validate_replace_rtx_1 (&PATTERN (insn), from, to, insn); + validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true); + return apply_change_group (); +} + +/* Try replacing every occurrence of FROM in WHERE with TO. Assume that WHERE + is a part of INSN. After all changes have been made, validate by seeing if + INSN is still valid. + validate_replace_rtx (from, to, insn) is equivalent to + validate_replace_rtx_part (from, to, &PATTERN (insn), insn). */ + +int +validate_replace_rtx_part (rtx from, rtx to, rtx *where, rtx insn) +{ + validate_replace_rtx_1 (where, from, to, insn, true); return apply_change_group (); } +/* Same as above, but do not simplify rtx afterwards. */ +int +validate_replace_rtx_part_nosimplify (rtx from, rtx to, rtx *where, + rtx insn) +{ + validate_replace_rtx_1 (where, from, to, insn, false); + return apply_change_group (); + +} + /* Try replacing every occurrence of FROM in INSN with TO. */ void validate_replace_rtx_group (rtx from, rtx to, rtx insn) { - validate_replace_rtx_1 (&PATTERN (insn), from, to, insn); + validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true); } /* Function called by note_uses to replace used subexpressions. */ @@ -720,7 +786,7 @@ validate_replace_src_1 (rtx *x, void *data) struct validate_replace_src_data *d = (struct validate_replace_src_data *) data; - validate_replace_rtx_1 (x, d->from, d->to, d->insn); + validate_replace_rtx_1 (x, d->from, d->to, d->insn, true); } /* Try replacing every occurrence of FROM in INSN with TO, avoiding @@ -736,6 +802,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 +862,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 +1327,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 +1412,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 +1448,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 +1469,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 +1512,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 +1535,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. @@ -1644,7 +1591,7 @@ asm_operand_ok (rtx op, const char *constraint) result = 1; break; - case 'm': + case TARGET_MEM_CONSTRAINT: case 'V': /* non-offsettable */ if (memory_operand (op, VOIDmode)) result = 1; @@ -1656,7 +1603,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. @@ -1778,16 +1725,14 @@ asm_operand_ok (rtx op, const char *constraint) result = 1; } #ifdef EXTRA_CONSTRAINT_STR + else if (EXTRA_MEMORY_CONSTRAINT (c, constraint)) + /* Every memory operand can be reloaded to fit. */ + result = result || memory_operand (op, VOIDmode); + else if (EXTRA_ADDRESS_CONSTRAINT (c, constraint)) + /* Every address operand can be reloaded to fit. */ + result = result || address_operand (op, VOIDmode); else if (EXTRA_CONSTRAINT_STR (op, c, constraint)) result = 1; - else if (EXTRA_MEMORY_CONSTRAINT (c, constraint) - /* Every memory operand can be reloaded to fit. */ - && memory_operand (op, VOIDmode)) - result = 1; - else if (EXTRA_ADDRESS_CONSTRAINT (c, constraint) - /* Every address operand can be reloaded to fit. */ - && address_operand (op, VOIDmode)) - result = 1; #endif break; } @@ -1959,8 +1904,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. */ @@ -2012,11 +1966,9 @@ extract_insn (rtx insn) int noperands; rtx body = PATTERN (insn); - recog_data.insn = NULL; recog_data.n_operands = 0; recog_data.n_alternatives = 0; recog_data.n_dups = 0; - which_alternative = -1; switch (GET_CODE (body)) { @@ -2053,7 +2005,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]; @@ -2096,6 +2048,22 @@ extract_insn (rtx insn) : OP_IN); gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES); + + if (INSN_CODE (insn) < 0) + for (i = 0; i < recog_data.n_alternatives; i++) + recog_data.alternative_enabled_p[i] = true; + else + { + recog_data.insn = insn; + for (i = 0; i < recog_data.n_alternatives; i++) + { + which_alternative = i; + recog_data.alternative_enabled_p[i] = get_attr_enabled (insn); + } + } + + recog_data.insn = NULL; + which_alternative = -1; } /* After calling extract_insn, you can use this function to extract some @@ -2125,6 +2093,12 @@ preprocess_constraints (void) op_alt[j].matches = -1; op_alt[j].matched = -1; + if (!recog_data.alternative_enabled_p[j]) + { + p = skip_alternative (p); + continue; + } + if (*p == '\0' || *p == ',') { op_alt[j].anything_ok = 1; @@ -2174,7 +2148,7 @@ preprocess_constraints (void) } continue; - case 'm': + case TARGET_MEM_CONSTRAINT: op_alt[j].memory_ok = 1; break; case '<': @@ -2196,7 +2170,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 +2191,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; } @@ -2262,7 +2237,7 @@ preprocess_constraints (void) struct funny_match { - int this, other; + int this_op, other; }; int @@ -2293,6 +2268,17 @@ constrain_operands (int strict) int lose = 0; funny_match_index = 0; + if (!recog_data.alternative_enabled_p[which_alternative]) + { + int i; + + for (i = 0; i < recog_data.n_operands; i++) + constraints[i] = skip_alternative (constraints[i]); + + which_alternative++; + continue; + } + for (opno = 0; opno < recog_data.n_operands; opno++) { rtx op = recog_data.operand[opno]; @@ -2401,7 +2387,7 @@ constrain_operands (int strict) output op is the one that will be printed. */ if (val == 2 && strict > 0) { - funny_match[funny_match_index].this = opno; + funny_match[funny_match_index].this_op = opno; funny_match[funny_match_index++].other = match; } } @@ -2446,7 +2432,7 @@ constrain_operands (int strict) win = 1; break; - case 'm': + case TARGET_MEM_CONSTRAINT: /* Memory operands must be valid, to the extent required by STRICT. */ if (MEM_P (op)) @@ -2634,7 +2620,7 @@ constrain_operands (int strict) while (--funny_match_index >= 0) { recog_data.operand[funny_match[funny_match_index].other] - = recog_data.operand[funny_match[funny_match_index].this]; + = recog_data.operand[funny_match[funny_match_index].this_op]; } return 1; @@ -2664,21 +2650,13 @@ reg_fits_class_p (rtx operand, enum reg_class cl, int offset, enum machine_mode mode) { int regno = REGNO (operand); - 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; + if (cl == NO_REGS) + 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 @@ -2691,10 +2669,29 @@ split_insn (rtx insn) /* Split insns here to get max fine-grain parallelism. */ rtx first = PREV_INSN (insn); rtx last = try_split (PATTERN (insn), insn, 1); + rtx insn_set, last_set, note; if (last == insn) return NULL_RTX; + /* If the original instruction was a single set that was known to be + equivalent to a constant, see if we can say the same about the last + instruction in the split sequence. The two instructions must set + the same destination. */ + insn_set = single_set (insn); + if (insn_set) + { + last_set = single_set (last); + if (last_set && rtx_equal_p (SET_DEST (last_set), SET_DEST (insn_set))) + { + note = find_reg_equal_equiv_note (insn); + if (note && CONSTANT_P (XEXP (note, 0))) + set_unique_reg_note (last, REG_EQUAL, XEXP (note, 0)); + else if (CONSTANT_P (SET_SRC (insn_set))) + set_unique_reg_note (last, REG_EQUAL, SET_SRC (insn_set)); + } + } + /* try_split returns the NOTE that INSN became. */ SET_INSN_DELETED (insn); @@ -2712,13 +2709,14 @@ split_insn (rtx insn) first = NEXT_INSN (first); } } + return last; } /* 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; @@ -2733,6 +2731,7 @@ split_all_insns (int upd_life) rtx insn, next; bool finish = false; + rtl_profile_for_bb (bb); for (insn = BB_HEAD (bb); !finish ; insn = next) { /* Can't use `next_real_insn' because that might go across @@ -2745,7 +2744,7 @@ split_all_insns (int upd_life) /* Don't split no-op move insns. These should silently disappear later in final. Splitting such insns would - break the code that handles REG_NO_CONFLICT blocks. */ + break the code that handles LIBCALL blocks. */ if (set && set_noop_p (set)) { /* Nops get in the way while scheduling, so delete them @@ -2754,17 +2753,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 { @@ -2785,19 +2774,9 @@ split_all_insns (int upd_life) } } + default_rtl_profile (); 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 (); @@ -2809,7 +2788,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; @@ -2821,7 +2800,7 @@ split_all_insns_noflow (void) { /* Don't split no-op move insns. These should silently disappear later in final. Splitting such insns would - break the code that handles REG_NO_CONFLICT blocks. */ + break the code that handles LIBCALL blocks. */ rtx set = single_set (insn); if (set && set_noop_p (set)) { @@ -2839,6 +2818,7 @@ split_all_insns_noflow (void) split_insn (insn); } } + return 0; } #ifdef HAVE_peephole2 @@ -2855,7 +2835,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 @@ -2978,6 +2958,9 @@ peep2_find_free_register (int from, int to, const char *class_str, /* Don't allocate fixed registers. */ if (fixed_regs[regno]) continue; + /* Don't allocate global registers. */ + if (global_regs[regno]) + continue; /* Make sure the register is of the right class. */ if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno)) continue; @@ -2985,8 +2968,11 @@ 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; + if (! targetm.hard_regno_scratch_ok (regno)) continue; + /* And we don't clobber traceback for noreturn functions. */ if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM) && (! reload_completed || frame_pointer_needed)) @@ -3004,8 +2990,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) @@ -3023,39 +3008,26 @@ peep2_find_free_register (int from, int to, const char *class_str, /* Perform the peephole2 optimization pass. */ static void -peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) +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; - + rtl_profile_for_bb (bb); /* 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; @@ -3066,21 +3038,16 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) 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) { prev = PREV_INSN (insn); if (INSN_P (insn)) { - rtx try, before_try, x; + rtx attempt, before_try, x; int match_len; rtx note; bool was_call = false; @@ -3092,7 +3059,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) && 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 (bb, insn, live); COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live); if (RTX_FRAME_RELATED_P (insn)) @@ -3101,13 +3068,13 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) substitution would lose the REG_FRAME_RELATED_EXPR that is attached. */ peep2_current_count = 0; - try = NULL; + attempt = NULL; } else /* Match the peephole. */ - try = peephole2_insns (PATTERN (insn), insn, &match_len); + attempt = peephole2_insns (PATTERN (insn), insn, &match_len); - if (try != NULL) + if (attempt != NULL) { /* If we are splitting a CALL_INSN, look for the CALL_INSN in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other @@ -3125,7 +3092,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) continue; was_call = true; - new_insn = try; + new_insn = attempt; while (new_insn != NULL_RTX) { if (CALL_P (new_insn)) @@ -3145,10 +3112,9 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) { case REG_NORETURN: case REG_SETJMP: - REG_NOTES (new_insn) - = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), - XEXP (note, 0), - REG_NOTES (new_insn)); + add_reg_note (new_insn, REG_NOTE_KIND (note), + XEXP (note, 0)); + break; default: /* Discard all other reg notes. */ break; @@ -3174,10 +3140,11 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) REG_EH_REGION, NULL_RTX); /* Replace the old sequence with the new. */ - try = emit_insn_after_setloc (try, peep2_insn_data[i].insn, - INSN_LOCATOR (peep2_insn_data[i].insn)); + attempt = emit_insn_after_setloc (attempt, + 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)) @@ -3189,17 +3156,14 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) break; - for (x = try ; x != before_try ; x = PREV_INSN (x)) + for (x = attempt ; x != before_try ; x = PREV_INSN (x)) if (CALL_P (x) || (flag_non_call_exceptions && may_trap_p (PATTERN (x)) && !find_reg_note (x, REG_EH_REGION, NULL))) { if (note) - REG_NOTES (x) - = gen_rtx_EXPR_LIST (REG_EH_REGION, - XEXP (note, 0), - REG_NOTES (x)); + add_reg_note (x, REG_EH_REGION, XEXP (note, 0)); if (x != BB_END (bb) && eh_edge) { @@ -3219,10 +3183,6 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) = 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; } @@ -3234,14 +3194,6 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) } #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; @@ -3251,10 +3203,10 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) 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; + x = attempt; do { if (INSN_P (x)) @@ -3265,22 +3217,20 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) && 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 (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 /* If we generated a jump instruction, it won't have JUMP_LABEL set. Recompute after we're done. */ - for (x = try; x != before_try; x = PREV_INSN (x)) + for (x = attempt; x != before_try; x = PREV_INSN (x)) if (JUMP_P (x)) { do_rebuild_jump_labels = true; @@ -3292,91 +3242,106 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) 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); } + default_rtl_profile (); 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; @@ -3442,16 +3407,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 (dump_file); + 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 */ @@ -3463,18 +3431,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 */ @@ -3486,40 +3458,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) { @@ -3538,19 +3510,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 */ - 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_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 */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */ + } +}; + +