X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fregclass.c;h=8a0bab19026da50a25824c5674eef9dce0382b10;hp=9c496b6afdc10be871df45fb78c7df647520b686;hb=89e055a801f833420d05c7d9918f37c4f974ea4e;hpb=c235b58a9960d521ea6a36f5a1deb0821dced436 diff --git a/gcc/regclass.c b/gcc/regclass.c index 9c496b6afdc..8a0bab19026 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -1,6 +1,7 @@ /* Compute register class preferences for pseudo-registers. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996 - 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +17,8 @@ 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. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ /* This file contains two passes of the compiler: reg_scan and reg_class. @@ -35,6 +36,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "flags.h" #include "basic-block.h" #include "regs.h" +#include "addresses.h" #include "function.h" #include "insn-config.h" #include "recog.h" @@ -44,6 +46,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "output.h" #include "ggc.h" #include "timevar.h" +#include "hashtab.h" +#include "target.h" static void init_reg_sets_1 (void); static void init_reg_autoinc (void); @@ -51,12 +55,11 @@ static void init_reg_autoinc (void); /* If we have auto-increment or auto-decrement and we can have secondary reloads, we are not allowed to use classes requiring secondary reloads for pseudos auto-incremented since reload can't handle it. */ - -#ifdef AUTO_INC_DEC -#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS) +/* We leave it to target hooks to decide if we have secondary reloads, so + assume that we might have them. */ +#if defined(AUTO_INC_DEC) /* */ #define FORBIDDEN_INC_DEC_CLASSES #endif -#endif /* Register tables used by many passes. */ @@ -103,6 +106,13 @@ static const char initial_call_used_regs[] = CALL_USED_REGISTERS; char call_really_used_regs[] = CALL_REALLY_USED_REGISTERS; #endif +#ifdef CALL_REALLY_USED_REGISTERS +#define CALL_REALLY_USED_REGNO_P(X) call_really_used_regs[X] +#else +#define CALL_REALLY_USED_REGNO_P(X) call_used_regs[X] +#endif + + /* Indexed by hard register number, contains 1 for registers that are fixed use or call used registers that cannot hold quantities across calls even if we are willing to save and restore them. call fixed @@ -114,10 +124,6 @@ char call_fixed_regs[FIRST_PSEUDO_REGISTER]; HARD_REG_SET call_fixed_reg_set; -/* Number of non-fixed registers. */ - -int n_non_fixed_regs; - /* Indexed by hard register number, contains 1 for registers that are being used for global register decls. These must be exempt from ordinary flow analysis @@ -163,11 +169,11 @@ unsigned int reg_class_size[N_REG_CLASSES]; /* For each reg class, table listing all the containing classes. */ -enum reg_class reg_class_superclasses[N_REG_CLASSES][N_REG_CLASSES]; +static enum reg_class reg_class_superclasses[N_REG_CLASSES][N_REG_CLASSES]; /* For each reg class, table listing all the classes contained in it. */ -enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES]; +static enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES]; /* For each pair of reg classes, a largest reg class contained in their union. */ @@ -179,12 +185,13 @@ enum reg_class reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES]; enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES]; -/* Array containing all of the register names. Unless - DEBUG_REGISTER_NAMES is defined, use the copy in print-rtl.c. */ +/* Array containing all of the register names. */ -#ifdef DEBUG_REGISTER_NAMES const char * reg_names[] = REGISTER_NAMES; -#endif + +/* Array containing all of the register class names. */ + +const char * reg_class_names[] = REG_CLASS_NAMES; /* For each hard register, the widest mode object that it can contain. This will be a MODE_INT mode if the register can hold integers. Otherwise @@ -193,6 +200,10 @@ const char * reg_names[] = REGISTER_NAMES; enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER]; +/* 1 if there is a register of given mode. */ + +bool have_regs_of_mode [MAX_MACHINE_MODE]; + /* 1 if class does contain register of given mode. */ static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE]; @@ -226,12 +237,6 @@ static char *in_inc_dec; #endif /* FORBIDDEN_INC_DEC_CLASSES */ -#ifdef CANNOT_CHANGE_MODE_CLASS -/* All registers that have been subreged. Indexed by regno * MAX_MACHINE_MODE - + mode. */ -bitmap_head subregs_of_mode; -#endif - /* Sample MEM values for use by memory_move_secondary_cost. */ static GTY(()) rtx top_of_stack[MAX_MACHINE_MODE]; @@ -255,6 +260,8 @@ static struct reg_info_data *reg_info_head; static int no_global_reg_vars = 0; +/* Specify number of hard registers given machine mode occupy. */ +unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE]; /* Function called only once to initialize the above data on reg usage. Once this is done, various switches may override. */ @@ -278,13 +285,15 @@ init_reg_sets (void) SET_HARD_REG_BIT (reg_class_contents[i], j); } + /* Sanity check: make sure the target macros FIXED_REGISTERS and + CALL_USED_REGISTERS had the right number of initializers. */ + gcc_assert (sizeof fixed_regs == sizeof initial_fixed_regs); + gcc_assert (sizeof call_used_regs == sizeof initial_call_used_regs); + memcpy (fixed_regs, initial_fixed_regs, sizeof fixed_regs); memcpy (call_used_regs, initial_call_used_regs, sizeof call_used_regs); memset (global_regs, 0, sizeof global_regs); - /* Do any additional initialization regsets may need. */ - INIT_ONCE_REG_SET (); - #ifdef REG_ALLOC_ORDER for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) inv_reg_alloc_order[reg_alloc_order[i]] = i; @@ -299,7 +308,6 @@ init_reg_sets_1 (void) { unsigned int i, j; unsigned int /* enum machine_mode */ m; - char allocatable_regs_of_mode [MAX_MACHINE_MODE]; /* This macro allows the fixed or call-used registers and the register classes to depend on target flags. */ @@ -324,10 +332,7 @@ init_reg_sets_1 (void) { for (j = 0; j < N_REG_CLASSES; j++) { -#ifdef HARD_REG_SET - register /* Declare it register if it's a scalar. */ -#endif - HARD_REG_SET c; + HARD_REG_SET c; int k; COPY_HARD_REG_SET (c, reg_class_contents[i]); @@ -358,10 +363,7 @@ init_reg_sets_1 (void) { for (j = 0; j < N_REG_CLASSES; j++) { -#ifdef HARD_REG_SET - register /* Declare it register if it's a scalar. */ -#endif - HARD_REG_SET c; + HARD_REG_SET c; int k; COPY_HARD_REG_SET (c, reg_class_contents[i]); @@ -420,14 +422,17 @@ init_reg_sets_1 (void) memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs); - n_non_fixed_regs = 0; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { + /* call_used_regs must include fixed_regs. */ + gcc_assert (!fixed_regs[i] || call_used_regs[i]); +#ifdef CALL_REALLY_USED_REGISTERS + /* call_used_regs must include call_really_used_regs. */ + gcc_assert (!call_really_used_regs[i] || call_used_regs[i]); +#endif + if (fixed_regs[i]) SET_HARD_REG_BIT (fixed_reg_set, i); - else - n_non_fixed_regs++; if (call_used_regs[i]) SET_HARD_REG_BIT (call_used_reg_set, i); @@ -445,7 +450,11 @@ init_reg_sets_1 (void) If we are generating PIC code, the PIC offset table register is preserved across calls, though the target can override that. */ - if (i == STACK_POINTER_REGNUM || i == FRAME_POINTER_REGNUM) + if (i == STACK_POINTER_REGNUM) + ; + else if (global_regs[i]) + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + else if (i == FRAME_POINTER_REGNUM) ; #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM else if (i == HARD_FRAME_POINTER_REGNUM) @@ -459,18 +468,12 @@ init_reg_sets_1 (void) else if (i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i]) ; #endif - else if (0 -#ifdef CALL_REALLY_USED_REGISTERS - || call_really_used_regs[i] -#else - || call_used_regs[i] -#endif - || global_regs[i]) + else if (CALL_REALLY_USED_REGNO_P (i)) SET_HARD_REG_BIT (regs_invalidated_by_call, i); } + memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode)); memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode)); - memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode)); for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++) for (i = 0; i < N_REG_CLASSES; i++) if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i]) @@ -479,7 +482,7 @@ init_reg_sets_1 (void) && HARD_REGNO_MODE_OK (j, m)) { contains_reg_of_mode [i][m] = 1; - allocatable_regs_of_mode [m] = 1; + have_regs_of_mode [m] = 1; break; } @@ -487,7 +490,7 @@ init_reg_sets_1 (void) and take the maximum cost of moving any subset to any other. */ for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++) - if (allocatable_regs_of_mode [m]) + if (have_regs_of_mode [m]) { for (i = 0; i < N_REG_CLASSES; i++) if (contains_reg_of_mode [i][m]) @@ -548,7 +551,11 @@ init_reg_sets_1 (void) void init_reg_modes_once (void) { - int i; + int i, j; + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + for (j = 0; j < MAX_MACHINE_MODE; j++) + hard_regno_nregs[i][j] = HARD_REGNO_NREGS(i, (enum machine_mode)j); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { @@ -583,17 +590,14 @@ init_regs (void) void init_fake_stack_mems (void) { -#ifdef HAVE_SECONDARY_RELOADS { int i; for (i = 0; i < MAX_MACHINE_MODE; i++) top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx); } -#endif } -#ifdef HAVE_SECONDARY_RELOADS /* Compute extra cost of moving registers to/from memory due to reloads. Only needed if secondary reloads are required for memory moves. */ @@ -608,22 +612,7 @@ memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in rtx mem ATTRIBUTE_UNUSED = top_of_stack[(int) mode]; - if (in) - { -#ifdef SECONDARY_INPUT_RELOAD_CLASS - altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem); -#else - altclass = NO_REGS; -#endif - } - else - { -#ifdef SECONDARY_OUTPUT_RELOAD_CLASS - altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem); -#else - altclass = NO_REGS; -#endif - } + altclass = secondary_reload_class (in ? 1 : 0, class, mode, mem); if (altclass == NO_REGS) return 0; @@ -638,7 +627,7 @@ memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in what it is, so MEMORY_MOVE_COST really ought not to be calling here in that case. - I'm tempted to put in an abort here, but returning this will + I'm tempted to put in an assert here, but returning this will probably only give poor estimates, which is what we would've had before this code anyways. */ return partial_cost; @@ -647,7 +636,6 @@ memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in secondary reload. */ return memory_move_secondary_cost (mode, altclass, in) + partial_cost; } -#endif /* Return a machine mode that is legitimate for hard reg REGNO and large enough to save nregs. If we can't find one, return VOIDmode. @@ -667,7 +655,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs + if ((unsigned) hard_regno_nregs[regno][mode] == nregs && HARD_REGNO_MODE_OK (regno, mode) && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))) found_mode = mode; @@ -678,7 +666,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs + if ((unsigned) hard_regno_nregs[regno][mode] == nregs && HARD_REGNO_MODE_OK (regno, mode) && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))) found_mode = mode; @@ -689,7 +677,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs + if ((unsigned) hard_regno_nregs[regno][mode] == nregs && HARD_REGNO_MODE_OK (regno, mode) && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))) found_mode = mode; @@ -700,7 +688,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs + if ((unsigned) hard_regno_nregs[regno][mode] == nregs && HARD_REGNO_MODE_OK (regno, mode) && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))) found_mode = mode; @@ -712,7 +700,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m) { mode = (enum machine_mode) m; - if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs + if ((unsigned) hard_regno_nregs[regno][mode] == nregs && HARD_REGNO_MODE_OK (regno, mode) && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))) return mode; @@ -764,7 +752,7 @@ fix_register (const char *name, int fixed, int call_used) } else { - warning ("unknown register name: %s", name); + warning (0, "unknown register name: %s", name); } } @@ -778,26 +766,33 @@ globalize_reg (int i) if (global_regs[i]) { - warning ("register used for two global register variables"); + warning (0, "register used for two global register variables"); return; } if (call_used_regs[i] && ! fixed_regs[i]) - warning ("call-clobbered register used for global register variable"); + warning (0, "call-clobbered register used for global register variable"); global_regs[i] = 1; + /* If we're globalizing the frame pointer, we need to set the + appropriate regs_invalidated_by_call bit, even if it's already + set in fixed_regs. */ + if (i != STACK_POINTER_REGNUM) + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + /* If already fixed, nothing else to do. */ if (fixed_regs[i]) return; fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1; - n_non_fixed_regs--; +#ifdef CALL_REALLY_USED_REGISTERS + call_really_used_regs[i] = 1; +#endif SET_HARD_REG_BIT (fixed_reg_set, i); SET_HARD_REG_BIT (call_used_reg_set, i); SET_HARD_REG_BIT (call_fixed_reg_set, i); - SET_HARD_REG_BIT (regs_invalidated_by_call, i); } /* Now the data and code for the `regclass' pass, which happens @@ -816,7 +811,8 @@ struct costs /* Structure used to record preferences of given pseudo. */ struct reg_pref { - /* (enum reg_class) prefclass is the preferred class. */ + /* (enum reg_class) prefclass is the preferred class. May be + NO_REGS if no class is better than memory. */ char prefclass; /* altclass is a register class that we should use for allocating @@ -856,12 +852,37 @@ static void dump_regclass (FILE *); static void record_reg_classes (int, int, rtx *, enum machine_mode *, const char **, rtx, struct costs *, struct reg_pref *); -static int copy_cost (rtx, enum machine_mode, enum reg_class, int); -static void record_address_regs (rtx, enum reg_class, int); +static int copy_cost (rtx, enum machine_mode, enum reg_class, int, + secondary_reload_info *); +static void record_address_regs (enum machine_mode, rtx, int, enum rtx_code, + enum rtx_code, int); #ifdef FORBIDDEN_INC_DEC_CLASSES static int auto_inc_dec_reg_p (rtx, enum machine_mode); #endif -static void reg_scan_mark_refs (rtx, rtx, int, unsigned int); +static void reg_scan_mark_refs (rtx, rtx, int); + +/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudo registers. */ + +static inline bool +ok_for_index_p_nonstrict (rtx reg) +{ + unsigned regno = REGNO (reg); + return regno >= FIRST_PSEUDO_REGISTER || REGNO_OK_FOR_INDEX_P (regno); +} + +/* A version of regno_ok_for_base_p for use during regclass, when all pseudos + should count as OK. Arguments as for regno_ok_for_base_p. */ + +static inline bool +ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, + enum rtx_code outer_code, enum rtx_code index_code) +{ + unsigned regno = REGNO (reg); + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return ok_for_base_p_1 (regno, mode, outer_code, index_code); +} /* Return the reg_class in which pseudo reg number REGNO is best allocated. This function is sometimes called before the info has been computed. @@ -907,7 +928,6 @@ regclass_init (void) static void dump_regclass (FILE *dump) { - static const char *const reg_class_names[] = REG_CLASS_NAMES; int i; for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) { @@ -963,13 +983,14 @@ record_operand_costs (rtx insn, struct costs *op_costs, if (GET_CODE (recog_data.operand[i]) == SUBREG) recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]); - if (GET_CODE (recog_data.operand[i]) == MEM) - record_address_regs (XEXP (recog_data.operand[i], 0), - MODE_BASE_REG_CLASS (modes[i]), frequency * 2); + if (MEM_P (recog_data.operand[i])) + record_address_regs (GET_MODE (recog_data.operand[i]), + XEXP (recog_data.operand[i], 0), + 0, MEM, SCRATCH, frequency * 2); else if (constraints[i][0] == 'p' || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i])) - record_address_regs (recog_data.operand[i], - MODE_BASE_REG_CLASS (modes[i]), frequency * 2); + record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS, + SCRATCH, frequency * 2); } /* Check for commutative in a separate loop so everything will @@ -1010,13 +1031,12 @@ record_operand_costs (rtx insn, struct costs *op_costs, static rtx scan_one_insn (rtx insn, int pass) { - enum rtx_code code = GET_CODE (insn); enum rtx_code pat_code; rtx set, note; int i, j; struct costs op_costs[MAX_RECOG_OPERANDS]; - if (GET_RTX_CLASS (code) != 'i') + if (!INSN_P (insn)) return insn; pat_code = GET_CODE (PATTERN (insn)); @@ -1034,18 +1054,18 @@ scan_one_insn (rtx insn, int pass) it represents a savings, rather than a cost, if the parameter is stored in memory. Record this fact. */ - if (set != 0 && GET_CODE (SET_DEST (set)) == REG - && GET_CODE (SET_SRC (set)) == MEM + if (set != 0 && REG_P (SET_DEST (set)) + && MEM_P (SET_SRC (set)) && (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0 - && GET_CODE (XEXP (note, 0)) == MEM) + && MEM_P (XEXP (note, 0))) { costs[REGNO (SET_DEST (set))].mem_cost -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)), GENERAL_REGS, 1) * frequency); - record_address_regs (XEXP (SET_SRC (set), 0), - MODE_BASE_REG_CLASS (VOIDmode), frequency * 2); + record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0), + 0, MEM, SCRATCH, frequency * 2); return insn; } @@ -1068,7 +1088,7 @@ scan_one_insn (rtx insn, int pass) && CONSTANT_P (recog_data.operand[1]) && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[1]) && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[2]) - && GET_CODE (recog_data.operand[0]) == REG + && REG_P (recog_data.operand[0]) && MODES_TIEABLE_P (GET_MODE (recog_data.operand[0]), recog_data.operand_mode[1])) { @@ -1084,12 +1104,12 @@ scan_one_insn (rtx insn, int pass) We need not check for code_label here; while a basic block can start with a code_label, INSN could not be at the beginning of that block. */ - if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN) + if (previnsn == 0 || JUMP_P (previnsn)) { basic_block b; FOR_EACH_BB (b) - if (insn == b->head) - b->head = newinsn; + if (insn == BB_HEAD (b)) + BB_HEAD (b) = newinsn; } /* This makes one more setting of new insns's dest. */ @@ -1117,7 +1137,7 @@ scan_one_insn (rtx insn, int pass) its register. */ for (i = 0; i < recog_data.n_operands; i++) - if (GET_CODE (recog_data.operand[i]) == REG + if (REG_P (recog_data.operand[i]) && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER) { int regno = REGNO (recog_data.operand[i]); @@ -1155,6 +1175,13 @@ init_reg_autoinc (void) m = (enum machine_mode) ((int) m + 1)) if (HARD_REGNO_MODE_OK (j, m)) { + /* ??? There are two assumptions here; that the base class does not + depend on the exact outer code (POST_INC vs. PRE_INC etc.), and + that it does not depend on the machine mode of the memory + reference. */ + enum reg_class base_class + = base_reg_class (VOIDmode, POST_INC, SCRATCH); + PUT_MODE (r, m); /* If a register is not directly suitable for an @@ -1162,21 +1189,8 @@ init_reg_autoinc (void) requires secondary reloads, disallow its class from being used in such addresses. */ - if ((0 -#ifdef SECONDARY_RELOAD_CLASS - || (SECONDARY_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r) - != NO_REGS) -#else -#ifdef SECONDARY_INPUT_RELOAD_CLASS - || (SECONDARY_INPUT_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r) - != NO_REGS) -#endif -#ifdef SECONDARY_OUTPUT_RELOAD_CLASS - || (SECONDARY_OUTPUT_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r) - != NO_REGS) -#endif -#endif - ) + if ((secondary_reload_class (1, base_class, m, r) + || secondary_reload_class (1, base_class, m, r)) && ! auto_inc_dec_reg_p (r, m)) forbidden_inc_dec_class[i] = 1; } @@ -1191,7 +1205,7 @@ init_reg_autoinc (void) This pass comes just before local register allocation. */ void -regclass (rtx f, int nregs, FILE *dump) +regclass (rtx f, int nregs) { rtx insn; int i; @@ -1199,11 +1213,11 @@ regclass (rtx f, int nregs, FILE *dump) init_recog (); - costs = xmalloc (nregs * sizeof (struct costs)); + costs = XNEWVEC (struct costs, nregs); #ifdef FORBIDDEN_INC_DEC_CLASSES - in_inc_dec = xmalloc (nregs); + in_inc_dec = XNEWVEC (char, nregs); #endif /* FORBIDDEN_INC_DEC_CLASSES */ @@ -1216,8 +1230,8 @@ regclass (rtx f, int nregs, FILE *dump) { basic_block bb; - if (dump) - fprintf (dump, "\n\nPass %i\n\n",pass); + if (dump_file) + fprintf (dump_file, "\n\nPass %i\n\n",pass); /* Zero out our accumulation of the cost of each class for each reg. */ memset (costs, 0, nregs * sizeof (struct costs)); @@ -1243,10 +1257,10 @@ regclass (rtx f, int nregs, FILE *dump) aggressive than the assumptions made elsewhere and is being tried as an experiment. */ frequency = REG_FREQ_FROM_BB (bb); - for (insn = bb->head; ; insn = NEXT_INSN (insn)) + for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) { insn = scan_one_insn (insn, pass); - if (insn == bb->end) + if (insn == BB_END (bb)) break; } } @@ -1259,10 +1273,10 @@ regclass (rtx f, int nregs, FILE *dump) if (pass == 0) reg_pref = reg_pref_buffer; - if (dump) + if (dump_file) { - dump_regclass (dump); - fprintf (dump,"\n"); + dump_regclass (dump_file); + fprintf (dump_file,"\n"); } for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++) { @@ -1301,6 +1315,10 @@ regclass (rtx f, int nregs, FILE *dump) best = reg_class_subunion[(int) best][class]; } + /* If no register class is better than memory, use memory. */ + if (p->mem_cost < best_cost) + best = NO_REGS; + /* Record the alternate register class; i.e., a class for which every register in it is better than using memory. If adding a class would make a smaller class (i.e., no union of just those @@ -1308,7 +1326,7 @@ regclass (rtx f, int nregs, FILE *dump) should be provided as a register class. Don't do this if we will be doing it again later. */ - if ((pass == 1 || dump) || ! flag_expensive_optimizations) + if ((pass == 1 || dump_file) || ! flag_expensive_optimizations) for (class = 0; class < N_REG_CLASSES; class++) if (p->cost[class] < p->mem_cost && (reg_class_size[(int) reg_class_subunion[(int) alt][class]] @@ -1327,18 +1345,17 @@ regclass (rtx f, int nregs, FILE *dump) if (alt == best) alt = NO_REGS; - if (dump + if (dump_file && (reg_pref[i].prefclass != (int) best || reg_pref[i].altclass != (int) alt)) { - static const char *const reg_class_names[] = REG_CLASS_NAMES; - fprintf (dump, " Register %i", i); + fprintf (dump_file, " Register %i", i); if (alt == ALL_REGS || best == ALL_REGS) - fprintf (dump, " pref %s\n", reg_class_names[(int) best]); + fprintf (dump_file, " pref %s\n", reg_class_names[(int) best]); else if (alt == NO_REGS) - fprintf (dump, " pref %s or none\n", reg_class_names[(int) best]); + fprintf (dump_file, " pref %s or none\n", reg_class_names[(int) best]); else - fprintf (dump, " pref %s, else %s\n", + fprintf (dump_file, " pref %s, else %s\n", reg_class_names[(int) best], reg_class_names[(int) alt]); } @@ -1419,7 +1436,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, if (*p == 0) { - if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) + if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) memset (&this_op_costs[i], 0, sizeof this_op_costs[i]); continue; @@ -1442,7 +1459,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, classes[i] = classes[j]; allows_mem[i] = allows_mem[j]; - if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER) + if (!REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER) { /* If this matches the other operand, we have no added cost and we win. */ @@ -1454,9 +1471,12 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, operand to the register used for the other operand. */ else if (classes[j] != NO_REGS) - alt_cost += copy_cost (op, mode, classes[j], 1), win = 1; + { + alt_cost += copy_cost (op, mode, classes[j], 1, NULL); + win = 1; + } } - else if (GET_CODE (ops[j]) != REG + else if (!REG_P (ops[j]) || REGNO (ops[j]) < FIRST_PSEUDO_REGISTER) { /* This op is a pseudo but the one it matches is not. */ @@ -1472,7 +1492,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, operand. */ else - alt_cost += copy_cost (ops[j], mode, classes[j], 1); + alt_cost += copy_cost (ops[j], mode, classes[j], 1, NULL); } else { @@ -1509,7 +1529,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, to what we would add if this register were not in the appropriate class. */ - if (reg_pref) + if (reg_pref && reg_pref[REGNO (op)].prefclass != NO_REGS) alt_cost += (may_move_in_cost[mode] [(unsigned char) reg_pref[REGNO (op)].prefclass] @@ -1557,29 +1577,29 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, win = address_operand (op, GET_MODE (op)); /* We know this operand is an address, so we want it to be allocated to a register that can be the base of an - address, ie BASE_REG_CLASS. */ + address, i.e. BASE_REG_CLASS. */ classes[i] = reg_class_subunion[(int) classes[i]] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]; + [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; break; case 'm': case 'o': case 'V': /* It doesn't seem worth distinguishing between offsettable and non-offsettable addresses here. */ allows_mem[i] = 1; - if (GET_CODE (op) == MEM) + if (MEM_P (op)) 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; @@ -1608,10 +1628,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, break; case 'i': if (CONSTANT_P (op) -#ifdef LEGITIMATE_PIC_OPERAND_P - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif - ) + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) win = 1; break; @@ -1640,12 +1657,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, break; case 'g': - if (GET_CODE (op) == MEM + if (MEM_P (op) || (CONSTANT_P (op) -#ifdef LEGITIMATE_PIC_OPERAND_P - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif - )) + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))) win = 1; allows_mem[i] = 1; case 'r': @@ -1666,7 +1680,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, { /* Every MEM can be reloaded to fit. */ allows_mem[i] = 1; - if (GET_CODE (op) == MEM) + if (MEM_P (op)) win = 1; } if (EXTRA_ADDRESS_CONSTRAINT (c, p)) @@ -1677,10 +1691,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, win = 1; /* We know this operand is an address, so we want it to be allocated to a register that can be the base of an - address, ie BASE_REG_CLASS. */ + address, i.e. BASE_REG_CLASS. */ classes[i] = reg_class_subunion[(int) classes[i]] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]; + [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; } #endif break; @@ -1699,7 +1713,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, register preferencing. If some register class is valid, compute the costs of moving the pseudo into that class. */ - if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) + if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) { if (classes[i] == NO_REGS) { @@ -1741,7 +1755,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, to what we would add if this register were not in the appropriate class. */ - if (reg_pref) + if (reg_pref && reg_pref[REGNO (op)].prefclass != NO_REGS) alt_cost += (may_move_in_cost[mode] [(unsigned char) reg_pref[REGNO (op)].prefclass] @@ -1754,7 +1768,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, the proper class, there is no cost for this alternative. */ else if (win - || (GET_CODE (op) == REG + || (REG_P (op) && reg_fits_class_p (op, classes[i], 0, GET_MODE (op)))) ; @@ -1764,10 +1778,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, else if (classes[i] != NO_REGS) { if (recog_data.operand_type[i] != OP_OUT) - alt_cost += copy_cost (op, mode, classes[i], 1); + alt_cost += copy_cost (op, mode, classes[i], 1, NULL); if (recog_data.operand_type[i] != OP_IN) - alt_cost += copy_cost (op, mode, classes[i], 0); + alt_cost += copy_cost (op, mode, classes[i], 0, NULL); } /* The only other way this alternative can be used is if this is a @@ -1786,7 +1800,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, about this alternative. */ for (i = 0; i < n_ops; i++) - if (GET_CODE (ops[i]) == REG + if (REG_P (ops[i]) && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) { struct costs *pp = &op_costs[i], *qq = &this_op_costs[i]; @@ -1817,7 +1831,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, if ((set = single_set (insn)) != 0 && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set) - && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG + && REG_P (ops[0]) && REG_P (ops[1]) && find_regno_note (insn, REG_DEAD, REGNO (ops[1]))) for (i = 0; i <= 1; i++) if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) @@ -1827,7 +1841,8 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, int class; unsigned int nr; - if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0) + if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0 + && reg_pref[regno].prefclass != NO_REGS) { enum reg_class pref = reg_pref[regno].prefclass; @@ -1845,14 +1860,14 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, op_costs[i].cost[class] = -1; else { - for (nr = 0; nr < (unsigned) HARD_REGNO_NREGS (regno, mode); nr++) + for (nr = 0; nr < (unsigned) hard_regno_nregs[regno][mode]; nr++) { if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr)) break; } - if (nr == (unsigned) HARD_REGNO_NREGS (regno,mode)) + if (nr == (unsigned) hard_regno_nregs[regno][mode]) op_costs[i].cost[class] = -1; } } @@ -1865,12 +1880,11 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, X must not be a pseudo. */ static int -copy_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED, - enum reg_class class, int to_p ATTRIBUTE_UNUSED) +copy_cost (rtx x, enum machine_mode mode, enum reg_class class, int to_p, + secondary_reload_info *prev_sri) { -#ifdef HAVE_SECONDARY_RELOADS enum reg_class secondary_class = NO_REGS; -#endif + secondary_reload_info sri; /* If X is a SCRATCH, there is actually nothing to move since we are assuming optimal allocation. */ @@ -1881,55 +1895,60 @@ copy_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED, /* Get the class we will actually use for a reload. */ class = PREFERRED_RELOAD_CLASS (x, class); -#ifdef HAVE_SECONDARY_RELOADS - /* If we need a secondary reload (we assume here that we are using - the secondary reload as an intermediate, not a scratch register), the + /* If we need a secondary reload for an intermediate, the cost is that to load the input into the intermediate register, then - to copy them. We use a special value of TO_P to avoid recursion. */ + to copy it. */ -#ifdef SECONDARY_INPUT_RELOAD_CLASS - if (to_p == 1) - secondary_class = SECONDARY_INPUT_RELOAD_CLASS (class, mode, x); -#endif - -#ifdef SECONDARY_OUTPUT_RELOAD_CLASS - if (! to_p) - secondary_class = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x); -#endif + sri.prev_sri = prev_sri; + sri.extra_cost = 0; + secondary_class = targetm.secondary_reload (to_p, x, class, mode, &sri); if (secondary_class != NO_REGS) return (move_cost[mode][(int) secondary_class][(int) class] - + copy_cost (x, mode, secondary_class, 2)); -#endif /* HAVE_SECONDARY_RELOADS */ + + sri.extra_cost + + copy_cost (x, mode, secondary_class, to_p, &sri)); /* For memory, use the memory move cost, for (hard) registers, use the cost to move between the register classes, and use 2 for everything else (constants). */ - if (GET_CODE (x) == MEM || class == NO_REGS) - return MEMORY_MOVE_COST (mode, class, to_p); + if (MEM_P (x) || class == NO_REGS) + return sri.extra_cost + MEMORY_MOVE_COST (mode, class, to_p); - else if (GET_CODE (x) == REG) - return move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class]; + else if (REG_P (x)) + return (sri.extra_cost + + move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class]); else /* If this is a constant, we may eventually want to call rtx_cost here. */ - return COSTS_N_INSNS (1); + return sri.extra_cost + COSTS_N_INSNS (1); } /* Record the pseudo registers we must reload into hard registers in a subexpression of a memory address, X. - CLASS is the class that the register needs to be in and is either - BASE_REG_CLASS or INDEX_REG_CLASS. + If CONTEXT is 0, we are looking at the base part of an address, otherwise we + are looking at the index part. + + MODE is the mode of the memory reference; OUTER_CODE and INDEX_CODE + give the context that the rtx appears in. These three arguments are + passed down to base_reg_class. SCALE is twice the amount to multiply the cost by (it is twice so we can represent half-cost adjustments). */ static void -record_address_regs (rtx x, enum reg_class class, int scale) +record_address_regs (enum machine_mode mode, rtx x, int context, + enum rtx_code outer_code, enum rtx_code index_code, + int scale) { enum rtx_code code = GET_CODE (x); + enum reg_class class; + + if (context == 1) + class = INDEX_REG_CLASS; + else + class = base_reg_class (mode, outer_code, index_code); switch (code) { @@ -1970,52 +1989,52 @@ record_address_regs (rtx x, enum reg_class class, int scale) be in the first operand. */ if (MAX_REGS_PER_ADDRESS == 1) - record_address_regs (arg0, class, scale); + record_address_regs (mode, arg0, 0, PLUS, code1, scale); /* If index and base registers are the same on this machine, just record registers in any non-constant operands. We assume here, as well as in the tests below, that all addresses are in canonical form. */ - else if (INDEX_REG_CLASS == MODE_BASE_REG_CLASS (VOIDmode)) + else if (INDEX_REG_CLASS == base_reg_class (VOIDmode, PLUS, SCRATCH)) { - record_address_regs (arg0, class, scale); + record_address_regs (mode, arg0, context, PLUS, code1, scale); if (! CONSTANT_P (arg1)) - record_address_regs (arg1, class, scale); + record_address_regs (mode, arg1, context, PLUS, code0, scale); } /* If the second operand is a constant integer, it doesn't change what class the first operand must be. */ else if (code1 == CONST_INT || code1 == CONST_DOUBLE) - record_address_regs (arg0, class, scale); + record_address_regs (mode, arg0, context, PLUS, code1, scale); /* If the second operand is a symbolic constant, the first operand must be an index register. */ else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF) - record_address_regs (arg0, INDEX_REG_CLASS, scale); + record_address_regs (mode, arg0, 1, PLUS, code1, scale); /* If both operands are registers but one is already a hard register - of index or base class, give the other the class that the hard - register is not. */ + of index or reg-base class, give the other the class that the + hard register is not. */ -#ifdef REG_OK_FOR_BASE_P else if (code0 == REG && code1 == REG && REGNO (arg0) < FIRST_PSEUDO_REGISTER - && (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0))) - record_address_regs (arg1, - REG_OK_FOR_BASE_P (arg0) - ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (VOIDmode), - scale); + && (ok_for_base_p_nonstrict (arg0, mode, PLUS, REG) + || ok_for_index_p_nonstrict (arg0))) + record_address_regs (mode, arg1, + ok_for_base_p_nonstrict (arg0, mode, PLUS, REG) + ? 1 : 0, + PLUS, REG, scale); else if (code0 == REG && code1 == REG && REGNO (arg1) < FIRST_PSEUDO_REGISTER - && (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1))) - record_address_regs (arg0, - REG_OK_FOR_BASE_P (arg1) - ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (VOIDmode), - scale); -#endif + && (ok_for_base_p_nonstrict (arg1, mode, PLUS, REG) + || ok_for_index_p_nonstrict (arg1))) + record_address_regs (mode, arg0, + ok_for_base_p_nonstrict (arg1, mode, PLUS, REG) + ? 1 : 0, + PLUS, REG, scale); /* If one operand is known to be a pointer, it must be the base with the other operand the index. Likewise if the other operand @@ -2024,14 +2043,14 @@ record_address_regs (rtx x, enum reg_class class, int scale) else if ((code0 == REG && REG_POINTER (arg0)) || code1 == MULT) { - record_address_regs (arg0, MODE_BASE_REG_CLASS (VOIDmode), scale); - record_address_regs (arg1, INDEX_REG_CLASS, scale); + record_address_regs (mode, arg0, 0, PLUS, code1, scale); + record_address_regs (mode, arg1, 1, PLUS, code0, scale); } else if ((code1 == REG && REG_POINTER (arg1)) || code0 == MULT) { - record_address_regs (arg0, INDEX_REG_CLASS, scale); - record_address_regs (arg1, MODE_BASE_REG_CLASS (VOIDmode), scale); + record_address_regs (mode, arg0, 1, PLUS, code1, scale); + record_address_regs (mode, arg1, 0, PLUS, code0, scale); } /* Otherwise, count equal chances that each might be a base @@ -2039,12 +2058,10 @@ record_address_regs (rtx x, enum reg_class class, int scale) else { - record_address_regs (arg0, MODE_BASE_REG_CLASS (VOIDmode), - scale / 2); - record_address_regs (arg0, INDEX_REG_CLASS, scale / 2); - record_address_regs (arg1, MODE_BASE_REG_CLASS (VOIDmode), - scale / 2); - record_address_regs (arg1, INDEX_REG_CLASS, scale / 2); + record_address_regs (mode, arg0, 0, PLUS, code1, scale / 2); + record_address_regs (mode, arg0, 1, PLUS, code1, scale / 2); + record_address_regs (mode, arg1, 0, PLUS, code0, scale / 2); + record_address_regs (mode, arg1, 1, PLUS, code0, scale / 2); } } break; @@ -2054,11 +2071,11 @@ record_address_regs (rtx x, enum reg_class class, int scale) if it ends up in the wrong place. */ case POST_MODIFY: case PRE_MODIFY: - record_address_regs (XEXP (x, 0), MODE_BASE_REG_CLASS (VOIDmode), - 2 * scale); + record_address_regs (mode, XEXP (x, 0), 0, code, + GET_CODE (XEXP (XEXP (x, 1), 1)), 2 * scale); if (REG_P (XEXP (XEXP (x, 1), 1))) - record_address_regs (XEXP (XEXP (x, 1), 1), - INDEX_REG_CLASS, 2 * scale); + record_address_regs (mode, XEXP (XEXP (x, 1), 1), 1, code, REG, + 2 * scale); break; case POST_INC: @@ -2071,12 +2088,12 @@ record_address_regs (rtx x, enum reg_class class, int scale) show it is being used in an INC_DEC context. */ #ifdef FORBIDDEN_INC_DEC_CLASSES - if (GET_CODE (XEXP (x, 0)) == REG + if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER) in_inc_dec[REGNO (XEXP (x, 0))] = 1; #endif - record_address_regs (XEXP (x, 0), class, 2 * scale); + record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale); break; case REG: @@ -2097,7 +2114,8 @@ record_address_regs (rtx x, enum reg_class class, int scale) int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') - record_address_regs (XEXP (x, i), class, scale); + record_address_regs (mode, XEXP (x, i), context, code, SCRATCH, + scale); } } } @@ -2158,29 +2176,41 @@ allocate_reg_info (size_t num_regs, int new_p, int renumber_p) if (!reg_n_info) { - VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info"); + reg_n_info = VEC_alloc (reg_info_p, heap, regno_allocated); + VEC_safe_grow (reg_info_p, heap, reg_n_info, regno_allocated); + memset (VEC_address (reg_info_p, reg_n_info), 0, + sizeof (reg_info_p) * regno_allocated); renumber = xmalloc (size_renumber); - reg_pref_buffer = xmalloc (regno_allocated - * sizeof (struct reg_pref)); + reg_pref_buffer = XNEWVEC (struct reg_pref, regno_allocated); } - else { - VARRAY_GROW (reg_n_info, regno_allocated); + size_t old_length = VEC_length (reg_info_p, reg_n_info); + if (old_length < regno_allocated) + { + reg_info_p *addr; + VEC_safe_grow (reg_info_p, heap, reg_n_info, regno_allocated); + addr = VEC_address (reg_info_p, reg_n_info); + memset (&addr[old_length], 0, + sizeof (reg_info_p) * (regno_allocated - old_length)); + } + else if (regno_allocated < old_length) + { + VEC_truncate (reg_info_p, reg_n_info, regno_allocated); + } if (new_p) /* If we're zapping everything, no need to realloc. */ { free ((char *) renumber); free ((char *) reg_pref); renumber = xmalloc (size_renumber); - reg_pref_buffer = xmalloc (regno_allocated - * sizeof (struct reg_pref)); + reg_pref_buffer = XNEWVEC (struct reg_pref, regno_allocated); } else { renumber = xrealloc (renumber, size_renumber); - reg_pref_buffer = xrealloc (reg_pref_buffer, + reg_pref_buffer = (struct reg_pref *) xrealloc (reg_pref_buffer, regno_allocated * sizeof (struct reg_pref)); } @@ -2223,7 +2253,8 @@ allocate_reg_info (size_t num_regs, int new_p, int renumber_p) for (i = min_index+local_min; i <= max; i++) { - VARRAY_REG (reg_n_info, i) = ®_data->data[i-min_index]; + VEC_replace (reg_info_p, reg_n_info, i, + ®_data->data[i-min_index]); REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN; renumber[i] = -1; reg_pref_buffer[i].prefclass = (char) NO_REGS; @@ -2239,9 +2270,6 @@ allocate_reg_info (size_t num_regs, int new_p, int renumber_p) if (renumber_p) reg_renumber = renumber; - - /* Tell the regset code about the new number of registers. */ - MAX_REGNO_REG_SET (num_regs, new_p, renumber_p); } /* Free up the space allocated by allocate_reg_info. */ @@ -2253,7 +2281,7 @@ free_reg_info (void) struct reg_info_data *reg_data; struct reg_info_data *reg_next; - VARRAY_FREE (reg_n_info); + VEC_free (reg_info_p, heap, reg_n_info); for (reg_data = reg_info_head; reg_data; reg_data = reg_next) { reg_next = reg_data->next; @@ -2292,28 +2320,27 @@ int max_parallel; static int max_set_parallel; void -reg_scan (rtx f, unsigned int nregs, int repeat ATTRIBUTE_UNUSED) +reg_scan (rtx f, unsigned int nregs) { rtx insn; + timevar_push (TV_REG_SCAN); + allocate_reg_info (nregs, TRUE, FALSE); max_parallel = 3; max_set_parallel = 0; - timevar_push (TV_REG_SCAN); - for (insn = f; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == INSN - || GET_CODE (insn) == CALL_INSN - || GET_CODE (insn) == JUMP_INSN) + if (INSN_P (insn)) { - if (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) > max_parallel) - max_parallel = XVECLEN (PATTERN (insn), 0); - reg_scan_mark_refs (PATTERN (insn), insn, 0, 0); + rtx pat = PATTERN (insn); + if (GET_CODE (pat) == PARALLEL + && XVECLEN (pat, 0) > max_parallel) + max_parallel = XVECLEN (pat, 0); + reg_scan_mark_refs (pat, insn, 0); if (REG_NOTES (insn)) - reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0); + reg_scan_mark_refs (REG_NOTES (insn), insn, 1); } max_parallel += max_set_parallel; @@ -2321,40 +2348,11 @@ reg_scan (rtx f, unsigned int nregs, int repeat ATTRIBUTE_UNUSED) timevar_pop (TV_REG_SCAN); } -/* Update 'regscan' information by looking at the insns - from FIRST to LAST. Some new REGs have been created, - and any REG with number greater than OLD_MAX_REGNO is - such a REG. We only update information for those. */ - -void -reg_scan_update (rtx first, rtx last, unsigned int old_max_regno) -{ - rtx insn; - - allocate_reg_info (max_reg_num (), FALSE, FALSE); - - for (insn = first; insn != last; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == INSN - || GET_CODE (insn) == CALL_INSN - || GET_CODE (insn) == JUMP_INSN) - { - if (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) > max_parallel) - max_parallel = XVECLEN (PATTERN (insn), 0); - reg_scan_mark_refs (PATTERN (insn), insn, 0, old_max_regno); - - if (REG_NOTES (insn)) - reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno); - } -} - /* X is the expression to scan. INSN is the insn it appears in. - NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. - We should only record information for REGs with numbers - greater than or equal to MIN_REGNO. */ + NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. */ static void -reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) +reg_scan_mark_refs (rtx x, rtx insn, int note_flag) { enum rtx_code code; rtx dest; @@ -2381,42 +2379,35 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) { unsigned int regno = REGNO (x); - if (regno >= min_regno) - { - REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn); - if (!note_flag) - REGNO_LAST_UID (regno) = INSN_UID (insn); - if (REGNO_FIRST_UID (regno) == 0) - REGNO_FIRST_UID (regno) = INSN_UID (insn); - /* If we are called by reg_scan_update() (indicated by min_regno - being set), we also need to update the reference count. */ - if (min_regno) - REG_N_REFS (regno)++; - } + if (!note_flag) + REGNO_LAST_UID (regno) = INSN_UID (insn); + if (REGNO_FIRST_UID (regno) == 0) + REGNO_FIRST_UID (regno) = INSN_UID (insn); } break; case EXPR_LIST: if (XEXP (x, 0)) - reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno); + reg_scan_mark_refs (XEXP (x, 0), insn, note_flag); if (XEXP (x, 1)) - reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno); + reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); break; case INSN_LIST: if (XEXP (x, 1)) - reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno); + reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); break; case CLOBBER: { rtx reg = XEXP (x, 0); - if (REG_P (reg) - && REGNO (reg) >= min_regno) + if (REG_P (reg)) { REG_N_SETS (REGNO (reg))++; REG_N_REFS (REGNO (reg))++; } + else if (MEM_P (reg)) + reg_scan_mark_refs (XEXP (reg, 0), insn, note_flag); } break; @@ -2433,8 +2424,7 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) if (GET_CODE (dest) == PARALLEL) max_set_parallel = MAX (max_set_parallel, XVECLEN (dest, 0) - 1); - if (GET_CODE (dest) == REG - && REGNO (dest) >= min_regno) + if (REG_P (dest)) { REG_N_SETS (REGNO (dest))++; REG_N_REFS (REGNO (dest))++; @@ -2452,9 +2442,8 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) variable since it should have already been set as a pointer based on the type. */ - if (GET_CODE (SET_DEST (x)) == REG + if (REG_P (SET_DEST (x)) && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER - && REGNO (SET_DEST (x)) >= min_regno /* If the destination pseudo is set more than once, then other sets might not be to a pointer value (consider access to a union in two threads of control in the presence of global @@ -2463,12 +2452,12 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) && REG_N_SETS (REGNO (SET_DEST (x))) == 1 && ! REG_USERVAR_P (SET_DEST (x)) && ! REG_POINTER (SET_DEST (x)) - && ((GET_CODE (SET_SRC (x)) == REG + && ((REG_P (SET_SRC (x)) && REG_POINTER (SET_SRC (x))) || ((GET_CODE (SET_SRC (x)) == PLUS || GET_CODE (SET_SRC (x)) == LO_SUM) && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT - && GET_CODE (XEXP (SET_SRC (x), 0)) == REG + && REG_P (XEXP (SET_SRC (x), 0)) && REG_POINTER (XEXP (SET_SRC (x), 0))) || GET_CODE (SET_SRC (x)) == CONST || GET_CODE (SET_SRC (x)) == SYMBOL_REF @@ -2490,7 +2479,7 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) /* If this is setting a register from a register or from a simple conversion of a register, propagate REG_EXPR. */ - if (GET_CODE (dest) == REG) + if (REG_P (dest)) { rtx src = SET_SRC (x); @@ -2502,7 +2491,7 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) if (!REG_ATTRS (dest) && REG_P (src)) REG_ATTRS (dest) = REG_ATTRS (src); - if (!REG_ATTRS (dest) && GET_CODE (src) == MEM) + if (!REG_ATTRS (dest) && MEM_P (src)) set_reg_attrs_from_mem (dest, src); } @@ -2515,12 +2504,12 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno); + reg_scan_mark_refs (XEXP (x, i), insn, note_flag); else if (fmt[i] == 'E' && XVEC (x, i) != 0) { int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) - reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno); + reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag); } } } @@ -2549,10 +2538,7 @@ reg_class_subset_p (enum reg_class c1, enum reg_class c2) int reg_classes_intersect_p (enum reg_class c1, enum reg_class c2) { -#ifdef HARD_REG_SET - register -#endif - HARD_REG_SET c; + HARD_REG_SET c; if (c1 == c2) return 1; @@ -2569,15 +2555,71 @@ reg_classes_intersect_p (enum reg_class c1, enum reg_class c2) return 0; } -/* Release any memory allocated by register sets. */ +#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 *a = x; + return a->block; +} + +static int +som_eq (const void *x, const void *y) +{ + const struct subregs_of_mode_node *a = x; + const struct subregs_of_mode_node *b = y; + return a->block == b->block; +} void -regset_release_memory (void) +init_subregs_of_mode (void) { - bitmap_release_memory (); + if (subregs_of_mode) + htab_empty (subregs_of_mode); + else + subregs_of_mode = htab_create (100, som_hash, som_eq, free); +} + +void +record_subregs_of_mode (rtx subreg) +{ + struct subregs_of_mode_node dummy, *node; + enum machine_mode mode; + unsigned int regno; + void **slot; + + if (!REG_P (SUBREG_REG (subreg))) + return; + + regno = REGNO (SUBREG_REG (subreg)); + mode = GET_MODE (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 = *slot; + if (node == NULL) + { + node = XCNEW (struct subregs_of_mode_node); + node->block = regno & -8; + *slot = node; + } + + node->modes[mode] |= 1 << (regno & 7); } -#ifdef CANNOT_CHANGE_MODE_CLASS /* Set bits in *USED which correspond to registers which can't change their mode from FROM to any mode in which REGNO was encountered. */ @@ -2585,19 +2627,23 @@ void cannot_change_mode_set_regs (HARD_REG_SET *used, enum machine_mode from, unsigned int regno) { + struct subregs_of_mode_node dummy, *node; enum machine_mode to; - int n, i; - int start = regno * MAX_MACHINE_MODE; + unsigned char mask; + unsigned int i; - EXECUTE_IF_SET_IN_BITMAP (&subregs_of_mode, start, n, - if (n >= MAX_MACHINE_MODE + start) - return; - to = n - start; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! TEST_HARD_REG_BIT (*used, i) - && REG_CANNOT_CHANGE_MODE_P (i, from, to)) - SET_HARD_REG_BIT (*used, i); - ); + dummy.block = regno & -8; + node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); + if (node == NULL) + return; + + mask = 1 << (regno & 7); + for (to = VOIDmode; to < NUM_MACHINE_MODES; to++) + if (node->modes[to] & mask) + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (!TEST_HARD_REG_BIT (*used, i) + && REG_CANNOT_CHANGE_MODE_P (i, from, to)) + SET_HARD_REG_BIT (*used, i); } /* Return 1 if REGNO has had an invalid mode change in CLASS from FROM @@ -2605,20 +2651,24 @@ cannot_change_mode_set_regs (HARD_REG_SET *used, enum machine_mode from, bool invalid_mode_change_p (unsigned int regno, enum reg_class class, - enum machine_mode from_mode) + enum machine_mode from) { - enum machine_mode to_mode; - int n; - int start = regno * MAX_MACHINE_MODE; - - EXECUTE_IF_SET_IN_BITMAP (&subregs_of_mode, start, n, - if (n >= MAX_MACHINE_MODE + start) - return 0; - to_mode = n - start; - if (CANNOT_CHANGE_MODE_CLASS (from_mode, to_mode, class)) - return 1; - ); - return 0; + struct subregs_of_mode_node dummy, *node; + enum machine_mode to; + unsigned char mask; + + dummy.block = regno & -8; + 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, to, class)) + return true; + + return false; } #endif /* CANNOT_CHANGE_MODE_CLASS */