X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frecog.c;h=c1e25d746a15150039aec6da7bc3f6b20c3b03cb;hb=dfdfba40c33e30656bb1e396990524750c505366;hp=d7c950724008860eff5610a87bb6cb0ec8534b6e;hpb=4ee9c6840ad3fc92a9034343278a1e476ad6872a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/recog.c b/gcc/recog.c index d7c95072400..c1e25d746a1 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, 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 @@ -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 -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); @@ -65,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. */ @@ -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,20 +146,17 @@ 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++) { 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; } @@ -178,6 +171,7 @@ typedef struct change_t int old_code; rtx *loc; rtx old; + bool unshare; } change_t; static change_t *changes; @@ -186,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 @@ -203,18 +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; - 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,14 +219,15 @@ 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 && GET_CODE (object) != MEM) + if (object && !MEM_P (object)) { /* Set INSN_CODE to force rerecognition of insn. Save old code in case invalid. */ @@ -252,6 +246,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 +347,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 +365,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; @@ -338,11 +374,23 @@ apply_change_group (void) if (object == 0 || object == last_validated) continue; - if (GET_CODE (object) == MEM) + if (MEM_P (object)) { 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 (DEBUG_INSN_P (object)) + continue; else if (insn_invalid_p (object)) { rtx pat = PATTERN (object); @@ -383,7 +431,8 @@ apply_change_group (void) validate_change (object, &PATTERN (object), newpat, 1); continue; } - else if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) + else if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER + || GET_CODE (pat) == VAR_LOCATION) /* If this insn is a CLOBBER or USE, it is always valid, but is never recognized. */ continue; @@ -393,17 +442,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); + + /* 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; +} - 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 +496,7 @@ apply_change_group (void) } } + /* Return the number of changes so far in the current group. */ int @@ -433,102 +517,31 @@ cancel_changes (int num) for (i = num_changes - 1; i >= num; i--) { *changes[i].loc = changes[i].old; - if (changes[i].object && GET_CODE (changes[i].object) != MEM) + if (changes[i].object && !MEM_P (changes[i].object)) INSN_CODE (changes[i].object) = changes[i].old_code; } 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 - || (GET_CODE (x) == REG && GET_CODE (from) == REG - && 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. */ - if (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) != - ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, j)))) - abort (); - 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); } @@ -540,13 +553,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 @@ -559,25 +572,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: @@ -586,9 +599,9 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) likely to be an insertion operation; if it was, nothing bad will happen, we might just fail in some cases). */ - if (GET_CODE (XEXP (x, 0)) == MEM - && GET_CODE (XEXP (x, 1)) == CONST_INT - && GET_CODE (XEXP (x, 2)) == CONST_INT + if (MEM_P (XEXP (x, 0)) + && 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))) { @@ -641,6 +654,93 @@ 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. */ @@ -648,7 +748,7 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) int validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc) { - validate_replace_rtx_1 (loc, from, to, insn); + validate_replace_rtx_1 (loc, from, to, insn, true); return apply_change_group (); } @@ -658,16 +758,39 @@ validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc) 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. */ @@ -684,7 +807,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 @@ -700,189 +823,65 @@ validate_replace_src_group (rtx from, rtx to, rtx insn) d.insn = insn; note_uses (&PATTERN (insn), validate_replace_src_1, &d); } - -#ifdef HAVE_cc0 -/* Return 1 if the insn using CC0 set by INSN does not contain - any ordered tests applied to the condition codes. - EQ and NE tests do not count. */ - -int -next_insn_tests_no_inequality (rtx insn) -{ - rtx next = next_cc0_user (insn); - /* If there is no next insn, we have to take the conservative choice. */ - if (next == 0) - return 0; +/* 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. */ - return ((GET_CODE (next) == JUMP_INSN - || GET_CODE (next) == INSN - || GET_CODE (next) == CALL_INSN) - && ! inequality_comparisons_p (PATTERN (next))); -} -#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) +bool +validate_simplify_insn (rtx insn) { - rtx x = *loc; - enum rtx_code code = GET_CODE (x); - rtx *result = 0; - rtx *this_result; int i; - const char *fmt; + rtx pat = NULL; + rtx newpat = NULL; - switch (code) - { - case CONST_INT: - case CONST: - case LABEL_REF: - case SYMBOL_REF: - case CONST_DOUBLE: - case CONST_VECTOR: - case CLOBBER: - return 0; + pat = PATTERN (insn); - 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 - && GET_CODE (SET_DEST (x)) != REG - && ! (GET_CODE (SET_DEST (x)) == SUBREG - && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG - && (((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 (GET_CODE (pat) == SET) { - if (fmt[i] == 'e') - { - if (dest == XEXP (x, i) - || (GET_CODE (dest) == REG && GET_CODE (XEXP (x, i)) == REG - && 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 - || (GET_CODE (dest) == REG - && GET_CODE (XVECEXP (x, i, j)) == REG - && 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; - } - } + 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); - return result; + 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)); } -/* 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 - || (GET_CODE (next) != INSN && GET_CODE (next) != JUMP_INSN)) - return 0; - - result = find_single_use_1 (dest, &PATTERN (next)); - if (result && ploc) - *ploc = next; - return result; - } -#endif - - if (reload_completed || reload_in_progress || GET_CODE (dest) != REG) - return 0; +/* Return 1 if the insn using CC0 set by INSN does not contain + any ordered tests applied to the condition codes. + EQ and NE tests do not count. */ - for (next = next_nonnote_insn (insn); - next != 0 && GET_CODE (next) != CODE_LABEL; - 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; +int +next_insn_tests_no_inequality (rtx insn) +{ + rtx next = next_cc0_user (insn); - if (link) - { - result = find_single_use_1 (dest, &PATTERN (next)); - if (ploc) - *ploc = next; - return result; - } - } + /* If there is no next insn, we have to take the conservative choice. */ + if (next == 0) + return 0; - return 0; + return (INSN_P (next) + && ! inequality_comparisons_p (PATTERN (next))); } +#endif /* Return 1 if OP is a valid general operand for machine mode MODE. This is either a register reference, a memory reference, @@ -916,7 +915,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; @@ -924,9 +923,7 @@ general_operand (rtx op, enum machine_mode mode) if (CONSTANT_P (op)) return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) -#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif && LEGITIMATE_CONSTANT_P (op)); /* Except for certain constants with VOIDmode, already checked for, @@ -941,8 +938,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 (GET_CODE (sub) == MEM + 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 @@ -953,12 +952,12 @@ general_operand (rtx op, enum machine_mode mode) ??? This is a kludge. */ if (!reload_completed && SUBREG_BYTE (op) != 0 - && GET_CODE (sub) == MEM) + && MEM_P (sub)) return 0; /* 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; @@ -978,23 +977,12 @@ general_operand (rtx op, enum machine_mode mode) if (! volatile_ok && MEM_VOLATILE_P (op)) return 0; - if (GET_CODE (y) == ADDRESSOF) - return 1; - /* 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; } - /* Pretend this is an operand for now; we'll run force_operand - on its replacement in fixup_var_refs_1. */ - if (code == ADDRESSOF) - return 1; - return 0; - - win: - return 1; } /* Return 1 if OP is a valid memory address for a memory reference @@ -1039,11 +1027,11 @@ register_operand (rtx op, enum machine_mode mode) (Ideally, (SUBREG (MEM)...) should not exist after reload, but currently it does result from (SUBREG (REG)...) where the reg went on the stack.) */ - if (! reload_completed && GET_CODE (sub) == MEM) + if (! reload_completed && MEM_P (sub)) return general_operand (op, mode); #ifdef CANNOT_CHANGE_MODE_CLASS - if (GET_CODE (sub) == REG + if (REG_P (sub) && REGNO (sub) < FIRST_PSEUDO_REGISTER && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode) && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT @@ -1053,21 +1041,16 @@ 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; op = sub; } - /* If we have an ADDRESSOF, consider it valid since it will be - converted into something that will not be a MEM. */ - if (GET_CODE (op) == ADDRESSOF) - return 1; - /* We don't consider registers whose class is NO_REGS to be a register operand. */ - return (GET_CODE (op) == REG + return (REG_P (op) && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); } @@ -1090,7 +1073,7 @@ scratch_operand (rtx op, enum machine_mode mode) return 0; return (GET_CODE (op) == SCRATCH - || (GET_CODE (op) == REG + || (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER)); } @@ -1109,7 +1092,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; @@ -1117,9 +1100,7 @@ immediate_operand (rtx op, enum machine_mode mode) return (CONSTANT_P (op) && (GET_MODE (op) == mode || mode == VOIDmode || GET_MODE (op) == VOIDmode) -#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif && LEGITIMATE_CONSTANT_P (op)); } @@ -1128,7 +1109,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 @@ -1151,7 +1132,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)); } @@ -1178,16 +1159,14 @@ 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; return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) -#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif && LEGITIMATE_CONSTANT_P (op)); } @@ -1202,14 +1181,14 @@ nonmemory_operand (rtx op, enum machine_mode mode) (Ideally, (SUBREG (MEM)...) should not exist after reload, but currently it does result from (SUBREG (REG)...) where the reg went on the stack.) */ - if (! reload_completed && GET_CODE (SUBREG_REG (op)) == MEM) + if (! reload_completed && MEM_P (SUBREG_REG (op))) return general_operand (op, mode); op = SUBREG_REG (op); } /* We don't consider registers whose class is NO_REGS to be a register operand. */ - return (GET_CODE (op) == REG + return (REG_P (op) && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); } @@ -1229,7 +1208,7 @@ push_operand (rtx op, enum machine_mode mode) rounded_size = PUSH_ROUNDING (rounded_size); #endif - if (GET_CODE (op) != MEM) + if (!MEM_P (op)) return 0; if (mode != VOIDmode && GET_MODE (op) != mode) @@ -1247,7 +1226,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 @@ -1269,7 +1248,7 @@ push_operand (rtx op, enum machine_mode mode) int pop_operand (rtx op, enum machine_mode mode) { - if (GET_CODE (op) != MEM) + if (!MEM_P (op)) return 0; if (mode != VOIDmode && GET_MODE (op) != mode) @@ -1288,14 +1267,15 @@ pop_operand (rtx op, enum machine_mode mode) int memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr) { - if (GET_CODE (addr) == ADDRESSOF) - return 1; - +#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, @@ -1312,7 +1292,7 @@ memory_operand (rtx op, enum machine_mode mode) if (! reload_completed) /* Note that no SUBREG is a memory operand before end of reload pass, because (SUBREG (MEM...)) forces reloading into a register. */ - return GET_CODE (op) == MEM && general_operand (op, mode); + return MEM_P (op) && general_operand (op, mode); if (mode != VOIDmode && GET_MODE (op) != mode) return 0; @@ -1321,7 +1301,7 @@ memory_operand (rtx op, enum machine_mode mode) if (GET_CODE (inner) == SUBREG) inner = SUBREG_REG (inner); - return (GET_CODE (inner) == MEM && general_operand (op, mode)); + return (MEM_P (inner) && general_operand (op, mode)); } /* Return 1 if OP is a valid indirect memory reference with mode MODE; @@ -1332,7 +1312,7 @@ indirect_operand (rtx op, enum machine_mode mode) { /* Before reload, a SUBREG isn't in memory (see memory_operand, above). */ if (! reload_completed - && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM) + && GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op))) { int offset = SUBREG_BYTE (op); rtx inner = SUBREG_REG (op); @@ -1347,16 +1327,42 @@ 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))); } - return (GET_CODE (op) == MEM + return (MEM_P (op) && memory_operand (op, 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. */ @@ -1372,7 +1378,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)) { @@ -1457,15 +1463,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; @@ -1492,11 +1499,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); @@ -1514,17 +1520,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. @@ -1556,16 +1563,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++) { @@ -1579,23 +1586,24 @@ 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. 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; /* Use constrain_operands after reload. */ - if (reload_completed) - abort (); + gcc_assert (!reload_completed); while (*constraint) { @@ -1618,15 +1626,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': @@ -1634,7 +1656,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; @@ -1646,14 +1668,14 @@ 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. Match any memory and hope things are resolved after reload. */ - if (GET_CODE (op) == MEM + if (MEM_P (op) && (1 || GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == POST_DEC)) @@ -1661,7 +1683,7 @@ asm_operand_ok (rtx op, const char *constraint) break; case '>': - if (GET_CODE (op) == MEM + if (MEM_P (op) && (1 || GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == POST_INC)) @@ -1688,65 +1710,61 @@ 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; /* Fall through. */ case 'i': - if (CONSTANT_P (op) -#ifdef LEGITIMATE_PIC_OPERAND_P - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif - ) + if (CONSTANT_P (op) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) result = 1; 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; @@ -1772,16 +1790,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; } @@ -1856,7 +1872,7 @@ find_constant_term_loc (rtx *p) int offsettable_memref_p (rtx op) { - return ((GET_CODE (op) == MEM) + return ((MEM_P (op)) && offsettable_address_p (1, GET_MODE (op), XEXP (op, 0))); } @@ -1866,7 +1882,7 @@ offsettable_memref_p (rtx op) int offsettable_nonstrict_memref_p (rtx op) { - return ((GET_CODE (op) == MEM) + return ((MEM_P (op)) && offsettable_address_p (0, GET_MODE (op), XEXP (op, 0))); } @@ -1953,8 +1969,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. */ @@ -1974,6 +1999,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 @@ -1984,6 +2010,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) @@ -2004,11 +2031,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)) { @@ -2017,6 +2042,7 @@ extract_insn (rtx insn) case ASM_INPUT: case ADDR_VEC: case ADDR_DIFF_VEC: + case VAR_LOCATION: return; case SET: @@ -2039,14 +2065,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]; @@ -2088,8 +2113,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 @@ -2114,11 +2154,17 @@ preprocess_constraints (void) for (j = 0; j < recog_data.n_alternatives; j++) { - op_alt[j].class = NO_REGS; + op_alt[j].cl = NO_REGS; op_alt[j].constraint = p; 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; @@ -2168,7 +2214,7 @@ preprocess_constraints (void) } continue; - case 'm': + case TARGET_MEM_CONSTRAINT: op_alt[j].memory_ok = 1; break; case '<': @@ -2189,12 +2235,14 @@ preprocess_constraints (void) case 'p': op_alt[j].is_address = 1; - op_alt[j].class = reg_class_subunion[(int) op_alt[j].class] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]; + op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl] + [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; break; - case 'g': case 'r': - op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) GENERAL_REGS]; + case 'g': + case 'r': + op_alt[j].cl = + reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS]; break; default: @@ -2206,16 +2254,17 @@ preprocess_constraints (void) if (EXTRA_ADDRESS_CONSTRAINT (c, p)) { op_alt[j].is_address = 1; - op_alt[j].class + op_alt[j].cl = (reg_class_subunion - [(int) op_alt[j].class] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]); + [(int) op_alt[j].cl] + [(int) base_reg_class (VOIDmode, ADDRESS, + SCRATCH)]); break; } - op_alt[j].class + op_alt[j].cl = (reg_class_subunion - [(int) op_alt[j].class] + [(int) op_alt[j].cl] [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]); break; } @@ -2254,7 +2303,7 @@ preprocess_constraints (void) struct funny_match { - int this, other; + int this_op, other; }; int @@ -2280,10 +2329,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]; @@ -2303,7 +2364,7 @@ constrain_operands (int strict) if (GET_CODE (op) == SUBREG) { - if (GET_CODE (SUBREG_REG (op)) == REG + if (REG_P (SUBREG_REG (op)) && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER) offset = subreg_regno_offset (REGNO (SUBREG_REG (op)), GET_MODE (SUBREG_REG (op)), @@ -2342,6 +2403,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': @@ -2390,7 +2453,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; } } @@ -2409,16 +2472,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 - || GET_CODE (op) != REG - || (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; @@ -2429,10 +2498,10 @@ 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 (GET_CODE (op) == MEM) + if (MEM_P (op)) { if (strict > 0 && !strict_memory_address_p (GET_MODE (op), @@ -2447,20 +2516,20 @@ constrain_operands (int strict) else if (strict < 0 && CONSTANT_P (op)) win = 1; /* During reload, accept a pseudo */ - else if (reload_in_progress && GET_CODE (op) == REG + else if (reload_in_progress && REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) win = 1; break; case '<': - if (GET_CODE (op) == MEM + if (MEM_P (op) && (GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == POST_DEC)) win = 1; break; case '>': - if (GET_CODE (op) == MEM + if (MEM_P (op) && (GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == POST_INC)) win = 1; @@ -2482,7 +2551,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; @@ -2492,7 +2561,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; @@ -2506,18 +2575,18 @@ 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; case 'V': - if (GET_CODE (op) == MEM + if (MEM_P (op) && ((strict > 0 && ! offsettable_memref_p (op)) || (strict < 0 - && !(CONSTANT_P (op) || GET_CODE (op) == MEM)) + && !(CONSTANT_P (op) || MEM_P (op))) || (reload_in_progress - && !(GET_CODE (op) == REG + && !(REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)))) win = 1; break; @@ -2527,28 +2596,28 @@ constrain_operands (int strict) || (strict == 0 && offsettable_nonstrict_memref_p (op)) /* Before reload, accept what reload can handle. */ || (strict < 0 - && (CONSTANT_P (op) || GET_CODE (op) == MEM)) + && (CONSTANT_P (op) || MEM_P (op))) /* During reload, accept a pseudo */ - || (reload_in_progress && GET_CODE (op) == REG + || (reload_in_progress && REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)) win = 1; break; default: { - enum reg_class class; + enum reg_class cl; - class = (c == 'r' + cl = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p)); - if (class != NO_REGS) + if (cl != NO_REGS) { if (strict < 0 || (strict == 0 - && GET_CODE (op) == REG + && REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) || (strict == 0 && GET_CODE (op) == SCRATCH) - || (GET_CODE (op) == REG - && reg_fits_class_p (op, class, offset, mode))) + || (REG_P (op) + && reg_fits_class_p (op, cl, offset, mode))) win = 1; } #ifdef EXTRA_CONSTRAINT_STR @@ -2557,12 +2626,12 @@ constrain_operands (int strict) else if (EXTRA_MEMORY_CONSTRAINT (c, p) /* Every memory operand can be reloaded to fit. */ - && ((strict < 0 && GET_CODE (op) == MEM) + && ((strict < 0 && MEM_P (op)) /* Before reload, accept what reload can turn into mem. */ || (strict < 0 && CONSTANT_P (op)) /* During reload, accept a pseudo */ - || (reload_in_progress && GET_CODE (op) == REG + || (reload_in_progress && REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER))) win = 1; else if (EXTRA_ADDRESS_CONSTRAINT (c, p) @@ -2590,15 +2659,17 @@ 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. */ if (earlyclobber[eopno] - && GET_CODE (recog_data.operand[eopno]) == REG) + && REG_P (recog_data.operand[eopno])) for (opno = 0; opno < recog_data.n_operands; opno++) - if ((GET_CODE (recog_data.operand[opno]) == MEM + if ((MEM_P (recog_data.operand[opno]) || recog_data.operand_type[opno] != OP_OUT) && opno != eopno /* Ignore things like match_operator operands. */ @@ -2615,7 +2686,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; @@ -2641,25 +2712,17 @@ constrain_operands (int strict) If REG occupies multiple hard regs, all of them must be in CLASS. */ int -reg_fits_class_p (rtx operand, enum reg_class class, int offset, +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) class], - 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) class], - 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 @@ -2672,14 +2735,31 @@ 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. */ - PUT_CODE (insn, NOTE); - NOTE_SOURCE_FILE (insn) = 0; - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + SET_INSN_DELETED (insn); /* ??? Coddle to md files that generate subregs in post-reload splitters instead of computing the proper hard register. */ @@ -2695,13 +2775,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; @@ -2716,6 +2797,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 @@ -2728,7 +2810,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 @@ -2737,17 +2819,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 { @@ -2758,7 +2830,7 @@ split_all_insns (int upd_life) BB boundary we are interested in will be set to previous one. */ - while (GET_CODE (last) == BARRIER) + while (BARRIER_P (last)) last = PREV_INSN (last); SET_BIT (blocks, bb->index); changed = true; @@ -2768,19 +2840,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 (); @@ -2792,7 +2854,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; @@ -2804,7 +2866,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)) { @@ -2822,6 +2884,7 @@ split_all_insns_noflow (void) split_insn (insn); } } + return 0; } #ifdef HAVE_peephole2 @@ -2833,10 +2896,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 @@ -2846,15 +2911,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; } @@ -2864,15 +2926,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); } @@ -2884,15 +2944,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)]; @@ -2918,12 +2976,12 @@ peep2_find_free_register (int from, int to, const char *class_str, enum machine_mode mode, HARD_REG_SET *reg_set) { static int search_ofs; - enum reg_class class; + enum reg_class cl; 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) @@ -2932,8 +2990,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) @@ -2942,13 +2999,12 @@ 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); } - class = (class_str[0] == 'r' ? GENERAL_REGS + cl = (class_str[0] == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str)); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) @@ -2968,15 +3024,21 @@ 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[class], regno)) + if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno)) continue; /* And can support the mode we need. */ 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)) @@ -2994,8 +3056,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) @@ -3010,64 +3071,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. */ -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; - - /* 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->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)) + if (NONDEBUG_INSN_P (insn)) { - rtx try, before_try, x; + rtx attempt, before_try, x; int match_len; rtx note; bool was_call = false; @@ -3075,13 +3133,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_backwards (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_reinit_state (live); + 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 @@ -3095,20 +3166,19 @@ 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 (GET_CODE (old_insn) != CALL_INSN) + if (!CALL_P (old_insn)) continue; was_call = true; - new_insn = try; + new_insn = attempt; while (new_insn != NULL_RTX) { - if (GET_CODE (new_insn) == CALL_INSN) + if (CALL_P (new_insn)) break; 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); @@ -3120,11 +3190,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; @@ -3137,8 +3205,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 (GET_CODE (old_insn) == CALL_INSN) - abort (); + gcc_assert (!CALL_P (old_insn)); } break; } @@ -3151,32 +3218,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)) - if (GET_CODE (x) == CALL_INSN + 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) { @@ -3186,7 +3251,7 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) nfte = split_block (bb, x); flags = (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL)); - if (GET_CODE (x) == CALL_INSN) + if (CALL_P (x)) flags |= EDGE_ABNORMAL_CALL; nehe = make_edge (nfte->src, eh_edge->dest, flags); @@ -3196,10 +3261,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; } @@ -3211,50 +3272,44 @@ 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_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)) - if (GET_CODE (x) == JUMP_INSN) + for (x = attempt; x != before_try; x = PREV_INSN (x)) + if (JUMP_P (x)) { do_rebuild_jump_labels = true; break; @@ -3265,83 +3320,106 @@ peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED) if (insn == BB_HEAD (bb)) 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); - 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 (GET_CODE (SET_DEST (in_set)) != MEM) - 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; @@ -3360,9 +3438,8 @@ if_test_bypass_p (rtx out_insn, rtx in_insn) in_set = single_set (in_insn); if (! in_set) { - if (GET_CODE (in_insn) == JUMP_INSN || GET_CODE (in_insn) == CALL_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) @@ -3382,8 +3459,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++) { @@ -3392,8 +3468,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))) @@ -3403,3 +3478,208 @@ 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 */ + TV_NONE, /* 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 */ + 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_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 */ + 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_NONE, /* 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 */ + } +};