X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frecog.c;h=cd47155ad4eaf016bd00532a521c234def2a3948;hb=97ba552253e2473141a58a0829fe797af9660601;hp=12b0fbf68a15496c26933514ed56d782af4a62a1;hpb=7151fd0e46078735d19ba3c266e02bc66e5bcc84;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/recog.c b/gcc/recog.c index 12b0fbf68a1..cd47155ad4e 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 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, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" @@ -31,6 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, 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,6 +40,10 @@ Software Foundation, 59 Temple Place - Suite 330, 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 @@ -56,8 +61,15 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #endif #endif +#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); -static rtx *find_single_use_1 (rtx, rtx *); static void validate_replace_src_1 (rtx *, void *); static rtx split_insn (rtx); @@ -107,22 +119,6 @@ init_recog (void) volatile_ok = 1; } -/* Try recognizing the instruction INSN, - and return the code number that results. - Remember the code so that repeated calls do not - need to spend the time for actual rerecognition. - - This function is the normal interface to instruction recognition. - The automatically-generated function `recog' is normally called - through this one. (The only exception is in combine.c.) */ - -int -recog_memoized_1 (rtx insn) -{ - if (INSN_CODE (insn) < 0) - INSN_CODE (insn) = recog (PATTERN (insn), insn, 0); - return INSN_CODE (insn); -} /* Check that X is an insn-body for an `asm' with operands and that the operands mentioned in it are legitimate. */ @@ -150,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++) { @@ -178,6 +174,7 @@ typedef struct change_t int old_code; rtx *loc; rtx old; + bool unshare; } change_t; static change_t *changes; @@ -186,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 @@ -203,18 +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; - if (in_group == 0 && num_changes != 0) - abort (); + gcc_assert (in_group != 0 || num_changes == 0); - *loc = new; + *loc = new_rtx; /* Save the information describing this change. */ if (num_changes >= changes_allocated) @@ -226,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)) { @@ -252,6 +249,48 @@ 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. + + 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. */ @@ -311,11 +350,11 @@ num_changes_pending (void) return num_changes; } -/* Apply a group of changes previously issued with `validate_change'. +/* Tentatively apply the changes numbered NUM and up. Return 1 if all changes are valid, zero otherwise. */ int -apply_change_group (void) +verify_changes (int num) { int i; rtx last_validated = NULL_RTX; @@ -329,7 +368,7 @@ apply_change_group (void) we also require that the operands meet the constraints for the insn. */ - for (i = 0; i < num_changes; i++) + for (i = num; i < num_changes; i++) { rtx object = changes[i].object; @@ -393,17 +432,51 @@ apply_change_group (void) last_validated = object; } - if (i == num_changes) + return (i == 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; + rtx last_object = NULL; + + for (i = 0; i < num_changes; i++) { - basic_block bb; + rtx object = changes[i].object; - 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; + if (changes[i].unshare) + *changes[i].loc = copy_rtx (*changes[i].loc); - num_changes = 0; + /* 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; +} + +/* Apply a group of changes previously issued with `validate_change'. + If all changes are valid, call confirm_change_group and return 1, + otherwise, call cancel_changes and return 0. */ + +int +apply_change_group (void) +{ + if (verify_changes (0)) + { + confirm_change_group (); return 1; } else @@ -413,6 +486,7 @@ apply_change_group (void) } } + /* Return the number of changes so far in the current group. */ int @@ -451,7 +525,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) enum rtx_code code; enum machine_mode op0_mode = VOIDmode; int prev_changes = num_changes; - rtx new; + rtx new_rtx; if (!x) return; @@ -472,7 +546,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) && rtx_equal_p (x, from))) { - validate_change (object, loc, to, 1); + validate_unshare_change (object, loc, to, 1); return; } @@ -489,9 +563,9 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS) { /* Verify that operands are really shared. */ - if (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) != - ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, j)))) - abort (); + 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); } @@ -524,11 +598,11 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) 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); } @@ -559,25 +633,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: @@ -641,17 +715,6 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) } } -/* 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); - 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. */ @@ -700,6 +763,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 @@ -720,168 +823,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 @@ -937,8 +878,10 @@ general_operand (rtx op, enum machine_mode mode) #ifdef INSN_SCHEDULING /* On machines that have insn scheduling, we want all memory - reference to be explicit, so outlaw paradoxical SUBREGs. */ - if (MEM_P (sub) + reference to be explicit, so outlaw paradoxical SUBREGs. + However, we must allow them after reload so that they can + get cleaned up by cleanup_subreg_operands. */ + if (!reload_completed && MEM_P (sub) && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (sub))) return 0; #endif @@ -954,7 +897,7 @@ general_operand (rtx op, enum machine_mode mode) /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally create such rtl, and we must reject it. */ - if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT + if (SCALAR_FLOAT_MODE_P (GET_MODE (op)) && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub))) return 0; @@ -975,14 +918,11 @@ general_operand (rtx op, enum machine_mode mode) return 0; /* Use the mem's mode, since it will be reloaded thus. */ - mode = GET_MODE (op); - GO_IF_LEGITIMATE_ADDRESS (mode, y, win); + if (memory_address_p (GET_MODE (op), y)) + return 1; } return 0; - - win: - return 1; } /* Return 1 if OP is a valid memory address for a memory reference @@ -1041,7 +981,7 @@ register_operand (rtx op, enum machine_mode mode) /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally create such rtl, and we must reject it. */ - if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT + if (SCALAR_FLOAT_MODE_P (GET_MODE (op)) && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub))) return 0; @@ -1348,7 +1288,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)) { @@ -1433,15 +1373,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; @@ -1468,11 +1409,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); @@ -1490,17 +1430,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. @@ -1532,16 +1473,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++) { @@ -1555,10 +1496,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. @@ -1570,8 +1513,7 @@ asm_operand_ok (rtx op, const char *constraint) int result = 0; /* Use constrain_operands after reload. */ - if (reload_completed) - abort (); + gcc_assert (!reload_completed); while (*constraint) { @@ -1610,7 +1552,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; @@ -1622,7 +1564,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. @@ -1744,16 +1686,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; } @@ -1925,8 +1865,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. */ @@ -1946,6 +1895,7 @@ extract_insn_cached (rtx insn) extract_insn (insn); recog_data.insn = insn; } + /* Do cached extract_insn, constrain_operands and complain about failures. Used by insn_attrtab. */ void @@ -1956,6 +1906,7 @@ extract_constrain_insn_cached (rtx insn) && !constrain_operands (reload_completed)) fatal_insn_not_found (insn); } + /* Do cached constrain_operands and complain about failures. */ int constrain_operands_cached (int strict) @@ -1976,11 +1927,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)) { @@ -2011,14 +1960,13 @@ extract_insn (rtx insn) /* This insn is an `asm' with operands. */ /* expand_asm_operands makes sure there aren't too many operands. */ - if (noperands > MAX_RECOG_OPERANDS) - abort (); + gcc_assert (noperands <= MAX_RECOG_OPERANDS); /* Now get the operand values and constraints out of the 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]; @@ -2060,8 +2008,23 @@ extract_insn (rtx insn) : recog_data.constraints[i][0] == '+' ? OP_INOUT : OP_IN); - if (recog_data.n_alternatives > MAX_RECOG_ALTERNATIVES) - abort (); + 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 @@ -2091,6 +2054,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; @@ -2140,7 +2109,7 @@ preprocess_constraints (void) } continue; - case 'm': + case TARGET_MEM_CONSTRAINT: op_alt[j].memory_ok = 1; break; case '<': @@ -2162,7 +2131,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': @@ -2183,7 +2152,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; } @@ -2228,7 +2198,7 @@ preprocess_constraints (void) struct funny_match { - int this, other; + int this_op, other; }; int @@ -2254,10 +2224,22 @@ constrain_operands (int strict) do { + int seen_earlyclobber_at = -1; int opno; 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]; @@ -2316,6 +2298,8 @@ constrain_operands (int strict) case '&': earlyclobber[opno] = 1; + if (seen_earlyclobber_at < 0) + seen_earlyclobber_at = opno; break; case '0': case '1': case '2': case '3': case '4': @@ -2364,7 +2348,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; } } @@ -2383,16 +2367,22 @@ constrain_operands (int strict) break; /* No need to check general_operand again; - it was done in insn-recog.c. */ + it was done in insn-recog.c. Well, except that reload + doesn't check the validity of its replacements, but + that should only matter when there's a bug. */ case 'g': /* Anything goes unless it is a REG and really has a hard reg but the hard reg is not in the class GENERAL_REGS. */ - if (strict < 0 - || GENERAL_REGS == ALL_REGS - || !REG_P (op) - || (reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER) - || reg_fits_class_p (op, GENERAL_REGS, offset, mode)) + if (REG_P (op)) + { + if (strict < 0 + || GENERAL_REGS == ALL_REGS + || (reload_in_progress + && REGNO (op) >= FIRST_PSEUDO_REGISTER) + || reg_fits_class_p (op, GENERAL_REGS, offset, mode)) + win = 1; + } + else if (strict < 0 || general_operand (op, mode)) win = 1; break; @@ -2403,7 +2393,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)) @@ -2564,8 +2554,10 @@ constrain_operands (int strict) /* See if any earlyclobber operand conflicts with some other operand. */ - if (strict > 0) - for (eopno = 0; eopno < recog_data.n_operands; eopno++) + if (strict > 0 && seen_earlyclobber_at >= 0) + for (eopno = seen_earlyclobber_at; + eopno < recog_data.n_operands; + eopno++) /* Ignore earlyclobber operands now in memory, because we would often report failure when we have two memory operands, one of which was formerly a REG. */ @@ -2589,7 +2581,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; @@ -2619,21 +2611,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 @@ -2673,7 +2657,7 @@ split_insn (rtx insn) /* Split all insns in the function. If UPD_LIFE, update life info after. */ void -split_all_insns (int upd_life) +split_all_insns (void) { sbitmap blocks; bool changed; @@ -2700,7 +2684,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 @@ -2709,17 +2693,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 { @@ -2741,18 +2715,7 @@ split_all_insns (int upd_life) } if (changed) - { - int old_last_basic_block = last_basic_block; - - find_many_sub_basic_blocks (blocks); - - if (old_last_basic_block != last_basic_block && upd_life) - blocks = sbitmap_resize (blocks, last_basic_block, 1); - } - - if (changed && upd_life) - update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES, - PROP_DEATH_NOTES); + find_many_sub_basic_blocks (blocks); #ifdef ENABLE_CHECKING verify_flow_info (); @@ -2764,7 +2727,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; @@ -2776,7 +2739,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)) { @@ -2794,6 +2757,7 @@ split_all_insns_noflow (void) split_insn (insn); } } + return 0; } #ifdef HAVE_peephole2 @@ -2805,10 +2769,12 @@ struct peep2_insn_data static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1]; static int peep2_current; +/* The number of instructions available to match a peep2. */ +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 @@ -2818,15 +2784,12 @@ static int peep2_current; rtx peep2_next_insn (int n) { - if (n >= MAX_INSNS_PER_PEEP2 + 1) - abort (); + gcc_assert (n <= peep2_current_count); n += peep2_current; if (n >= MAX_INSNS_PER_PEEP2 + 1) n -= MAX_INSNS_PER_PEEP2 + 1; - if (peep2_insn_data[n].insn == PEEP2_EOB) - return NULL_RTX; return peep2_insn_data[n].insn; } @@ -2836,15 +2799,13 @@ peep2_next_insn (int n) int peep2_regno_dead_p (int ofs, int regno) { - if (ofs >= MAX_INSNS_PER_PEEP2 + 1) - abort (); + gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1); ofs += peep2_current; if (ofs >= MAX_INSNS_PER_PEEP2 + 1) ofs -= MAX_INSNS_PER_PEEP2 + 1; - if (peep2_insn_data[ofs].insn == NULL_RTX) - abort (); + gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX); return ! REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno); } @@ -2856,15 +2817,13 @@ peep2_reg_dead_p (int ofs, rtx reg) { int regno, n; - if (ofs >= MAX_INSNS_PER_PEEP2 + 1) - abort (); + gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1); ofs += peep2_current; if (ofs >= MAX_INSNS_PER_PEEP2 + 1) ofs -= MAX_INSNS_PER_PEEP2 + 1; - if (peep2_insn_data[ofs].insn == NULL_RTX) - abort (); + gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX); regno = REGNO (reg); n = hard_regno_nregs[regno][GET_MODE (reg)]; @@ -2894,8 +2853,8 @@ peep2_find_free_register (int from, int to, const char *class_str, HARD_REG_SET live; int i; - if (from >= MAX_INSNS_PER_PEEP2 + 1 || to >= MAX_INSNS_PER_PEEP2 + 1) - abort (); + gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1); + gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1); from += peep2_current; if (from >= MAX_INSNS_PER_PEEP2 + 1) @@ -2904,8 +2863,7 @@ peep2_find_free_register (int from, int to, const char *class_str, if (to >= MAX_INSNS_PER_PEEP2 + 1) to -= MAX_INSNS_PER_PEEP2 + 1; - if (peep2_insn_data[from].insn == NULL_RTX) - abort (); + gcc_assert (peep2_insn_data[from].insn != NULL_RTX); REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before); while (from != to) @@ -2914,8 +2872,7 @@ peep2_find_free_register (int from, int to, const char *class_str, if (++from >= MAX_INSNS_PER_PEEP2 + 1) from = 0; - if (peep2_insn_data[from].insn == NULL_RTX) - abort (); + gcc_assert (peep2_insn_data[from].insn != NULL_RTX); REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before); IOR_HARD_REG_SET (live, this_live); } @@ -2940,6 +2897,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; @@ -2947,8 +2907,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)) @@ -2966,8 +2929,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) @@ -2984,62 +2946,46 @@ peep2_find_free_register (int from, int to, const char *class_str, /* Perform the peephole2 optimization pass. */ -void -peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) +static void +peephole2_optimize (void) { - regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2]; 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_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 = INITIALIZE_REG_SET (rs_heads[i]); - live = INITIALIZE_REG_SET (rs_heads[i]); - -#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; - /* 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; /* Start up propagation. */ - COPY_REG_SET (live, bb->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; @@ -3047,13 +2993,26 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) /* Record this insn. */ if (--peep2_current < 0) peep2_current = MAX_INSNS_PER_PEEP2; + if (peep2_current_count < MAX_INSNS_PER_PEEP2 + && 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); - /* Match the peephole. */ - try = peephole2_insns (PATTERN (insn), insn, &match_len); - if (try != NULL) + if (RTX_FRAME_RELATED_P (insn)) + { + /* 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; + attempt = NULL; + } + else + /* Match the peephole. */ + attempt = peephole2_insns (PATTERN (insn), insn, &match_len); + + 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 @@ -3071,7 +3030,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)) @@ -3079,8 +3038,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) new_insn = NEXT_INSN (new_insn); } - if (new_insn == NULL_RTX) - abort (); + gcc_assert (new_insn != NULL_RTX); CALL_INSN_FUNCTION_USAGE (new_insn) = CALL_INSN_FUNCTION_USAGE (old_insn); @@ -3092,11 +3050,9 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) { case REG_NORETURN: case REG_SETJMP: - case REG_ALWAYS_RETURN: - 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; @@ -3109,8 +3065,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) if (j >= MAX_INSNS_PER_PEEP2 + 1) j -= MAX_INSNS_PER_PEEP2 + 1; old_insn = peep2_insn_data[j].insn; - if (CALL_P (old_insn)) - abort (); + gcc_assert (!CALL_P (old_insn)); } break; } @@ -3123,32 +3078,30 @@ 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)) { edge eh_edge; + edge_iterator ei; - for (eh_edge = bb->succ; eh_edge - ; eh_edge = eh_edge->succ_next) + FOR_EACH_EDGE (eh_edge, ei, bb->succs) 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) { @@ -3168,10 +3121,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; } @@ -3183,49 +3132,43 @@ 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; + peep2_current_count = 0; #else /* Back up lifetime information past the end of the 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)) { if (--i < 0) i = MAX_INSNS_PER_PEEP2; + if (peep2_current_count < MAX_INSNS_PER_PEEP2 + && 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; @@ -3237,83 +3180,105 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) if (insn == BB_HEAD (bb)) break; } - - free_propagate_block_info (pbi); } for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i) - FREE_REG_SET (peep2_insn_data[i].live_before); - FREE_REG_SET (live); - + BITMAP_FREE (peep2_insn_data[i].live_before); + BITMAP_FREE (live); if (do_rebuild_jump_labels) rebuild_jump_labels (get_insns ()); - - /* If we eliminated EH edges, we may be able to merge blocks. Further, - we've changed global life since exception handlers are no longer - reachable. */ - if (do_cleanup_cfg) - { - cleanup_cfg (0); - 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); - if (! in_set) - abort (); - - 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; - - out_pat = PATTERN (out_insn); - if (GET_CODE (out_pat) != PARALLEL) - abort (); + in_pat = PATTERN (in_insn); + gcc_assert (GET_CODE (in_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; - if (GET_CODE (exp) != SET) - abort (); + 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; @@ -3332,9 +3297,8 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) in_set = single_set (in_insn); if (! in_set) { - if (JUMP_P (in_insn) || CALL_P (in_insn)) - return false; - abort (); + gcc_assert (JUMP_P (in_insn) || CALL_P (in_insn)); + return false; } if (GET_CODE (SET_SRC (in_set)) != IF_THEN_ELSE) @@ -3354,8 +3318,7 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) int i; out_pat = PATTERN (out_insn); - if (GET_CODE (out_pat) != PARALLEL) - abort (); + gcc_assert (GET_CODE (out_pat) == PARALLEL); for (i = 0; i < XVECLEN (out_pat, 0); i++) { @@ -3364,8 +3327,7 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) if (GET_CODE (exp) == CLOBBER) continue; - if (GET_CODE (exp) != SET) - abort (); + gcc_assert (GET_CODE (exp) == SET); if (reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 1)) || reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 2))) @@ -3375,3 +3337,210 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) return true; } + +static bool +gate_handle_peephole2 (void) +{ + return (optimize > 0 && flag_peephole2); +} + +static unsigned int +rest_of_handle_peephole2 (void) +{ +#ifdef HAVE_peephole2 + peephole2_optimize (); +#endif + return 0; +} + +struct rtl_opt_pass pass_peephole2 = +{ + { + RTL_PASS, + "peephole2", /* name */ + gate_handle_peephole2, /* gate */ + rest_of_handle_peephole2, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_PEEPHOLE2, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 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 (); + return 0; +} + +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 */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + } +}; + +static unsigned int +rest_of_handle_split_after_reload (void) +{ + /* If optimizing, then go ahead and split insns now. */ +#ifndef STACK_REGS + if (optimize > 0) +#endif + split_all_insns (); + return 0; +} + +struct rtl_opt_pass pass_split_after_reload = +{ + { + RTL_PASS, + "split2", /* name */ + NULL, /* gate */ + rest_of_handle_split_after_reload, /* 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_regstack (void) +{ +#if defined (HAVE_ATTR_length) && defined (STACK_REGS) + /* If flow2 creates new instructions which need splitting + and scheduling after reload is not done, they might not be + split until final which doesn't allow splitting + if HAVE_ATTR_length. */ +# ifdef INSN_SCHEDULING + return (optimize && !flag_schedule_insns_after_reload); +# else + return (optimize); +# endif +#else + return 0; +#endif +} + +static unsigned int +rest_of_handle_split_before_regstack (void) +{ + 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_before_regstack, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + } +}; + +static bool +gate_handle_split_before_sched2 (void) +{ +#ifdef INSN_SCHEDULING + return optimize > 0 && flag_schedule_insns_after_reload; +#else + return 0; +#endif +} + +static unsigned int +rest_of_handle_split_before_sched2 (void) +{ +#ifdef INSN_SCHEDULING + split_all_insns (); +#endif + return 0; +} + +struct rtl_opt_pass pass_split_before_sched2 = +{ + { + RTL_PASS, + "split4", /* name */ + gate_handle_split_before_sched2, /* gate */ + rest_of_handle_split_before_sched2, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_verify_flow | + TODO_dump_func /* todo_flags_finish */ + } +}; + +/* The placement of the splitting that we do for shorten_branches + depends on whether regstack is used by the target or not. */ +static bool +gate_do_final_split (void) +{ +#if defined (HAVE_ATTR_length) && !defined (STACK_REGS) + return 1; +#else + return 0; +#endif +} + +struct rtl_opt_pass pass_split_for_shorten_branches = +{ + { + RTL_PASS, + "split5", /* name */ + gate_do_final_split, /* gate */ + split_all_insns_noflow, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 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 */ + } +}; + +