X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frecog.c;h=138b03bcd19ec44540b1e2caf3d377de7519119e;hb=d3832055fda2ca4c70c534b5638eb8f018ea3225;hp=1b81704d5375dd19395e6e7e10f838fe9f9e3ad1;hpb=a2c6f0b7da35eadcfafa42e5ad04647c2696fbb4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/recog.c b/gcc/recog.c index 1b81704d537..138b03bcd19 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -1,13 +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, 2006, 2007 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 @@ -16,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" @@ -41,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 @@ -60,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); @@ -69,7 +77,7 @@ static rtx split_insn (rtx); This should be 0 if you are generating rtl, such as if you are calling the functions in optabs.c and expmed.c (most of the time). This should be 1 if all valid insns need to be recognized, - such as in regclass.c and final.c and reload.c. + such as in reginfo.c and final.c and reload.c. init_recog and init_recog_no_volatile are responsible for setting this. */ @@ -138,8 +146,8 @@ 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, NULL); @@ -148,10 +156,7 @@ check_asm_operands (rtx x) const char *c = constraints[i]; if (c[0] == '%') c++; - if (ISDIGIT ((unsigned char) c[0]) && c[1] == '\0') - c = constraints[c[0] - '0']; - - if (! asm_operand_ok (operands[i], c)) + if (! asm_operand_ok (operands[i], c, constraints)) return 0; } @@ -166,6 +171,7 @@ typedef struct change_t int old_code; rtx *loc; rtx old; + bool unshare; } change_t; static change_t *changes; @@ -174,7 +180,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 @@ -191,17 +197,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) @@ -213,12 +219,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)) { @@ -239,6 +246,25 @@ 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. */ + +bool +validate_change (rtx object, rtx *loc, rtx new_rtx, bool in_group) +{ + return validate_change_1 (object, loc, new_rtx, in_group, false); +} + +/* Wrapper for validate_change_1 without the UNSHARE argument defaulting + UNSHARE to true. */ + +bool +validate_unshare_change (rtx object, rtx *loc, rtx new_rtx, bool in_group) +{ + return validate_change_1 (object, loc, new_rtx, in_group, true); +} + + /* 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. @@ -353,6 +379,16 @@ verify_changes (int num) if (! memory_address_p (GET_MODE (object), XEXP (object, 0))) break; } + else if (REG_P (changes[i].old) + && asm_noperands (PATTERN (object)) > 0 + && REG_EXPR (changes[i].old) != NULL_TREE + && DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (changes[i].old)) + && DECL_REGISTER (REG_EXPR (changes[i].old))) + { + /* Don't allow changes of hard register operands to inline + assemblies if they have been defined as register asm ("x"). */ + break; + } else if (insn_invalid_p (object)) { rtx pat = PATTERN (object); @@ -406,22 +442,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; } @@ -471,96 +520,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); } @@ -572,13 +550,13 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) simplify_gen_binary to try to simplify it. ??? We may want later to remove this, once simplification is separated from this function. */ - if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to) + if (CONST_INT_P (XEXP (x, 1)) && XEXP (x, 1) == to) validate_change (object, loc, simplify_gen_binary (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1); break; case MINUS: - if (GET_CODE (XEXP (x, 1)) == CONST_INT + if (CONST_INT_P (XEXP (x, 1)) || GET_CODE (XEXP (x, 1)) == CONST_DOUBLE) validate_change (object, loc, simplify_gen_binary @@ -591,25 +569,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: @@ -619,8 +597,8 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) happen, we might just fail in some cases). */ if (MEM_P (XEXP (x, 0)) - && GET_CODE (XEXP (x, 1)) == CONST_INT - && GET_CODE (XEXP (x, 2)) == CONST_INT + && CONST_INT_P (XEXP (x, 1)) + && CONST_INT_P (XEXP (x, 2)) && !mode_dependent_address_p (XEXP (XEXP (x, 0), 0)) && !MEM_VOLATILE_P (XEXP (x, 0))) { @@ -673,22 +651,143 @@ 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 subexpression LOC of INSN + with TO. After all changes have been made, validate by seeing + if INSN is still valid. */ + +int +validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc) +{ + validate_replace_rtx_1 (loc, from, to, insn, true); + return apply_change_group (); +} + /* 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. */ @@ -705,7 +804,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 @@ -781,168 +880,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 @@ -975,7 +912,7 @@ general_operand (rtx op, enum machine_mode mode) && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) return 0; - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && mode != VOIDmode && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op)) return 0; @@ -1152,7 +1089,7 @@ immediate_operand (rtx op, enum machine_mode mode) && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) return 0; - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && mode != VOIDmode && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op)) return 0; @@ -1169,7 +1106,7 @@ immediate_operand (rtx op, enum machine_mode mode) int const_int_operand (rtx op, enum machine_mode mode) { - if (GET_CODE (op) != CONST_INT) + if (!CONST_INT_P (op)) return 0; if (mode != VOIDmode @@ -1192,7 +1129,7 @@ const_double_operand (rtx op, enum machine_mode mode) && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) return 0; - return ((GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT) + return ((GET_CODE (op) == CONST_DOUBLE || CONST_INT_P (op)) && (mode == VOIDmode || GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)); } @@ -1219,7 +1156,7 @@ nonmemory_operand (rtx op, enum machine_mode mode) && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) return 0; - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && mode != VOIDmode && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op)) return 0; @@ -1286,7 +1223,7 @@ push_operand (rtx op, enum machine_mode mode) if (GET_CODE (op) != PRE_MODIFY || GET_CODE (XEXP (op, 1)) != PLUS || XEXP (XEXP (op, 1), 0) != XEXP (op, 0) - || GET_CODE (XEXP (XEXP (op, 1), 1)) != CONST_INT + || !CONST_INT_P (XEXP (XEXP (op, 1), 1)) #ifdef STACK_GROWS_DOWNWARD || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size #else @@ -1327,11 +1264,15 @@ pop_operand (rtx op, enum machine_mode mode) int memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr) { +#ifdef GO_IF_LEGITIMATE_ADDRESS GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); return 0; win: return 1; +#else + return targetm.legitimate_address_p (mode, addr, 0); +#endif } /* Return 1 if OP is a valid memory reference with mode MODE, @@ -1383,7 +1324,7 @@ indirect_operand (rtx op, enum machine_mode mode) return ((offset == 0 && general_operand (XEXP (inner, 0), Pmode)) || (GET_CODE (XEXP (inner, 0)) == PLUS - && GET_CODE (XEXP (XEXP (inner, 0), 1)) == CONST_INT + && CONST_INT_P (XEXP (XEXP (inner, 0), 1)) && INTVAL (XEXP (XEXP (inner, 0), 1)) == -offset && general_operand (XEXP (XEXP (inner, 0), 0), Pmode))); } @@ -1393,6 +1334,32 @@ indirect_operand (rtx op, enum machine_mode mode) && general_operand (XEXP (op, 0), Pmode)); } +/* Return 1 if this is an ordered comparison operator (not including + ORDERED and UNORDERED). */ + +int +ordered_comparison_operator (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && GET_MODE (op) != mode) + return false; + switch (GET_CODE (op)) + { + case EQ: + case NE: + case LT: + case LTU: + case LE: + case LEU: + case GT: + case GTU: + case GE: + case GEU: + return true; + default: + return false; + } +} + /* Return 1 if this is a comparison operator. This allows the use of MATCH_OPERATOR to recognize all the branch insns. */ @@ -1408,7 +1375,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)) { @@ -1619,14 +1586,7 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, } if (loc) - { -#ifdef USE_MAPPED_LOCATION - *loc = ASM_OPERANDS_SOURCE_LOCATION (asmop); -#else - loc->file = ASM_OPERANDS_SOURCE_FILE (asmop); - loc->line = ASM_OPERANDS_SOURCE_LINE (asmop); -#endif - } + *loc = ASM_OPERANDS_SOURCE_LOCATION (asmop); return ASM_OPERANDS_TEMPLATE (asmop); } @@ -1635,7 +1595,7 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs, Return > 0 if ok, = 0 if bad, < 0 if inconclusive. */ int -asm_operand_ok (rtx op, const char *constraint) +asm_operand_ok (rtx op, const char *constraint, const char **constraints) { int result = 0; @@ -1663,15 +1623,29 @@ asm_operand_ok (rtx op, const char *constraint) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - /* For best results, our caller should have given us the - proper matching constraint, but we can't actually fail - the check if they didn't. Indicate that results are - inconclusive. */ - do - constraint++; - while (ISDIGIT (*constraint)); - if (! result) - result = -1; + /* If caller provided constraints pointer, look up + the maching constraint. Otherwise, our caller should have + given us the proper matching constraint, but we can't + actually fail the check if they didn't. Indicate that + results are inconclusive. */ + if (constraints) + { + char *end; + unsigned long match; + + match = strtoul (constraint, &end, 10); + if (!result) + result = asm_operand_ok (op, constraints[match], NULL); + constraint = (const char *) end; + } + else + { + do + constraint++; + while (ISDIGIT (*constraint)); + if (! result) + result = -1; + } continue; case 'p': @@ -1679,7 +1653,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; @@ -1691,7 +1665,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. @@ -1733,7 +1707,7 @@ asm_operand_ok (rtx op, const char *constraint) break; case 's': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)) break; @@ -1745,49 +1719,49 @@ asm_operand_ok (rtx op, const char *constraint) break; case 'n': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)) result = 1; break; case 'I': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint)) result = 1; break; case 'J': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint)) result = 1; break; case 'K': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint)) result = 1; break; case 'L': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint)) result = 1; break; case 'M': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint)) result = 1; break; case 'N': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint)) result = 1; break; case 'O': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint)) result = 1; break; case 'P': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint)) result = 1; break; @@ -1813,16 +1787,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; } @@ -2056,11 +2028,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)) { @@ -2140,6 +2110,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 @@ -2169,6 +2155,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; @@ -2218,7 +2210,7 @@ preprocess_constraints (void) } continue; - case 'm': + case TARGET_MEM_CONSTRAINT: op_alt[j].memory_ok = 1; break; case '<': @@ -2307,7 +2299,7 @@ preprocess_constraints (void) struct funny_match { - int this, other; + int this_op, other; }; int @@ -2338,6 +2330,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]; @@ -2446,7 +2449,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; } } @@ -2491,7 +2494,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)) @@ -2544,7 +2547,7 @@ constrain_operands (int strict) break; case 's': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)) break; @@ -2554,7 +2557,7 @@ constrain_operands (int strict) break; case 'n': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)) win = 1; @@ -2568,7 +2571,7 @@ constrain_operands (int strict) case 'N': case 'O': case 'P': - if (GET_CODE (op) == CONST_INT + if (CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) win = 1; break; @@ -2679,7 +2682,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; @@ -2728,10 +2731,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); @@ -2749,13 +2771,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; @@ -2770,6 +2793,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 @@ -2782,7 +2806,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 @@ -2791,17 +2815,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 { @@ -2822,19 +2836,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 (); @@ -2858,7 +2862,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)) { @@ -2893,7 +2897,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 @@ -3016,6 +3020,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; @@ -3023,8 +3030,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)) @@ -3057,67 +3067,61 @@ peep2_find_free_register (int from, int to, const char *class_str, return NULL_RTX; } +/* Forget all currently tracked instructions, only remember current + LIVE regset. */ + +static void +peep2_reinit_state (regset live) +{ + int i; + + /* 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; + peep2_current_count = 0; + + /* Indicate that the last slot contains live_after data. */ + peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB; + peep2_current = MAX_INSNS_PER_PEEP2; + + COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live); +} + /* Perform the peephole2 optimization pass. */ 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; - peep2_current_count = 0; - - /* Indicate that the last slot contains live_after data. */ - peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB; - peep2_current = MAX_INSNS_PER_PEEP2; + rtl_profile_for_bb (bb); /* 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_initialize_backwards (bb, live); + peep2_reinit_state (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; @@ -3129,7 +3133,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)) @@ -3137,14 +3141,14 @@ peephole2_optimize (void) /* If an insn has RTX_FRAME_RELATED_P set, peephole substitution would lose the REG_FRAME_RELATED_EXPR that is attached. */ - peep2_current_count = 0; - try = NULL; + peep2_reinit_state (live); + 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 @@ -3162,7 +3166,7 @@ peephole2_optimize (void) continue; was_call = true; - new_insn = try; + new_insn = attempt; while (new_insn != NULL_RTX) { if (CALL_P (new_insn)) @@ -3182,10 +3186,9 @@ peephole2_optimize (void) { 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; @@ -3211,10 +3214,11 @@ peephole2_optimize (void) 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)) @@ -3226,17 +3230,14 @@ peephole2_optimize (void) 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) { @@ -3256,10 +3257,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; } @@ -3271,14 +3268,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; @@ -3288,10 +3277,10 @@ 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; + x = attempt; do { if (INSN_P (x)) @@ -3302,22 +3291,20 @@ 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 /* 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; @@ -3329,44 +3316,14 @@ 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); } + 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 */ @@ -3533,8 +3490,10 @@ rest_of_handle_peephole2 (void) 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 */ @@ -3546,64 +3505,67 @@ 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 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 */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* 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 */ + } }; -/* 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 */ + TV_NONE, /* 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) { @@ -3622,19 +3584,98 @@ 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) +{ + split_all_insns (); + return 0; +} + +struct rtl_opt_pass pass_split_before_regstack = { - "split2", /* name */ + { + 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 */ + TV_NONE, /* 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_NONE, /* 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 */ + TV_NONE, /* 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 */ + } };