diff options
Diffstat (limited to 'contrib/gcc/regmove.c')
-rw-r--r-- | contrib/gcc/regmove.c | 287 |
1 files changed, 122 insertions, 165 deletions
diff --git a/contrib/gcc/regmove.c b/contrib/gcc/regmove.c index cb5e547..8dcd054 100644 --- a/contrib/gcc/regmove.c +++ b/contrib/gcc/regmove.c @@ -1,6 +1,6 @@ /* Move registers around to reduce number of move instructions needed. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -27,6 +27,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" /* stdio.h must precede rtl.h for FFS. */ #include "tm_p.h" #include "insn-config.h" @@ -51,11 +53,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #define STACK_GROWS_DOWNWARD 0 #endif -static int perhaps_ends_bb_p PARAMS ((rtx)); -static int optimize_reg_copy_1 PARAMS ((rtx, rtx, rtx)); -static void optimize_reg_copy_2 PARAMS ((rtx, rtx, rtx)); -static void optimize_reg_copy_3 PARAMS ((rtx, rtx, rtx)); -static void copy_src_to_dest PARAMS ((rtx, rtx, rtx, int)); +static int perhaps_ends_bb_p (rtx); +static int optimize_reg_copy_1 (rtx, rtx, rtx); +static void optimize_reg_copy_2 (rtx, rtx, rtx); +static void optimize_reg_copy_3 (rtx, rtx, rtx); +static void copy_src_to_dest (rtx, rtx, rtx, int); static int *regmove_bb_head; struct match { @@ -65,26 +67,24 @@ struct match { int early_clobber[MAX_RECOG_OPERANDS]; }; -static rtx discover_flags_reg PARAMS ((void)); -static void mark_flags_life_zones PARAMS ((rtx)); -static void flags_set_1 PARAMS ((rtx, rtx, void *)); - -static int try_auto_increment PARAMS ((rtx, rtx, rtx, rtx, HOST_WIDE_INT, int)); -static int find_matches PARAMS ((rtx, struct match *)); -static void replace_in_call_usage PARAMS ((rtx *, unsigned int, rtx, rtx)); -static int fixup_match_1 PARAMS ((rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *)) -; -static int reg_is_remote_constant_p PARAMS ((rtx, rtx, rtx)); -static int stable_and_no_regs_but_for_p PARAMS ((rtx, rtx, rtx)); -static int regclass_compatible_p PARAMS ((int, int)); -static int replacement_quality PARAMS ((rtx)); -static int fixup_match_2 PARAMS ((rtx, rtx, rtx, rtx, FILE *)); +static rtx discover_flags_reg (void); +static void mark_flags_life_zones (rtx); +static void flags_set_1 (rtx, rtx, void *); + +static int try_auto_increment (rtx, rtx, rtx, rtx, HOST_WIDE_INT, int); +static int find_matches (rtx, struct match *); +static void replace_in_call_usage (rtx *, unsigned int, rtx, rtx); +static int fixup_match_1 (rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *); +static int reg_is_remote_constant_p (rtx, rtx, rtx); +static int stable_and_no_regs_but_for_p (rtx, rtx, rtx); +static int regclass_compatible_p (int, int); +static int replacement_quality (rtx); +static int fixup_match_2 (rtx, rtx, rtx, rtx, FILE *); /* Return nonzero if registers with CLASS1 and CLASS2 can be merged without causing too much register allocation problems. */ static int -regclass_compatible_p (class0, class1) - int class0, class1; +regclass_compatible_p (int class0, int class1) { return (class0 == class1 || (reg_class_subset_p (class0, class1) @@ -98,10 +98,8 @@ regclass_compatible_p (class0, class1) Iff INC_INSN_SET is nonzero, inc_insn has a destination different from src. Return nonzero for success. */ static int -try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre) - rtx reg, insn, inc_insn ,inc_insn_set; - HOST_WIDE_INT increment; - int pre; +try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg, + HOST_WIDE_INT increment, int pre) { enum rtx_code inc_code; @@ -165,7 +163,7 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre) if no flags were found. Return pc_rtx if we got confused. */ static rtx -discover_flags_reg () +discover_flags_reg (void) { rtx tmp; tmp = gen_rtx_REG (word_mode, 10000); @@ -218,8 +216,7 @@ static rtx flags_set_1_rtx; static int flags_set_1_set; static void -mark_flags_life_zones (flags) - rtx flags; +mark_flags_life_zones (rtx flags) { int flags_regno; int flags_nregs; @@ -259,8 +256,8 @@ mark_flags_life_zones (flags) rtx insn, end; int live; - insn = block->head; - end = block->end; + insn = BB_HEAD (block); + end = BB_END (block); /* Look out for the (unlikely) case of flags being live across basic block boundaries. */ @@ -317,9 +314,7 @@ mark_flags_life_zones (flags) /* A subroutine of mark_flags_life_zones, called through note_stores. */ static void -flags_set_1 (x, pat, data) - rtx x, pat; - void *data ATTRIBUTE_UNUSED; +flags_set_1 (rtx x, rtx pat, void *data ATTRIBUTE_UNUSED) { if (GET_CODE (pat) == SET && reg_overlap_mentioned_p (x, flags_set_1_rtx)) @@ -334,8 +329,7 @@ static int *regno_src_regno; a candidate for tying to a hard register, since the output might in turn be a candidate to be tied to a different hard register. */ static int -replacement_quality (reg) - rtx reg; +replacement_quality (rtx reg) { int src_regno; @@ -366,8 +360,7 @@ replacement_quality (reg) /* Return 1 if INSN might end a basic block. */ -static int perhaps_ends_bb_p (insn) - rtx insn; +static int perhaps_ends_bb_p (rtx insn) { switch (GET_CODE (insn)) { @@ -382,7 +375,7 @@ static int perhaps_ends_bb_p (insn) very conservative. */ if (nonlocal_goto_handler_labels) return 1; - /* FALLTHRU */ + /* Fall through. */ default: return can_throw_internal (insn); } @@ -400,10 +393,7 @@ static int perhaps_ends_bb_p (insn) register-register copy. */ static int -optimize_reg_copy_1 (insn, dest, src) - rtx insn; - rtx dest; - rtx src; +optimize_reg_copy_1 (rtx insn, rtx dest, rtx src) { rtx p, q; rtx note; @@ -599,10 +589,7 @@ optimize_reg_copy_1 (insn, dest, src) this for hard registers since the substitutions we may make might fail. */ static void -optimize_reg_copy_2 (insn, dest, src) - rtx insn; - rtx dest; - rtx src; +optimize_reg_copy_2 (rtx insn, rtx dest, rtx src) { rtx p, q; rtx set; @@ -655,15 +642,12 @@ optimize_reg_copy_2 (insn, dest, src) } /* INSN is a ZERO_EXTEND or SIGN_EXTEND of SRC to DEST. Look if SRC dies there, and if it is only set once, by loading - it from memory. If so, try to encorporate the zero/sign extension + it from memory. If so, try to incorporate the zero/sign extension into the memory read, change SRC to the mode of DEST, and alter the remaining accesses to use the appropriate SUBREG. This allows SRC and DEST to be tied later. */ static void -optimize_reg_copy_3 (insn, dest, src) - rtx insn; - rtx dest; - rtx src; +optimize_reg_copy_3 (rtx insn, rtx dest, rtx src) { rtx src_reg = XEXP (src, 0); int src_no = REGNO (src_reg); @@ -694,7 +678,7 @@ optimize_reg_copy_3 (insn, dest, src) || SET_DEST (set) != src_reg) return; - /* Be conserative: although this optimization is also valid for + /* Be conservative: although this optimization is also valid for volatile memory references, that could cause trouble in later passes. */ if (MEM_VOLATILE_P (SET_SRC (set))) return; @@ -722,7 +706,7 @@ optimize_reg_copy_3 (insn, dest, src) if (! INSN_P (p)) continue; - /* Make a tenative change. */ + /* Make a tentative change. */ validate_replace_rtx_group (src_reg, subreg, p); } @@ -748,11 +732,7 @@ optimize_reg_copy_3 (insn, dest, src) instead moving the value to dest directly before the operation. */ static void -copy_src_to_dest (insn, src, dest, old_max_uid) - rtx insn; - rtx src; - rtx dest; - int old_max_uid; +copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid) { rtx seq; rtx link; @@ -830,7 +810,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid) bb = regmove_bb_head[insn_uid]; if (bb >= 0) { - BLOCK_HEAD (bb) = move_insn; + BB_HEAD (BASIC_BLOCK (bb)) = move_insn; regmove_bb_head[insn_uid] = -1; } } @@ -869,10 +849,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid) the first insn in the function. */ static int -reg_is_remote_constant_p (reg, insn, first) - rtx reg; - rtx insn; - rtx first; +reg_is_remote_constant_p (rtx reg, rtx insn, rtx first) { rtx p; @@ -933,13 +910,11 @@ reg_is_remote_constant_p (reg, insn, first) (set (reg100) (plus reg100 offset2-offset1)) */ /* ??? What does this comment mean? */ -/* cse disrupts preincrement / postdecrement squences when it finds a +/* cse disrupts preincrement / postdecrement sequences when it finds a hard register as ultimate source, like the frame pointer. */ static int -fixup_match_2 (insn, dst, src, offset, regmove_dump_file) - rtx insn, dst, src, offset; - FILE *regmove_dump_file; +fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file) { rtx p, dst_death = 0; int length, num_calls = 0; @@ -1061,10 +1036,7 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file) (or 0 if none should be output). */ void -regmove_optimize (f, nregs, regmove_dump_file) - rtx f; - int nregs; - FILE *regmove_dump_file; +regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file) { int old_max_uid = get_max_uid (); rtx insn; @@ -1080,16 +1052,16 @@ regmove_optimize (f, nregs, regmove_dump_file) return; /* Find out where a potential flags register is live, and so that we - can supress some optimizations in those zones. */ + can suppress some optimizations in those zones. */ mark_flags_life_zones (discover_flags_reg ()); - regno_src_regno = (int *) xmalloc (sizeof *regno_src_regno * nregs); + regno_src_regno = xmalloc (sizeof *regno_src_regno * nregs); for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1; - regmove_bb_head = (int *) xmalloc (sizeof (int) * (old_max_uid + 1)); + regmove_bb_head = xmalloc (sizeof (int) * (old_max_uid + 1)); for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1; FOR_EACH_BB (bb) - regmove_bb_head[INSN_UID (bb->head)] = bb->index; + regmove_bb_head[INSN_UID (BB_HEAD (bb))] = bb->index; /* A forward/backward pass. Replace output operands with input operands. */ @@ -1287,7 +1259,8 @@ regmove_optimize (f, nregs, regmove_dump_file) if (GET_CODE (dst) != REG || REGNO (dst) < FIRST_PSEUDO_REGISTER || REG_LIVE_LENGTH (REGNO (dst)) < 0 - || RTX_UNCHANGING_P (dst)) + || RTX_UNCHANGING_P (dst) + || GET_MODE (src) != GET_MODE (dst)) continue; /* If the operands already match, then there is nothing to do. */ @@ -1347,7 +1320,7 @@ regmove_optimize (f, nregs, regmove_dump_file) it produces worse code, as it eliminates no copy instructions and the copy emitted will be produced by reload anyway. On patterns with multiple alternatives, - there may be better sollution availble. + there may be better solution available. In particular this change produced slower code for numeric i387 programs. */ @@ -1507,7 +1480,7 @@ regmove_optimize (f, nregs, regmove_dump_file) } /* If we weren't able to replace any of the alternatives, try an - alternative appoach of copying the source to the destination. */ + alternative approach of copying the source to the destination. */ if (!success && copy_src != NULL_RTX) copy_src_to_dest (insn, copy_src, copy_dst, old_max_uid); @@ -1518,13 +1491,13 @@ regmove_optimize (f, nregs, regmove_dump_file) ends. Fix that here. */ FOR_EACH_BB (bb) { - rtx end = bb->end; + rtx end = BB_END (bb); rtx new = end; rtx next = NEXT_INSN (new); while (next != 0 && INSN_UID (next) >= old_max_uid - && (bb->next_bb == EXIT_BLOCK_PTR || bb->next_bb->head != next)) + && (bb->next_bb == EXIT_BLOCK_PTR || BB_HEAD (bb->next_bb) != next)) new = next, next = NEXT_INSN (new); - bb->end = new; + BB_END (bb) = new; } done: @@ -1540,9 +1513,7 @@ regmove_optimize (f, nregs, regmove_dump_file) Initialize the info in MATCHP based on the constraints. */ static int -find_matches (insn, matchp) - rtx insn; - struct match *matchp; +find_matches (rtx insn, struct match *matchp) { int likely_spilled[MAX_RECOG_OPERANDS]; int op_no; @@ -1578,47 +1549,50 @@ find_matches (insn, matchp) if (*p == ',') i++; - while ((c = *p++) != '\0' && c != ',') - switch (c) - { - case '=': - break; - case '+': - break; - case '&': - matchp->early_clobber[op_no] = 1; - break; - case '%': - matchp->commutative[op_no] = op_no + 1; - matchp->commutative[op_no + 1] = op_no; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': + while ((c = *p) != '\0' && c != ',') + { + switch (c) { - char *end; - unsigned long match_ul = strtoul (p - 1, &end, 10); - int match = match_ul; + case '=': + break; + case '+': + break; + case '&': + matchp->early_clobber[op_no] = 1; + break; + case '%': + matchp->commutative[op_no] = op_no + 1; + matchp->commutative[op_no + 1] = op_no; + break; - p = end; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + char *end; + unsigned long match_ul = strtoul (p, &end, 10); + int match = match_ul; - if (match < op_no && likely_spilled[match]) - break; - matchp->with[op_no] = match; - any_matches = 1; - if (matchp->commutative[op_no] >= 0) - matchp->with[matchp->commutative[op_no]] = match; - } - break; + p = end; + + if (match < op_no && likely_spilled[match]) + continue; + matchp->with[op_no] = match; + any_matches = 1; + if (matchp->commutative[op_no] >= 0) + matchp->with[matchp->commutative[op_no]] = match; + } + continue; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'W': case 'Y': case 'Z': - if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER ((unsigned char) c))) + if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p) )) likely_spilled[op_no] = 1; break; } + p += CONSTRAINT_LEN (c, p); + } } return any_matches; } @@ -1627,11 +1601,7 @@ find_matches (insn, matchp) assumed to be in INSN. */ static void -replace_in_call_usage (loc, dst_reg, src, insn) - rtx *loc; - unsigned int dst_reg; - rtx src; - rtx insn; +replace_in_call_usage (rtx *loc, unsigned int dst_reg, rtx src, rtx insn) { rtx x = *loc; enum rtx_code code; @@ -1670,18 +1640,16 @@ replace_in_call_usage (loc, dst_reg, src, insn) Return nonzero for success. */ static int -fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number, - match_number, regmove_dump_file) - rtx insn, set, src, src_subreg, dst; - int backward, operand_number, match_number; - FILE *regmove_dump_file; +fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst, + int backward, int operand_number, int match_number, + FILE *regmove_dump_file) { rtx p; rtx post_inc = 0, post_inc_set = 0, search_end = 0; int success = 0; int num_calls = 0, s_num_calls = 0; enum rtx_code code = NOTE; - HOST_WIDE_INT insn_const = 0, newconst; + HOST_WIDE_INT insn_const = 0, newconst = 0; rtx overlap = 0; /* need to move insn ? */ rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX; int length, s_length; @@ -2064,7 +2032,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number, } -/* return nonzero if X is stable and mentions no regsiters but for +/* Return nonzero if X is stable and mentions no registers but for mentioning SRC or mentioning / changing DST . If in doubt, presume it is unstable. The rationale is that we want to check if we can move an insn easily @@ -2073,8 +2041,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number, leave the burden to update REG_DEAD / REG_UNUSED notes, so we don't want any registers but SRC and DST. */ static int -stable_and_no_regs_but_for_p (x, src, dst) - rtx x, src, dst; +stable_and_no_regs_but_for_p (rtx x, rtx src, rtx dst) { RTX_CODE code = GET_CODE (x); switch (GET_RTX_CLASS (code)) @@ -2097,7 +2064,7 @@ stable_and_no_regs_but_for_p (x, src, dst) if (code == MEM && ! stable_and_no_regs_but_for_p (XEXP (x, 0), src, dst)) return 0; - /* fall through */ + /* Fall through. */ default: return ! rtx_unstable_p (x); } @@ -2134,21 +2101,21 @@ struct csa_memlist struct csa_memlist *next; }; -static int stack_memref_p PARAMS ((rtx)); -static rtx single_set_for_csa PARAMS ((rtx)); -static void free_csa_memlist PARAMS ((struct csa_memlist *)); -static struct csa_memlist *record_one_stack_memref - PARAMS ((rtx, rtx *, struct csa_memlist *)); -static int try_apply_stack_adjustment - PARAMS ((rtx, struct csa_memlist *, HOST_WIDE_INT, HOST_WIDE_INT)); -static void combine_stack_adjustments_for_block PARAMS ((basic_block)); -static int record_stack_memrefs PARAMS ((rtx *, void *)); +static int stack_memref_p (rtx); +static rtx single_set_for_csa (rtx); +static void free_csa_memlist (struct csa_memlist *); +static struct csa_memlist *record_one_stack_memref (rtx, rtx *, + struct csa_memlist *); +static int try_apply_stack_adjustment (rtx, struct csa_memlist *, + HOST_WIDE_INT, HOST_WIDE_INT); +static void combine_stack_adjustments_for_block (basic_block); +static int record_stack_memrefs (rtx *, void *); /* Main entry point for stack adjustment combination. */ void -combine_stack_adjustments () +combine_stack_adjustments (void) { basic_block bb; @@ -2159,8 +2126,7 @@ combine_stack_adjustments () /* Recognize a MEM of the form (sp) or (plus sp const). */ static int -stack_memref_p (x) - rtx x; +stack_memref_p (rtx x) { if (GET_CODE (x) != MEM) return 0; @@ -2180,8 +2146,7 @@ stack_memref_p (x) tying fp and sp adjustments. */ static rtx -single_set_for_csa (insn) - rtx insn; +single_set_for_csa (rtx insn) { int i; rtx tmp = single_set (insn); @@ -2215,8 +2180,7 @@ single_set_for_csa (insn) /* Free the list of csa_memlist nodes. */ static void -free_csa_memlist (memlist) - struct csa_memlist *memlist; +free_csa_memlist (struct csa_memlist *memlist) { struct csa_memlist *next; for (; memlist ; memlist = next) @@ -2230,13 +2194,11 @@ free_csa_memlist (memlist) It is already known that the memory is stack_memref_p. */ static struct csa_memlist * -record_one_stack_memref (insn, mem, next_memlist) - rtx insn, *mem; - struct csa_memlist *next_memlist; +record_one_stack_memref (rtx insn, rtx *mem, struct csa_memlist *next_memlist) { struct csa_memlist *ml; - ml = (struct csa_memlist *) xmalloc (sizeof (*ml)); + ml = xmalloc (sizeof (*ml)); if (XEXP (*mem, 0) == stack_pointer_rtx) ml->sp_offset = 0; @@ -2254,10 +2216,8 @@ record_one_stack_memref (insn, mem, next_memlist) as each of the memories in MEMLIST. Return true on success. */ static int -try_apply_stack_adjustment (insn, memlist, new_adjust, delta) - rtx insn; - struct csa_memlist *memlist; - HOST_WIDE_INT new_adjust, delta; +try_apply_stack_adjustment (rtx insn, struct csa_memlist *memlist, HOST_WIDE_INT new_adjust, + HOST_WIDE_INT delta) { struct csa_memlist *ml; rtx set; @@ -2293,9 +2253,7 @@ struct record_stack_memrefs_data }; static int -record_stack_memrefs (xp, data) - rtx *xp; - void *data; +record_stack_memrefs (rtx *xp, void *data) { rtx x = *xp; struct record_stack_memrefs_data *d = @@ -2317,14 +2275,14 @@ record_stack_memrefs (xp, data) return 1; case REG: /* ??? We want be able to handle non-memory stack pointer - references later. For now just discard all insns refering to + references later. For now just discard all insns referring to stack pointer outside mem expressions. We would probably want to teach validate_replace to simplify expressions first. We can't just compare with STACK_POINTER_RTX because the reference to the stack pointer might be in some other mode. - In particular, an explict clobber in an asm statement will - result in a QImode clober. */ + In particular, an explicit clobber in an asm statement will + result in a QImode clobber. */ if (REGNO (x) == STACK_POINTER_REGNUM) return 1; break; @@ -2337,8 +2295,7 @@ record_stack_memrefs (xp, data) /* Subroutine of combine_stack_adjustments, called for each basic block. */ static void -combine_stack_adjustments_for_block (bb) - basic_block bb; +combine_stack_adjustments_for_block (basic_block bb) { HOST_WIDE_INT last_sp_adjust = 0; rtx last_sp_set = NULL_RTX; @@ -2347,9 +2304,9 @@ combine_stack_adjustments_for_block (bb) struct record_stack_memrefs_data data; bool end_of_block = false; - for (insn = bb->head; !end_of_block ; insn = next) + for (insn = BB_HEAD (bb); !end_of_block ; insn = next) { - end_of_block = insn == bb->end; + end_of_block = insn == BB_END (bb); next = NEXT_INSN (insn); if (! INSN_P (insn)) @@ -2382,7 +2339,7 @@ combine_stack_adjustments_for_block (bb) adjustment is now too large for a constant addition, we cannot merge the two stack adjustments. - Also we need to be carefull to not move stack pointer + Also we need to be careful to not move stack pointer such that we create stack accesses outside the allocated area. We can combine an allocation into the first insn, or a deallocation into the second insn. We can not |