X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fresource.c;h=05308491f61fe10e71ab733e3b3858dde3a707d8;hb=498b39713afcac3f7e60903fdaca81a2ff0bbb96;hp=240cf2323344d79f932a1b02bf66fdf932842f05;hpb=13c5e7bfc77941b205095c42ac3bf3a03987678e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/resource.c b/gcc/resource.c index 240cf232334..05308491f61 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -1,12 +1,12 @@ /* Definitions for computing resource usage of specific insns. - Copyright (C) 1999, 2000, 2001, 2002, 2003 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 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 +15,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" #include "system.h" @@ -27,7 +26,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "rtl.h" #include "tm_p.h" #include "hard-reg-set.h" -#include "basic-block.h" #include "function.h" #include "regs.h" #include "flags.h" @@ -36,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "except.h" #include "insn-attr.h" #include "params.h" +#include "df.h" /* This structure is used to record liveness information at the targets or fallthrough insns of branches. We will most likely need the information @@ -79,7 +78,7 @@ static HARD_REG_SET current_live_regs; static HARD_REG_SET pending_dead_regs; -static void update_live_status (rtx, rtx, void *); +static void update_live_status (rtx, const_rtx, void *); static int find_basic_block (rtx, int); static rtx next_insn_no_annul (rtx); static rtx find_dead_or_set_registers (rtx, struct resources*, @@ -90,21 +89,26 @@ static rtx find_dead_or_set_registers (rtx, struct resources*, It deadens any CLOBBERed registers and livens any SET registers. */ static void -update_live_status (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED) +update_live_status (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED) { int first_regno, last_regno; int i; - if (GET_CODE (dest) != REG - && (GET_CODE (dest) != SUBREG || GET_CODE (SUBREG_REG (dest)) != REG)) + if (!REG_P (dest) + && (GET_CODE (dest) != SUBREG || !REG_P (SUBREG_REG (dest)))) return; if (GET_CODE (dest) == SUBREG) - first_regno = subreg_regno (dest); - else - first_regno = REGNO (dest); + { + first_regno = subreg_regno (dest); + last_regno = first_regno + subreg_nregs (dest); - last_regno = first_regno + HARD_REGNO_NREGS (first_regno, GET_MODE (dest)); + } + else + { + first_regno = REGNO (dest); + last_regno = END_HARD_REGNO (dest); + } if (GET_CODE (x) == CLOBBER) for (i = first_regno; i < last_regno; i++) @@ -136,7 +140,7 @@ find_basic_block (rtx insn, int search_limit) /* Scan backwards to the previous BARRIER. Then see if we can find a label that starts a basic block. Return the basic block number. */ for (insn = prev_nonnote_insn (insn); - insn && GET_CODE (insn) != BARRIER && search_limit != 0; + insn && !BARRIER_P (insn) && search_limit != 0; insn = prev_nonnote_insn (insn), --search_limit) ; @@ -151,7 +155,7 @@ find_basic_block (rtx insn, int search_limit) /* See if any of the upcoming CODE_LABELs start a basic block. If we reach anything other than a CODE_LABEL or note, we can't find this code. */ for (insn = next_nonnote_insn (insn); - insn && GET_CODE (insn) == CODE_LABEL; + insn && LABEL_P (insn); insn = next_nonnote_insn (insn)) { FOR_EACH_BB (bb) @@ -172,9 +176,7 @@ next_insn_no_annul (rtx insn) { /* If INSN is an annulled branch, skip any insns from the target of the branch. */ - if ((GET_CODE (insn) == JUMP_INSN - || GET_CODE (insn) == CALL_INSN - || GET_CODE (insn) == INSN) + if (INSN_P (insn) && INSN_ANNULLED_BRANCH_P (insn) && NEXT_INSN (PREV_INSN (insn)) != insn) { @@ -191,7 +193,7 @@ next_insn_no_annul (rtx insn) } insn = NEXT_INSN (insn); - if (insn && GET_CODE (insn) == INSN + if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); } @@ -220,6 +222,7 @@ mark_referenced_resources (rtx x, struct resources *res, case CONST: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case PC: case SYMBOL_REF: @@ -227,38 +230,28 @@ mark_referenced_resources (rtx x, struct resources *res, return; case SUBREG: - if (GET_CODE (SUBREG_REG (x)) != REG) + if (!REG_P (SUBREG_REG (x))) mark_referenced_resources (SUBREG_REG (x), res, 0); else { unsigned int regno = subreg_regno (x); - unsigned int last_regno - = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + unsigned int last_regno = regno + subreg_nregs (x); - if (last_regno > FIRST_PSEUDO_REGISTER) - abort (); + gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER); for (r = regno; r < last_regno; r++) SET_HARD_REG_BIT (res->regs, r); } return; case REG: - { - unsigned int regno = REGNO (x); - unsigned int last_regno - = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); - - if (last_regno > FIRST_PSEUDO_REGISTER) - abort (); - for (r = regno; r < last_regno; r++) - SET_HARD_REG_BIT (res->regs, r); - } + gcc_assert (HARD_REGISTER_P (x)); + add_to_hard_reg_set (&res->regs, GET_MODE (x), REGNO (x)); return; case MEM: /* If this memory shouldn't change, it really isn't referencing memory. */ - if (RTX_UNCHANGING_P (x)) + if (MEM_READONLY_P (x)) res->unch_memory = 1; else res->memory = 1; @@ -304,18 +297,17 @@ mark_referenced_resources (rtx x, struct resources *res, case SET: /* Usually, the first operand of SET is set, not referenced. But registers used to access memory are referenced. SET_DEST is - also referenced if it is a ZERO_EXTRACT or SIGN_EXTRACT. */ + also referenced if it is a ZERO_EXTRACT. */ mark_referenced_resources (SET_SRC (x), res, 0); x = SET_DEST (x); - if (GET_CODE (x) == SIGN_EXTRACT - || GET_CODE (x) == ZERO_EXTRACT + if (GET_CODE (x) == ZERO_EXTRACT || GET_CODE (x) == STRICT_LOW_PART) mark_referenced_resources (x, res, 0); else if (GET_CODE (x) == SUBREG) x = SUBREG_REG (x); - if (GET_CODE (x) == MEM) + if (MEM_P (x)) mark_referenced_resources (XEXP (x, 0), res, 0); return; @@ -342,8 +334,7 @@ mark_referenced_resources (rtx x, struct resources *res, { sequence = PATTERN (NEXT_INSN (insn)); seq_size = XVECLEN (sequence, 0); - if (GET_CODE (sequence) != SEQUENCE) - abort (); + gcc_assert (GET_CODE (sequence) == SEQUENCE); } res->memory = 1; @@ -495,7 +486,7 @@ find_dead_or_set_registers (rtx target, struct resources *res, for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) { this_jump_insn = XVECEXP (PATTERN (insn), 0, i); - if (GET_CODE (this_jump_insn) == JUMP_INSN) + if (JUMP_P (this_jump_insn)) break; } } @@ -504,7 +495,7 @@ find_dead_or_set_registers (rtx target, struct resources *res, break; } - if (GET_CODE (this_jump_insn) == JUMP_INSN) + if (JUMP_P (this_jump_insn)) { if (jump_count++ < 10) { @@ -648,6 +639,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, case USE: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case LABEL_REF: case SYMBOL_REF: @@ -671,9 +663,8 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, rtx link; res->cc = res->memory = 1; - for (r = 0; r < FIRST_PSEUDO_REGISTER; r++) - if (call_used_regs[r] || global_regs[r]) - SET_HARD_REG_BIT (res->regs, r); + + IOR_HARD_REG_SET (res->regs, regs_invalidated_by_call); for (link = CALL_INSN_FUNCTION_USAGE (x); link; link = XEXP (link, 1)) @@ -755,7 +746,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, if (in_dest) { res->memory = 1; - res->unch_memory |= RTX_UNCHANGING_P (x); + res->unch_memory |= MEM_READONLY_P (x); res->volatil |= MEM_VOLATILE_P (x); } @@ -765,16 +756,14 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, case SUBREG: if (in_dest) { - if (GET_CODE (SUBREG_REG (x)) != REG) + if (!REG_P (SUBREG_REG (x))) mark_set_resources (SUBREG_REG (x), res, in_dest, mark_type); else { unsigned int regno = subreg_regno (x); - unsigned int last_regno - = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + unsigned int last_regno = regno + subreg_nregs (x); - if (last_regno > FIRST_PSEUDO_REGISTER) - abort (); + gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER); for (r = regno; r < last_regno; r++) SET_HARD_REG_BIT (res->regs, r); } @@ -784,14 +773,8 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, case REG: if (in_dest) { - unsigned int regno = REGNO (x); - unsigned int last_regno - = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); - - if (last_regno > FIRST_PSEUDO_REGISTER) - abort (); - for (r = regno; r < last_regno; r++) - SET_HARD_REG_BIT (res->regs, r); + gcc_assert (HARD_REGISTER_P (x)); + add_to_hard_reg_set (&res->regs, GET_MODE (x), REGNO (x)); } return; @@ -838,6 +821,20 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, } } +/* Return TRUE if INSN is a return, possibly with a filled delay slot. */ + +static bool +return_insn_p (const_rtx insn) +{ + if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RETURN) + return true; + + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) + return return_insn_p (XVECEXP (PATTERN (insn), 0, 0)); + + return false; +} + /* Set the resources that are live at TARGET. If TARGET is zero, we refer to the end of the current function and can @@ -896,6 +893,14 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) return; } + /* Handle return insn. */ + else if (return_insn_p (target)) + { + *res = end_of_function_needs; + mark_referenced_resources (target, res, 0); + return; + } + /* We have to assume memory is needed, but the CC isn't. */ res->memory = 1; res->volatil = res->unch_memory = 0; @@ -936,7 +941,7 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) { /* Allocate a place to put our results and chain it into the hash table. */ - tinfo = xmalloc (sizeof (struct target_info)); + tinfo = XNEW (struct target_info); tinfo->uid = INSN_UID (target); tinfo->block = b; tinfo->next @@ -952,9 +957,7 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) TARGET. Otherwise, we must assume everything is live. */ if (b != -1) { - regset regs_live = BASIC_BLOCK (b)->global_live_at_start; - unsigned int j; - unsigned int regno; + regset regs_live = DF_LR_IN (BASIC_BLOCK (b)); rtx start_insn, stop_insn; /* Compute hard regs live at start of block -- this is the real hard regs @@ -963,30 +966,17 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) REG_SET_TO_HARD_REG_SET (current_live_regs, regs_live); - EXECUTE_IF_SET_IN_REG_SET - (regs_live, FIRST_PSEUDO_REGISTER, i, - { - if (reg_renumber[i] >= 0) - { - regno = reg_renumber[i]; - for (j = regno; - j < regno + HARD_REGNO_NREGS (regno, - PSEUDO_REGNO_MODE (i)); - j++) - SET_HARD_REG_BIT (current_live_regs, j); - } - }); - /* Get starting and ending insn, handling the case where each might be a SEQUENCE. */ - start_insn = (b == 0 ? insns : BB_HEAD (BASIC_BLOCK (b))); + start_insn = (b == ENTRY_BLOCK_PTR->next_bb->index ? + insns : BB_HEAD (BASIC_BLOCK (b))); stop_insn = target; - if (GET_CODE (start_insn) == INSN + if (NONJUMP_INSN_P (start_insn) && GET_CODE (PATTERN (start_insn)) == SEQUENCE) start_insn = XVECEXP (PATTERN (start_insn), 0, 0); - if (GET_CODE (stop_insn) == INSN + if (NONJUMP_INSN_P (stop_insn) && GET_CODE (PATTERN (stop_insn)) == SEQUENCE) stop_insn = next_insn (PREV_INSN (stop_insn)); @@ -1010,7 +1000,7 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) && INSN_P (XEXP (PATTERN (insn), 0))) real_insn = XEXP (PATTERN (insn), 0); - if (GET_CODE (real_insn) == CALL_INSN) + if (CALL_P (real_insn)) { /* CALL clobbers all call-used regs that aren't fixed except sp, ap, and fp. Do this before setting the result of the @@ -1030,26 +1020,19 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) parameters. But they might be early. A CALL_INSN will usually clobber registers used for parameters. It isn't worth bothering with the unlikely case when it won't. */ - if ((GET_CODE (real_insn) == INSN + if ((NONJUMP_INSN_P (real_insn) && GET_CODE (PATTERN (real_insn)) != USE && GET_CODE (PATTERN (real_insn)) != CLOBBER) - || GET_CODE (real_insn) == JUMP_INSN - || GET_CODE (real_insn) == CALL_INSN) + || JUMP_P (real_insn) + || CALL_P (real_insn)) { for (link = REG_NOTES (real_insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_DEAD - && GET_CODE (XEXP (link, 0)) == REG + && REG_P (XEXP (link, 0)) && REGNO (XEXP (link, 0)) < FIRST_PSEUDO_REGISTER) - { - unsigned int first_regno = REGNO (XEXP (link, 0)); - unsigned int last_regno - = (first_regno - + HARD_REGNO_NREGS (first_regno, - GET_MODE (XEXP (link, 0)))); - - for (i = first_regno; i < last_regno; i++) - SET_HARD_REG_BIT (pending_dead_regs, i); - } + add_to_hard_reg_set (&pending_dead_regs, + GET_MODE (XEXP (link, 0)), + REGNO (XEXP (link, 0))); note_stores (PATTERN (real_insn), update_live_status, NULL); @@ -1057,21 +1040,14 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) These notes will always be accurate. */ for (link = REG_NOTES (real_insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_UNUSED - && GET_CODE (XEXP (link, 0)) == REG + && REG_P (XEXP (link, 0)) && REGNO (XEXP (link, 0)) < FIRST_PSEUDO_REGISTER) - { - unsigned int first_regno = REGNO (XEXP (link, 0)); - unsigned int last_regno - = (first_regno - + HARD_REGNO_NREGS (first_regno, - GET_MODE (XEXP (link, 0)))); - - for (i = first_regno; i < last_regno; i++) - CLEAR_HARD_REG_BIT (current_live_regs, i); - } + remove_from_hard_reg_set (¤t_live_regs, + GET_MODE (XEXP (link, 0)), + REGNO (XEXP (link, 0))); } - else if (GET_CODE (real_insn) == CODE_LABEL) + else if (LABEL_P (real_insn)) { /* A label clobbers the pending dead registers since neither reload nor jump will propagate a value across a label. */ @@ -1082,8 +1058,8 @@ mark_target_live_regs (rtx insns, rtx target, struct resources *res) /* The beginning of the epilogue corresponds to the end of the RTL chain when there are no epilogue insns. Certain resources are implicitly required at that point. */ - else if (GET_CODE (real_insn) == NOTE - && NOTE_LINE_NUMBER (real_insn) == NOTE_INSN_EPILOGUE_BEG) + else if (NOTE_P (real_insn) + && NOTE_KIND (real_insn) == NOTE_INSN_EPILOGUE_BEG) IOR_HARD_REG_SET (current_live_regs, start_of_epilogue_needs.regs); } @@ -1174,8 +1150,8 @@ init_resource_info (rtx epilogue_insn) else SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM); - if (current_function_return_rtx != 0) - mark_referenced_resources (current_function_return_rtx, + if (crtl->return_rtx != 0) + mark_referenced_resources (crtl->return_rtx, &end_of_function_needs, 1); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) @@ -1206,12 +1182,16 @@ init_resource_info (rtx epilogue_insn) start_of_epilogue_needs = end_of_function_needs; while ((epilogue_insn = next_nonnote_insn (epilogue_insn))) - mark_set_resources (epilogue_insn, &end_of_function_needs, 0, - MARK_SRC_DEST_CALL); + { + mark_set_resources (epilogue_insn, &end_of_function_needs, 0, + MARK_SRC_DEST_CALL); + if (return_insn_p (epilogue_insn)) + break; + } /* Allocate and initialize the tables used by mark_target_live_regs. */ - target_hash_table = xcalloc (TARGET_HASH_PRIME, sizeof (struct target_info *)); - bb_ticks = xcalloc (last_basic_block, sizeof (int)); + target_hash_table = XCNEWVEC (struct target_info *, TARGET_HASH_PRIME); + bb_ticks = XCNEWVEC (int, last_basic_block); } /* Free up the resources allocated to mark_target_live_regs (). This