X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freginfo.c;h=635312655bcd0d95da19cfd8d86044518f44b09f;hb=b75cad1f01aff79f08d82d2da6e34a44fb2a1338;hp=1543340d6914b563d53fc58d608789402b4788c6;hpb=b2d7ede152361abfd65fcd95c1754c7af2ef0ada;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 1543340d691..635312655bc 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -1,7 +1,7 @@ /* Compute different info about registers. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010 Free Software Foundation, Inc. + 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see #include "insn-config.h" #include "recog.h" #include "reload.h" -#include "toplev.h" #include "diagnostic-core.h" #include "output.h" #include "timevar.h" @@ -88,10 +87,16 @@ static const char initial_call_really_used_regs[] = CALL_REALLY_USED_REGISTERS; and are also considered fixed. */ char global_regs[FIRST_PSEUDO_REGISTER]; +/* Declaration for the global register. */ +static tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER]; + /* Same information as REGS_INVALIDATED_BY_CALL but in regset form to be used in dataflow more conveniently. */ regset regs_invalidated_by_call_regset; +/* Same information as FIXED_REG_SET but in regset form. */ +regset fixed_reg_set_regset; + /* The bitmap_obstack is used to hold some static variables that should not be reset after each function is compiled. */ static bitmap_obstack persistent_obstack; @@ -187,6 +192,9 @@ init_reg_sets (void) memcpy (reg_alloc_order, initial_reg_alloc_order, sizeof reg_alloc_order); #endif memcpy (reg_names, initial_reg_names, sizeof reg_names); + + SET_HARD_REG_SET (accessible_reg_set); + SET_HARD_REG_SET (operand_reg_set); } /* Initialize may_move_cost and friends for mode M. */ @@ -287,6 +295,8 @@ static char saved_call_used_regs[FIRST_PSEUDO_REGISTER]; static char saved_call_really_used_regs[FIRST_PSEUDO_REGISTER]; #endif static const char *saved_reg_names[FIRST_PSEUDO_REGISTER]; +static HARD_REG_SET saved_accessible_reg_set; +static HARD_REG_SET saved_operand_reg_set; /* Save the register information. */ void @@ -310,6 +320,8 @@ save_register_info (void) /* And similarly for reg_names. */ gcc_assert (sizeof reg_names == sizeof saved_reg_names); memcpy (saved_reg_names, reg_names, sizeof reg_names); + COPY_HARD_REG_SET (saved_accessible_reg_set, accessible_reg_set); + COPY_HARD_REG_SET (saved_operand_reg_set, operand_reg_set); } /* Restore the register information. */ @@ -325,6 +337,8 @@ restore_register_info (void) #endif memcpy (reg_names, saved_reg_names, sizeof reg_names); + COPY_HARD_REG_SET (accessible_reg_set, saved_accessible_reg_set); + COPY_HARD_REG_SET (operand_reg_set, saved_operand_reg_set); } /* After switches have been processed, which perhaps alter @@ -449,9 +463,32 @@ init_reg_sets_1 (void) } else CLEAR_REG_SET (regs_invalidated_by_call_regset); + if (!fixed_reg_set_regset) + fixed_reg_set_regset = ALLOC_REG_SET (&persistent_obstack); + else + CLEAR_REG_SET (fixed_reg_set_regset); + AND_HARD_REG_SET (operand_reg_set, accessible_reg_set); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { + /* As a special exception, registers whose class is NO_REGS are + not accepted by `register_operand'. The reason for this change + is to allow the representation of special architecture artifacts + (such as a condition code register) without extending the rtl + definitions. Since registers of class NO_REGS cannot be used + as registers in any case where register classes are examined, + it is better to apply this exception in a target-independent way. */ + if (REGNO_REG_CLASS (i) == NO_REGS) + CLEAR_HARD_REG_BIT (operand_reg_set, i); + + /* If a register is too limited to be treated as a register operand, + then it should never be allocated to a pseudo. */ + if (!TEST_HARD_REG_BIT (operand_reg_set, i)) + { + fixed_regs[i] = 1; + call_used_regs[i] = 1; + } + /* call_used_regs must include fixed_regs. */ gcc_assert (!fixed_regs[i] || call_used_regs[i]); #ifdef CALL_REALLY_USED_REGISTERS @@ -460,7 +497,10 @@ init_reg_sets_1 (void) #endif if (fixed_regs[i]) - SET_HARD_REG_BIT (fixed_reg_set, i); + { + SET_HARD_REG_BIT (fixed_reg_set, i); + SET_REGNO_REG_SET (fixed_reg_set_regset, i); + } if (call_used_regs[i]) SET_HARD_REG_BIT (call_used_reg_set, i); @@ -527,8 +567,7 @@ init_reg_sets_1 (void) SET_HARD_REG_BIT (ok_regs, j); for (i = 0; i < N_REG_CLASSES; i++) - if (((unsigned) CLASS_MAX_NREGS ((enum reg_class) i, - (enum machine_mode) m) + if ((targetm.class_max_nregs ((reg_class_t) i, (enum machine_mode) m) <= reg_class_size[i]) && hard_reg_set_intersect_p (ok_regs, reg_class_contents[i])) { @@ -576,13 +615,15 @@ init_reg_modes_target (void) { reg_raw_mode[i] = choose_hard_reg_mode (i, 1, false); - /* If we couldn't find a valid mode, just use the previous mode. - ??? One situation in which we need to do this is on the mips where - HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2. Ideally we'd like - to use DF mode for the even registers and VOIDmode for the odd - (for the cpu models where the odd ones are inaccessible). */ + /* If we couldn't find a valid mode, just use the previous mode + if it is suitable, otherwise fall back on word_mode. */ if (reg_raw_mode[i] == VOIDmode) - reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1]; + { + if (i > 0 && hard_regno_nregs[i][reg_raw_mode[i - 1]] == 1) + reg_raw_mode[i] = reg_raw_mode[i - 1]; + else + reg_raw_mode[i] = word_mode; + } } } @@ -630,8 +671,9 @@ register_move_cost (enum machine_mode mode, reg_class_t from, reg_class_t to) } /* Compute cost of moving registers to/from memory. */ + int -memory_move_cost (enum machine_mode mode, enum reg_class rclass, bool in) +memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in) { return targetm.memory_move_cost (mode, rclass, in); } @@ -825,8 +867,10 @@ fix_register (const char *name, int fixed, int call_used) /* Mark register number I as global. */ void -globalize_reg (int i) +globalize_reg (tree decl, int i) { + location_t loc = DECL_SOURCE_LOCATION (decl); + #ifdef STACK_REGS if (IN_RANGE (i, FIRST_STACK_REG, LAST_STACK_REG)) { @@ -836,18 +880,23 @@ globalize_reg (int i) #endif if (fixed_regs[i] == 0 && no_global_reg_vars) - error ("global register variable follows a function definition"); + error_at (loc, "global register variable follows a function definition"); if (global_regs[i]) { - warning (0, "register used for two global register variables"); + warning_at (loc, 0, + "register of %qD used for multiple global register variables", + decl); + inform (DECL_SOURCE_LOCATION (global_regs_decl[i]), + "conflicts with %qD", global_regs_decl[i]); return; } if (call_used_regs[i] && ! fixed_regs[i]) - warning (0, "call-clobbered register used for global register variable"); + warning_at (loc, 0, "call-clobbered register used for global register variable"); global_regs[i] = 1; + global_regs_decl[i] = decl; /* If we're globalizing the frame pointer, we need to set the appropriate regs_invalidated_by_call bit, even if it's already @@ -891,9 +940,9 @@ struct reg_pref union of most major pair of classes, that generality is not required. */ char altclass; - /* coverclass is a register class that IRA uses for allocating + /* allocnoclass is a register class that IRA uses for allocating the pseudo. */ - char coverclass; + char allocnoclass; }; /* Record preferences of each pseudo. This is available after RA is @@ -926,12 +975,12 @@ reg_alternate_class (int regno) /* Return the reg_class which is used by IRA for its allocation. */ enum reg_class -reg_cover_class (int regno) +reg_allocno_class (int regno) { if (reg_pref == 0) return NO_REGS; - return (enum reg_class) reg_pref[regno].coverclass; + return (enum reg_class) reg_pref[regno].allocnoclass; } @@ -1028,18 +1077,18 @@ struct rtl_opt_pass pass_reginfo_init = /* Set up preferred, alternate, and cover classes for REGNO as - PREFCLASS, ALTCLASS, and COVERCLASS. */ + PREFCLASS, ALTCLASS, and ALLOCNOCLASS. */ void setup_reg_classes (int regno, enum reg_class prefclass, enum reg_class altclass, - enum reg_class coverclass) + enum reg_class allocnoclass) { if (reg_pref == NULL) return; gcc_assert (reg_info_size == max_reg_num ()); reg_pref[regno].prefclass = prefclass; reg_pref[regno].altclass = altclass; - reg_pref[regno].coverclass = coverclass; + reg_pref[regno].allocnoclass = allocnoclass; } @@ -1236,39 +1285,13 @@ reg_classes_intersect_p (reg_class_t c1, reg_class_t c2) #ifdef CANNOT_CHANGE_MODE_CLASS -struct subregs_of_mode_node -{ - unsigned int block; - unsigned char modes[MAX_MACHINE_MODE]; -}; - -static htab_t subregs_of_mode; - -static hashval_t -som_hash (const void *x) -{ - const struct subregs_of_mode_node *const a = - (const struct subregs_of_mode_node *) x; - return a->block; -} - -static int -som_eq (const void *x, const void *y) -{ - const struct subregs_of_mode_node *const a = - (const struct subregs_of_mode_node *) x; - const struct subregs_of_mode_node *const b = - (const struct subregs_of_mode_node *) y; - return a->block == b->block; -} +static bitmap invalid_mode_changes; static void -record_subregs_of_mode (rtx subreg) +record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode) { - struct subregs_of_mode_node dummy, *node; enum machine_mode mode; unsigned int regno; - void **slot; if (!REG_P (SUBREG_REG (subreg))) return; @@ -1279,41 +1302,41 @@ record_subregs_of_mode (rtx subreg) if (regno < FIRST_PSEUDO_REGISTER) return; - dummy.block = regno & -8; - slot = htab_find_slot_with_hash (subregs_of_mode, &dummy, - dummy.block, INSERT); - node = (struct subregs_of_mode_node *) *slot; - if (node == NULL) + if (bitmap_set_bit (subregs_of_mode, + regno * NUM_MACHINE_MODES + (unsigned int) mode)) { - node = XCNEW (struct subregs_of_mode_node); - node->block = regno & -8; - *slot = node; + unsigned int rclass; + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + if (!bitmap_bit_p (invalid_mode_changes, + regno * N_REG_CLASSES + rclass) + && CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno), + mode, (enum reg_class) rclass)) + bitmap_set_bit (invalid_mode_changes, + regno * N_REG_CLASSES + rclass); } - - node->modes[mode] |= 1 << (regno & 7); } /* Call record_subregs_of_mode for all the subregs in X. */ static void -find_subregs_of_mode (rtx x) +find_subregs_of_mode (rtx x, bitmap subregs_of_mode) { enum rtx_code code = GET_CODE (x); const char * const fmt = GET_RTX_FORMAT (code); int i; if (code == SUBREG) - record_subregs_of_mode (x); + record_subregs_of_mode (x, subregs_of_mode); /* Time for some deep diving. */ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - find_subregs_of_mode (XEXP (x, i)); + find_subregs_of_mode (XEXP (x, i), subregs_of_mode); else if (fmt[i] == 'E') { int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) - find_subregs_of_mode (XVECEXP (x, i, j)); + find_subregs_of_mode (XVECEXP (x, i, j), subregs_of_mode); } } } @@ -1323,50 +1346,37 @@ init_subregs_of_mode (void) { basic_block bb; rtx insn; + bitmap_obstack srom_obstack; + bitmap subregs_of_mode; - if (subregs_of_mode) - htab_empty (subregs_of_mode); - else - subregs_of_mode = htab_create (100, som_hash, som_eq, free); + gcc_assert (invalid_mode_changes == NULL); + invalid_mode_changes = BITMAP_ALLOC (NULL); + bitmap_obstack_initialize (&srom_obstack); + subregs_of_mode = BITMAP_ALLOC (&srom_obstack); FOR_EACH_BB (bb) FOR_BB_INSNS (bb, insn) - if (INSN_P (insn)) - find_subregs_of_mode (PATTERN (insn)); + if (NONDEBUG_INSN_P (insn)) + find_subregs_of_mode (PATTERN (insn), subregs_of_mode); + + BITMAP_FREE (subregs_of_mode); + bitmap_obstack_release (&srom_obstack); } /* Return 1 if REGNO has had an invalid mode change in CLASS from FROM mode. */ bool invalid_mode_change_p (unsigned int regno, - enum reg_class rclass ATTRIBUTE_UNUSED, - enum machine_mode from) + enum reg_class rclass) { - struct subregs_of_mode_node dummy, *node; - unsigned int to; - unsigned char mask; - - gcc_assert (subregs_of_mode); - dummy.block = regno & -8; - node = (struct subregs_of_mode_node *) - htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); - if (node == NULL) - return false; - - mask = 1 << (regno & 7); - for (to = VOIDmode; to < NUM_MACHINE_MODES; to++) - if (node->modes[to] & mask) - if (CANNOT_CHANGE_MODE_CLASS (from, (enum machine_mode) to, rclass)) - return true; - - return false; + return bitmap_bit_p (invalid_mode_changes, + regno * N_REG_CLASSES + (unsigned) rclass); } void finish_subregs_of_mode (void) { - htab_delete (subregs_of_mode); - subregs_of_mode = 0; + BITMAP_FREE (invalid_mode_changes); } #else void