X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fregclass.c;h=200f3eefa5812634f32b17ee0d8a656c5876f137;hp=668d92d4bea66c9d53faeb3e4740174a311fdb2f;hb=e101b9bf8101dbe59eb185e70db7ad293b3d71d6;hpb=4c5da23833f4604c04fb829abf1a39ab6976e7b2 diff --git a/gcc/regclass.c b/gcc/regclass.c index 668d92d4bea..200f3eefa58 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -1,12 +1,13 @@ /* Compute register class preferences for pseudo-registers. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996 - 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This file contains two passes of the compiler: reg_scan and reg_class. @@ -26,13 +26,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "hard-reg-set.h" #include "rtl.h" #include "expr.h" #include "tm_p.h" -#include "hard-reg-set.h" #include "flags.h" #include "basic-block.h" #include "regs.h" +#include "addresses.h" #include "function.h" #include "insn-config.h" #include "recog.h" @@ -41,23 +44,27 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "toplev.h" #include "output.h" #include "ggc.h" +#include "timevar.h" +#include "hashtab.h" +#include "target.h" +#include "tree-pass.h" +#include "df.h" -#ifndef REGISTER_MOVE_COST -#define REGISTER_MOVE_COST(m, x, y) 2 -#endif +/* Maximum register number used in this function, plus one. */ + +int max_regno; -static void init_reg_sets_1 PARAMS ((void)); -static void init_reg_modes PARAMS ((void)); +static void init_reg_sets_1 (void); +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. */ @@ -104,6 +111,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 @@ -115,10 +129,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 @@ -164,11 +174,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. */ @@ -180,12 +190,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 @@ -194,24 +205,33 @@ 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]; +typedef unsigned short move_table[N_REG_CLASSES]; + /* Maximum cost of moving from a register in one class to a register in another class. Based on REGISTER_MOVE_COST. */ -static int move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; +static move_table *move_cost[MAX_MACHINE_MODE]; /* Similar, but here we don't have to move if the first index is a subset of the second so in that case the cost is zero. */ -static int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; +static move_table *may_move_in_cost[MAX_MACHINE_MODE]; /* Similar, but here we don't have to move if the first index is a superset of the second so in that case the cost is zero. */ -static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; +static move_table *may_move_out_cost[MAX_MACHINE_MODE]; + +/* Keep track of the last mode we initialized move costs for. */ +static int last_mode_for_init_move_cost; #ifdef FORBIDDEN_INC_DEC_CLASSES @@ -220,61 +240,50 @@ static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; static int forbidden_inc_dec_class[N_REG_CLASSES]; -/* Indexed by n, is non-zero if (REG n) is used in an auto-inc or auto-dec +/* Indexed by n, is nonzero if (REG n) is used in an auto-inc or auto-dec context. */ static char *in_inc_dec; #endif /* FORBIDDEN_INC_DEC_CLASSES */ -#ifdef CLASS_CANNOT_CHANGE_MODE - -/* These are the classes containing only registers that can be used in - a SUBREG expression that changes the mode of the register in some - way that is illegal. */ - -static int class_can_change_mode[N_REG_CLASSES]; - -/* Registers, including pseudos, which change modes in some way that - is illegal. */ - -static regset reg_changes_mode; - -#endif /* CLASS_CANNOT_CHANGE_MODE */ - -#ifdef HAVE_SECONDARY_RELOADS - /* Sample MEM values for use by memory_move_secondary_cost. */ -static rtx top_of_stack[MAX_MACHINE_MODE]; - -#endif /* HAVE_SECONDARY_RELOADS */ - -/* Linked list of reg_info structures allocated for reg_n_info array. - Grouping all of the allocated structures together in one lump - means only one call to bzero to clear them, rather than n smaller - calls. */ -struct reg_info_data { - struct reg_info_data *next; /* next set of reg_info structures */ - size_t min_index; /* minimum index # */ - size_t max_index; /* maximum index # */ - char used_p; /* non-zero if this has been used previously */ - reg_info data[1]; /* beginning of the reg_info data */ -}; - -static struct reg_info_data *reg_info_head; +static GTY(()) rtx top_of_stack[MAX_MACHINE_MODE]; /* No more global register variables may be declared; true once regclass has been initialized. */ 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]; + +/* Given a register bitmap, turn on the bits in a HARD_REG_SET that + correspond to the hard registers, if any, set in that map. This + could be done far more efficiently by having all sorts of special-cases + with moving single words, but probably isn't worth the trouble. */ + +void +reg_set_to_hard_reg_set (HARD_REG_SET *to, const_bitmap from) +{ + unsigned i; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi) + { + if (i >= FIRST_PSEUDO_REGISTER) + return; + SET_HARD_REG_BIT (*to, i); + } +} + /* Function called only once to initialize the above data on reg usage. Once this is done, various switches may override. */ void -init_reg_sets () +init_reg_sets (void) { int i, j; @@ -292,28 +301,172 @@ init_reg_sets () 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 (); +/* Initialize may_move_cost and friends for mode M. */ -#ifdef REG_ALLOC_ORDER - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - inv_reg_alloc_order[reg_alloc_order[i]] = i; +static void +init_move_cost (enum machine_mode m) +{ + static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES]; + bool all_match = true; + unsigned int i, j; + + gcc_assert (have_regs_of_mode[m]); + for (i = 0; i < N_REG_CLASSES; i++) + if (contains_reg_of_mode[i][m]) + for (j = 0; j < N_REG_CLASSES; j++) + { + int cost; + if (!contains_reg_of_mode[j][m]) + cost = 65535; + else + { + cost = REGISTER_MOVE_COST (m, i, j); + gcc_assert (cost < 65535); + } + all_match &= (last_move_cost[i][j] == cost); + last_move_cost[i][j] = cost; + } + if (all_match && last_mode_for_init_move_cost != -1) + { + move_cost[m] = move_cost[last_mode_for_init_move_cost]; + may_move_in_cost[m] = may_move_in_cost[last_mode_for_init_move_cost]; + may_move_out_cost[m] = may_move_out_cost[last_mode_for_init_move_cost]; + return; + } + last_mode_for_init_move_cost = m; + move_cost[m] = (move_table *)xmalloc (sizeof (move_table) + * N_REG_CLASSES); + may_move_in_cost[m] = (move_table *)xmalloc (sizeof (move_table) + * N_REG_CLASSES); + may_move_out_cost[m] = (move_table *)xmalloc (sizeof (move_table) + * N_REG_CLASSES); + for (i = 0; i < N_REG_CLASSES; i++) + if (contains_reg_of_mode[i][m]) + for (j = 0; j < N_REG_CLASSES; j++) + { + int cost; + enum reg_class *p1, *p2; + + if (last_move_cost[i][j] == 65535) + { + move_cost[m][i][j] = 65535; + may_move_in_cost[m][i][j] = 65535; + may_move_out_cost[m][i][j] = 65535; + } + else + { + cost = last_move_cost[i][j]; + + for (p2 = ®_class_subclasses[j][0]; + *p2 != LIM_REG_CLASSES; p2++) + if (*p2 != i && contains_reg_of_mode[*p2][m]) + cost = MAX (cost, move_cost[m][i][*p2]); + + for (p1 = ®_class_subclasses[i][0]; + *p1 != LIM_REG_CLASSES; p1++) + if (*p1 != j && contains_reg_of_mode[*p1][m]) + cost = MAX (cost, move_cost[m][*p1][j]); + + gcc_assert (cost <= 65535); + move_cost[m][i][j] = cost; + + if (reg_class_subset_p (i, j)) + may_move_in_cost[m][i][j] = 0; + else + may_move_in_cost[m][i][j] = cost; + + if (reg_class_subset_p (j, i)) + may_move_out_cost[m][i][j] = 0; + else + may_move_out_cost[m][i][j] = cost; + } + } + else + for (j = 0; j < N_REG_CLASSES; j++) + { + move_cost[m][i][j] = 65535; + may_move_in_cost[m][i][j] = 65535; + may_move_out_cost[m][i][j] = 65535; + } +} + +/* We need to save copies of some of the register information which + can be munged by command-line switches so we can restore it during + subsequent back-end reinitialization. */ + +static char saved_fixed_regs[FIRST_PSEUDO_REGISTER]; +static char saved_call_used_regs[FIRST_PSEUDO_REGISTER]; +#ifdef CALL_REALLY_USED_REGISTERS +static char saved_call_really_used_regs[FIRST_PSEUDO_REGISTER]; +#endif +static const char *saved_reg_names[FIRST_PSEUDO_REGISTER]; + +/* Save the register information. */ + +void +save_register_info (void) +{ + /* 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 saved_fixed_regs); + gcc_assert (sizeof call_used_regs == sizeof saved_call_used_regs); + memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs); + memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs); + + /* Likewise for call_really_used_regs. */ +#ifdef CALL_REALLY_USED_REGISTERS + gcc_assert (sizeof call_really_used_regs + == sizeof saved_call_really_used_regs); + memcpy (saved_call_really_used_regs, call_really_used_regs, + sizeof call_really_used_regs); +#endif + + /* And similarly for reg_names. */ + gcc_assert (sizeof reg_names == sizeof saved_reg_names); + memcpy (saved_reg_names, reg_names, sizeof reg_names); +} + +/* Restore the register information. */ + +static void +restore_register_info (void) +{ + memcpy (fixed_regs, saved_fixed_regs, sizeof fixed_regs); + memcpy (call_used_regs, saved_call_used_regs, sizeof call_used_regs); + +#ifdef CALL_REALLY_USED_REGISTERS + memcpy (call_really_used_regs, saved_call_really_used_regs, + sizeof call_really_used_regs); #endif + + memcpy (reg_names, saved_reg_names, sizeof reg_names); } /* After switches have been processed, which perhaps alter `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs. */ static void -init_reg_sets_1 () +init_reg_sets_1 (void) { unsigned int i, j; unsigned int /* enum machine_mode */ m; - char allocatable_regs_of_mode [MAX_MACHINE_MODE]; + + restore_register_info (); + +#ifdef REG_ALLOC_ORDER + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + inv_reg_alloc_order[reg_alloc_order[i]] = i; +#endif /* This macro allows the fixed or call-used registers and the register classes to depend on target flags. */ @@ -324,7 +477,7 @@ init_reg_sets_1 () /* Compute number of hard regs in each class. */ - memset ((char *) reg_class_size, 0, sizeof reg_class_size); + memset (reg_class_size, 0, sizeof reg_class_size); for (i = 0; i < N_REG_CLASSES; i++) for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (TEST_HARD_REG_BIT (reg_class_contents[i], j)) @@ -334,33 +487,22 @@ init_reg_sets_1 () reg_class_subunion[I][J] gets the largest-numbered reg-class that is contained in the union of classes I and J. */ + memset (reg_class_subunion, 0, sizeof reg_class_subunion); for (i = 0; i < N_REG_CLASSES; i++) { 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]); IOR_HARD_REG_SET (c, reg_class_contents[j]); for (k = 0; k < N_REG_CLASSES; k++) - { - GO_IF_HARD_REG_SUBSET (reg_class_contents[k], c, - subclass1); - continue; - - subclass1: - /* keep the largest subclass */ /* SPEE 900308 */ - GO_IF_HARD_REG_SUBSET (reg_class_contents[k], - reg_class_contents[(int) reg_class_subunion[i][j]], - subclass2); + if (hard_reg_set_subset_p (reg_class_contents[k], c) + && !hard_reg_set_subset_p (reg_class_contents[k], + reg_class_contents + [(int) reg_class_subunion[i][j]])) reg_class_subunion[i][j] = (enum reg_class) k; - subclass2: - ; - } } } @@ -368,22 +510,20 @@ init_reg_sets_1 () reg_class_superunion[I][J] gets the smallest-numbered reg-class containing the union of classes I and J. */ + memset (reg_class_superunion, 0, sizeof reg_class_superunion); for (i = 0; i < N_REG_CLASSES; i++) { 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]); IOR_HARD_REG_SET (c, reg_class_contents[j]); for (k = 0; k < N_REG_CLASSES; k++) - GO_IF_HARD_REG_SUBSET (c, reg_class_contents[k], superclass); + if (hard_reg_set_subset_p (c, reg_class_contents[k])) + break; - superclass: reg_class_superunion[i][j] = (enum reg_class) k; } } @@ -406,23 +546,21 @@ init_reg_sets_1 () continue; for (j = i + 1; j < N_REG_CLASSES; j++) - { - enum reg_class *p; - - GO_IF_HARD_REG_SUBSET (reg_class_contents[i], reg_class_contents[j], - subclass); - continue; - subclass: - /* Reg class I is a subclass of J. - Add J to the table of superclasses of I. */ - p = ®_class_superclasses[i][0]; - while (*p != LIM_REG_CLASSES) p++; - *p = (enum reg_class) j; - /* Add I to the table of superclasses of J. */ - p = ®_class_subclasses[j][0]; - while (*p != LIM_REG_CLASSES) p++; - *p = (enum reg_class) i; - } + if (hard_reg_set_subset_p (reg_class_contents[i], + reg_class_contents[j])) + { + /* Reg class I is a subclass of J. + Add J to the table of superclasses of I. */ + enum reg_class *p; + + p = ®_class_superclasses[i][0]; + while (*p != LIM_REG_CLASSES) p++; + *p = (enum reg_class) j; + /* Add I to the table of superclasses of J. */ + p = ®_class_subclasses[j][0]; + while (*p != LIM_REG_CLASSES) p++; + *p = (enum reg_class) i; + } } /* Initialize "constant" tables. */ @@ -431,17 +569,21 @@ init_reg_sets_1 () CLEAR_HARD_REG_SET (call_used_reg_set); CLEAR_HARD_REG_SET (call_fixed_reg_set); CLEAR_HARD_REG_SET (regs_invalidated_by_call); + CLEAR_HARD_REG_SET (losing_caller_save_reg_set); 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); @@ -459,7 +601,11 @@ init_reg_sets_1 () 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) @@ -470,119 +616,83 @@ init_reg_sets_1 () ; #endif #ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED - else if (i == PIC_OFFSET_TABLE_REGNUM && fixed_regs[i]) + 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 (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 (CLASS_MAX_NREGS (i, m) <= reg_class_size[i]) - for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) - if (!fixed_regs [j] && TEST_HARD_REG_BIT (reg_class_contents[i], j) - && HARD_REGNO_MODE_OK (j, m)) - { - contains_reg_of_mode [i][m] = 1; - allocatable_regs_of_mode [m] = 1; - break; - } - - /* Initialize the move cost table. Find every subset of each class - and take the maximum cost of moving any subset to any other. */ + /* Preserve global registers if called more than once. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (global_regs[i]) + { + fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1; + 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); + } + } + memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode)); + memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode)); for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++) - if (allocatable_regs_of_mode [m]) - { - for (i = 0; i < N_REG_CLASSES; i++) - if (contains_reg_of_mode [i][m]) - for (j = 0; j < N_REG_CLASSES; j++) - { - int cost; - enum reg_class *p1, *p2; - - if (!contains_reg_of_mode [j][m]) - { - move_cost[m][i][j] = 65536; - may_move_in_cost[m][i][j] = 65536; - may_move_out_cost[m][i][j] = 65536; - } - else - { - cost = REGISTER_MOVE_COST (m, i, j); - - for (p2 = ®_class_subclasses[j][0]; - *p2 != LIM_REG_CLASSES; - p2++) - if (*p2 != i && contains_reg_of_mode [*p2][m]) - cost = MAX (cost, move_cost [m][i][*p2]); - - for (p1 = ®_class_subclasses[i][0]; - *p1 != LIM_REG_CLASSES; - p1++) - if (*p1 != j && contains_reg_of_mode [*p1][m]) - cost = MAX (cost, move_cost [m][*p1][j]); - - move_cost[m][i][j] = cost; - - if (reg_class_subset_p (i, j)) - may_move_in_cost[m][i][j] = 0; - else - may_move_in_cost[m][i][j] = cost; - - if (reg_class_subset_p (j, i)) - may_move_out_cost[m][i][j] = 0; - else - may_move_out_cost[m][i][j] = cost; - } - } - else - for (j = 0; j < N_REG_CLASSES; j++) - { - move_cost[m][i][j] = 65536; - may_move_in_cost[m][i][j] = 65536; - may_move_out_cost[m][i][j] = 65536; - } - } - -#ifdef CLASS_CANNOT_CHANGE_MODE - { - HARD_REG_SET c; - COMPL_HARD_REG_SET (c, reg_class_contents[CLASS_CANNOT_CHANGE_MODE]); + { + HARD_REG_SET ok_regs; + CLEAR_HARD_REG_SET (ok_regs); + for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) + if (!fixed_regs [j] && HARD_REGNO_MODE_OK (j, m)) + SET_HARD_REG_BIT (ok_regs, j); + + for (i = 0; i < N_REG_CLASSES; i++) + if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i] + && hard_reg_set_intersect_p (ok_regs, reg_class_contents[i])) + { + contains_reg_of_mode [i][m] = 1; + have_regs_of_mode [m] = 1; + } + } - for (i = 0; i < N_REG_CLASSES; i++) + /* Reset move_cost and friends, making sure we only free shared + table entries once. */ + for (i = 0; i < MAX_MACHINE_MODE; i++) + if (move_cost[i]) { - GO_IF_HARD_REG_SUBSET (reg_class_contents[i], c, ok_class); - class_can_change_mode [i] = 0; - continue; - ok_class: - class_can_change_mode [i] = 1; + for (j = 0; j < i && move_cost[i] != move_cost[j]; j++) + ; + if (i == j) + { + free (move_cost[i]); + free (may_move_in_cost[i]); + free (may_move_out_cost[i]); + } } - } -#endif /* CLASS_CANNOT_CHANGE_MODE */ + memset (move_cost, 0, sizeof move_cost); + memset (may_move_in_cost, 0, sizeof may_move_in_cost); + memset (may_move_out_cost, 0, sizeof may_move_out_cost); + last_mode_for_init_move_cost = -1; } /* Compute the table of register modes. These values are used to record death information for individual registers - (as opposed to a multi-register mode). */ + (as opposed to a multi-register mode). + This function might be invoked more than once, if the target has support + for changing register usage conventions on a per-function basis. +*/ -static void -init_reg_modes () +void +init_reg_modes_target (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++) { - reg_raw_mode[i] = choose_hard_reg_mode (i, 1); + 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 @@ -594,41 +704,41 @@ init_reg_modes () } } -/* Finish initializing the register sets and - initialize the register modes. */ +/* Finish initializing the register sets and initialize the register modes. + This function might be invoked more than once, if the target has support + for changing register usage conventions on a per-function basis. +*/ void -init_regs () +init_regs (void) { /* This finishes what was started by init_reg_sets, but couldn't be done until after register usage was specified. */ init_reg_sets_1 (); - init_reg_modes (); + init_reg_autoinc (); +} + +/* Initialize some fake stack-frame MEM references for use in + memory_move_secondary_cost. */ -#ifdef HAVE_SECONDARY_RELOADS +void +init_fake_stack_mems (void) +{ { - /* Make some fake stack-frame MEM references for use in - memory_move_secondary_cost. */ int i; for (i = 0; i < MAX_MACHINE_MODE; i++) top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx); - ggc_add_rtx_root (top_of_stack, MAX_MACHINE_MODE); } -#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. */ int -memory_move_secondary_cost (mode, class, in) - enum machine_mode mode; - enum reg_class class; - int in; +memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in) { enum reg_class altclass; int partial_cost = 0; @@ -637,22 +747,7 @@ memory_move_secondary_cost (mode, class, 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; @@ -667,7 +762,7 @@ memory_move_secondary_cost (mode, class, 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; @@ -676,15 +771,14 @@ memory_move_secondary_cost (mode, class, 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. */ + enough to save nregs. If we can't find one, return VOIDmode. + If CALL_SAVED is true, only consider modes that are call saved. */ enum machine_mode -choose_hard_reg_mode (regno, nregs) - unsigned int regno ATTRIBUTE_UNUSED; - unsigned int nregs; +choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, + unsigned int nregs, bool call_saved) { unsigned int /* enum machine_mode */ m; enum machine_mode found_mode = VOIDmode, mode; @@ -696,8 +790,9 @@ choose_hard_reg_mode (regno, nregs) for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_NREGS (regno, mode) == nregs - && HARD_REGNO_MODE_OK (regno, mode)) + 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; if (found_mode != VOIDmode) @@ -706,8 +801,9 @@ choose_hard_reg_mode (regno, nregs) for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_NREGS (regno, mode) == nregs - && HARD_REGNO_MODE_OK (regno, mode)) + 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; if (found_mode != VOIDmode) @@ -716,8 +812,9 @@ choose_hard_reg_mode (regno, nregs) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_NREGS (regno, mode) == nregs - && HARD_REGNO_MODE_OK (regno, mode)) + 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; if (found_mode != VOIDmode) @@ -726,8 +823,9 @@ choose_hard_reg_mode (regno, nregs) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_NREGS (regno, mode) == nregs - && HARD_REGNO_MODE_OK (regno, mode)) + 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; if (found_mode != VOIDmode) @@ -737,8 +835,9 @@ choose_hard_reg_mode (regno, nregs) for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m) { mode = (enum machine_mode) m; - if (HARD_REGNO_NREGS (regno, mode) == nregs - && HARD_REGNO_MODE_OK (regno, mode)) + 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; } @@ -751,9 +850,7 @@ choose_hard_reg_mode (regno, nregs) call-used register if CALL_USED. */ void -fix_register (name, fixed, call_used) - const char *name; - int fixed, call_used; +fix_register (const char *name, int fixed, int call_used) { int i; @@ -790,36 +887,43 @@ fix_register (name, fixed, call_used) } else { - warning ("unknown register name: %s", name); + warning (0, "unknown register name: %s", name); } } /* Mark register number I as global. */ void -globalize_reg (i) - int i; +globalize_reg (int i) { if (fixed_regs[i] == 0 && no_global_reg_vars) error ("global register variable follows a function definition"); 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); @@ -839,10 +943,11 @@ struct costs int mem_cost; }; -/* Structure used to record preferrences of given pseudo. */ +/* 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 @@ -863,40 +968,59 @@ static struct costs *costs; static struct costs init_cost; -/* Record preferrences of each pseudo. +/* Record preferences of each pseudo. This is available after `regclass' is run. */ static struct reg_pref *reg_pref; -/* Allocated buffers for reg_pref. */ - -static struct reg_pref *reg_pref_buffer; - /* Frequency of executions of current insn. */ static int frequency; -static rtx scan_one_insn PARAMS ((rtx, int)); -static void record_operand_costs PARAMS ((rtx, struct costs *, struct reg_pref *)); -static void dump_regclass PARAMS ((FILE *)); -static void record_reg_classes PARAMS ((int, int, rtx *, enum machine_mode *, - const char **, rtx, - struct costs *, struct reg_pref *)); -static int copy_cost PARAMS ((rtx, enum machine_mode, - enum reg_class, int)); -static void record_address_regs PARAMS ((rtx, enum reg_class, int)); +static rtx scan_one_insn (rtx, int); +static void record_operand_costs (rtx, struct costs *, struct reg_pref *); +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, + 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 PARAMS ((rtx, enum machine_mode)); +static int auto_inc_dec_reg_p (rtx, enum machine_mode); #endif -static void reg_scan_mark_refs PARAMS ((rtx, rtx, int, unsigned int)); +static void reg_scan_mark_refs (rtx, rtx); + +/* 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. When that happens, just return GENERAL_REGS, which is innocuous. */ enum reg_class -reg_preferred_class (regno) - int regno; +reg_preferred_class (int regno) { if (reg_pref == 0) return GENERAL_REGS; @@ -904,8 +1028,7 @@ reg_preferred_class (regno) } enum reg_class -reg_alternate_class (regno) - int regno; +reg_alternate_class (int regno) { if (reg_pref == 0) return ALL_REGS; @@ -915,11 +1038,14 @@ reg_alternate_class (regno) /* Initialize some global data for this pass. */ -void -regclass_init () +static unsigned int +regclass_init (void) { int i; + if (df) + df_compute_regs_ever_live (true); + init_cost.mem_cost = 10000; for (i = 0; i < N_REG_CLASSES; i++) init_cost.cost[i] = 10000; @@ -930,14 +1056,34 @@ regclass_init () /* No more global register variables may be declared. */ no_global_reg_vars = 1; + return 1; } + +struct rtl_opt_pass pass_regclass_init = +{ + { + RTL_PASS, + "regclass", /* name */ + NULL, /* gate */ + regclass_init, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + + /* Dump register costs. */ static void -dump_regclass (dump) - FILE *dump; +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++) { @@ -951,9 +1097,9 @@ dump_regclass (dump) && (!in_inc_dec[i] || !forbidden_inc_dec_class[(enum reg_class) class]) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - && (!REGNO_REG_SET_P (reg_changes_mode, i) - || class_can_change_mode [(enum reg_class) class]) +#ifdef CANNOT_CHANGE_MODE_CLASS + && ! invalid_mode_change_p (i, (enum reg_class) class, + PSEUDO_REGNO_MODE (i)) #endif ) fprintf (dump, " %s:%i", reg_class_names[class], @@ -967,10 +1113,8 @@ dump_regclass (dump) /* Calculate the costs of insn operands. */ static void -record_operand_costs (insn, op_costs, reg_pref) - rtx insn; - struct costs *op_costs; - struct reg_pref *reg_pref; +record_operand_costs (rtx insn, struct costs *op_costs, + struct reg_pref *reg_pref) { const char *constraints[MAX_RECOG_OPERANDS]; enum machine_mode modes[MAX_RECOG_OPERANDS]; @@ -993,22 +1137,16 @@ record_operand_costs (insn, op_costs, reg_pref) op_costs[i] = init_cost; if (GET_CODE (recog_data.operand[i]) == SUBREG) - { - rtx inner = SUBREG_REG (recog_data.operand[i]); -#ifdef CLASS_CANNOT_CHANGE_MODE - if (GET_CODE (inner) == REG - && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (inner))) - SET_REGNO_REG_SET (reg_changes_mode, REGNO (inner)); -#endif - recog_data.operand[i] = inner; - } - - 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); - else if (constraints[i][0] == 'p') - record_address_regs (recog_data.operand[i], - MODE_BASE_REG_CLASS (modes[i]), frequency * 2); + recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]); + + 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 (VOIDmode, recog_data.operand[i], 0, ADDRESS, + SCRATCH, frequency * 2); } /* Check for commutative in a separate loop so everything will @@ -1047,17 +1185,14 @@ record_operand_costs (insn, op_costs, reg_pref) there. */ static rtx -scan_one_insn (insn, pass) - rtx insn; - int pass; +scan_one_insn (rtx insn, int pass ATTRIBUTE_UNUSED) { - 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)); @@ -1075,90 +1210,28 @@ scan_one_insn (insn, 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; } - /* Improve handling of two-address insns such as - (set X (ashift CONST Y)) where CONST must be made to - match X. Change it into two insns: (set X CONST) - (set X (ashift X Y)). If we left this for reloading, it - would probably get three insns because X and Y might go - in the same place. This prevents X and Y from receiving - the same hard reg. - - We can only do this if the modes of operands 0 and 1 - (which might not be the same) are tieable and we only need - do this during our first pass. */ - - if (pass == 0 && optimize - && recog_data.n_operands >= 3 - && recog_data.constraints[1][0] == '0' - && recog_data.constraints[1][1] == 0 - && 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 - && MODES_TIEABLE_P (GET_MODE (recog_data.operand[0]), - recog_data.operand_mode[1])) - { - rtx previnsn = prev_real_insn (insn); - rtx dest - = gen_lowpart (recog_data.operand_mode[1], - recog_data.operand[0]); - rtx newinsn - = emit_insn_before (gen_move_insn (dest, recog_data.operand[1]), insn); - - /* If this insn was the start of a basic block, - include the new insn in that block. - 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) - { - basic_block b; - FOR_ALL_BB (b) - if (insn == b->head) - b->head = newinsn; - } - - /* This makes one more setting of new insns's dest. */ - REG_N_SETS (REGNO (recog_data.operand[0]))++; - REG_N_REFS (REGNO (recog_data.operand[0]))++; - REG_FREQ (REGNO (recog_data.operand[0])) += frequency; - - *recog_data.operand_loc[1] = recog_data.operand[0]; - REG_N_REFS (REGNO (recog_data.operand[0]))++; - REG_FREQ (REGNO (recog_data.operand[0])) += frequency; - for (i = recog_data.n_dups - 1; i >= 0; i--) - if (recog_data.dup_num[i] == 1) - { - *recog_data.dup_loc[i] = recog_data.operand[0]; - REG_N_REFS (REGNO (recog_data.operand[0]))++; - REG_FREQ (REGNO (recog_data.operand[0])) += frequency; - } - - return PREV_INSN (newinsn); - } - record_operand_costs (insn, op_costs, reg_pref); /* Now add the cost for each operand to the total costs for 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]); @@ -1172,53 +1245,38 @@ scan_one_insn (insn, pass) return insn; } -/* This is a pass of the compiler that scans all instructions - and calculates the preferred class for each pseudo-register. - This information can be accessed later by calling `reg_preferred_class'. - This pass comes just before local register allocation. */ +/* Initialize information about which register classes can be used for + pseudos that are auto-incremented or auto-decremented. */ -void -regclass (f, nregs, dump) - rtx f; - int nregs; - FILE *dump; +static void +init_reg_autoinc (void) { - rtx insn; - int i; - int pass; - - init_recog (); - - costs = (struct costs *) xmalloc (nregs * sizeof (struct costs)); - -#ifdef CLASS_CANNOT_CHANGE_MODE - reg_changes_mode = BITMAP_XMALLOC (); -#endif - #ifdef FORBIDDEN_INC_DEC_CLASSES + int i; - in_inc_dec = (char *) xmalloc (nregs); - - /* Initialize information about which register classes can be used for - pseudos that are auto-incremented or auto-decremented. It would - seem better to put this in init_reg_sets, but we need to be able - to allocate rtx, which we can't do that early. */ - + memset (forbidden_inc_dec_class, 0, sizeof forbidden_inc_dec_class); for (i = 0; i < N_REG_CLASSES; i++) { - rtx r = gen_rtx_REG (VOIDmode, 0); + rtx r = gen_rtx_raw_REG (VOIDmode, 0); enum machine_mode m; int j; for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (TEST_HARD_REG_BIT (reg_class_contents[i], j)) { - REGNO (r) = j; + SET_REGNO (r, j); for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE; 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 @@ -1226,27 +1284,42 @@ regclass (f, nregs, dump) 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 (0, 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; } } } #endif /* FORBIDDEN_INC_DEC_CLASSES */ +} + +/* This is a pass of the compiler that scans all instructions + and calculates the preferred class for each pseudo-register. + This information can be accessed later by calling `reg_preferred_class'. + This pass comes just before local register allocation. */ + +void +regclass (rtx f, int nregs) +{ + rtx insn; + int i; + int pass; + max_regno = max_reg_num (); + + init_recog (); + + reg_renumber = xmalloc (max_regno * sizeof (short)); + reg_pref = XCNEWVEC (struct reg_pref, max_regno); + memset (reg_renumber, -1, max_regno * sizeof (short)); + + costs = XNEWVEC (struct costs, nregs); + +#ifdef FORBIDDEN_INC_DEC_CLASSES + + in_inc_dec = XNEWVEC (char, nregs); + +#endif /* FORBIDDEN_INC_DEC_CLASSES */ /* Normally we scan the insns once and determine the best class to use for each register. However, if -fexpensive_optimizations are on, we do so @@ -1257,11 +1330,11 @@ regclass (f, nregs, 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 ((char *) costs, 0, nregs * sizeof (struct costs)); + memset (costs, 0, nregs * sizeof (struct costs)); #ifdef FORBIDDEN_INC_DEC_CLASSES memset (in_inc_dec, 0, nregs); @@ -1277,18 +1350,17 @@ regclass (f, nregs, dump) insn = scan_one_insn (insn, pass); } else - FOR_ALL_BB (bb) + FOR_EACH_BB (bb) { - /* Show that an insn inside a loop is likely to be executed three times more than insns outside a loop. This is much more 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; } } @@ -1298,13 +1370,10 @@ regclass (f, nregs, dump) `prefclass'. Record in `altclass' the largest register class any of whose registers is better than memory. */ - 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++) { @@ -1315,9 +1384,12 @@ regclass (f, nregs, dump) int class; struct costs *p = &costs[i]; + if (regno_reg_rtx[i] == NULL) + continue; + /* In non-optimizing compilation REG_N_REFS is not initialized yet. */ - if (optimize && !REG_N_REFS (i)) + if (optimize && !REG_N_REFS (i) && !REG_N_SETS (i)) continue; for (class = (int) ALL_REGS - 1; class > 0; class--) @@ -1328,9 +1400,9 @@ regclass (f, nregs, dump) #ifdef FORBIDDEN_INC_DEC_CLASSES || (in_inc_dec[i] && forbidden_inc_dec_class[class]) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - || (REGNO_REG_SET_P (reg_changes_mode, i) - && ! class_can_change_mode [class]) +#ifdef CANNOT_CHANGE_MODE_CLASS + || invalid_mode_change_p (i, (enum reg_class) class, + PSEUDO_REGNO_MODE (i)) #endif ) ; @@ -1343,6 +1415,10 @@ regclass (f, nregs, 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 @@ -1350,7 +1426,7 @@ regclass (f, nregs, 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]] @@ -1358,9 +1434,9 @@ regclass (f, nregs, dump) #ifdef FORBIDDEN_INC_DEC_CLASSES && ! (in_inc_dec[i] && forbidden_inc_dec_class[class]) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - && ! (REGNO_REG_SET_P (reg_changes_mode, i) - && ! class_can_change_mode [class]) +#ifdef CANNOT_CHANGE_MODE_CLASS + && ! invalid_mode_change_p (i, (enum reg_class) class, + PSEUDO_REGNO_MODE (i)) #endif ) alt = reg_class_subunion[(int) alt][class]; @@ -1369,18 +1445,17 @@ regclass (f, nregs, 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]); } @@ -1394,9 +1469,6 @@ regclass (f, nregs, dump) #ifdef FORBIDDEN_INC_DEC_CLASSES free (in_inc_dec); #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - BITMAP_XFREE (reg_changes_mode); -#endif free (costs); } @@ -1425,16 +1497,10 @@ regclass (f, nregs, dump) alternatives. */ static void -record_reg_classes (n_alts, n_ops, ops, modes, - constraints, insn, op_costs, reg_pref) - int n_alts; - int n_ops; - rtx *ops; - enum machine_mode *modes; - const char **constraints; - rtx insn; - struct costs *op_costs; - struct reg_pref *reg_pref; +record_reg_classes (int n_alts, int n_ops, rtx *ops, + enum machine_mode *modes, const char **constraints, + rtx insn, struct costs *op_costs, + struct reg_pref *reg_pref) { int alt; int i, j; @@ -1470,8 +1536,8 @@ record_reg_classes (n_alts, n_ops, ops, modes, if (*p == 0) { - if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) - memset ((char *) &this_op_costs[i], 0, sizeof this_op_costs[i]); + if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) + memset (&this_op_costs[i], 0, sizeof this_op_costs[i]); continue; } @@ -1493,7 +1559,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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. */ @@ -1505,9 +1571,12 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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. */ @@ -1523,7 +1592,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, operand. */ else - alt_cost += copy_cost (ops[j], mode, classes[j], 1); + alt_cost += copy_cost (ops[j], mode, classes[j], 1, NULL); } else { @@ -1533,15 +1602,33 @@ record_reg_classes (n_alts, n_ops, ops, modes, copy, which is one instruction. */ struct costs *pp = &this_op_costs[i]; - - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] - = ((recog_data.operand_type[i] != OP_OUT - ? may_move_in_cost[mode][class][(int) classes[i]] - : 0) - + (recog_data.operand_type[i] != OP_IN - ? may_move_out_cost[mode][(int) classes[i]][class] - : 0)); + move_table *intable = NULL; + move_table *outtable = NULL; + int op_class = (int) classes[i]; + + if (!move_cost[mode]) + init_move_cost (mode); + intable = may_move_in_cost[mode]; + outtable = may_move_out_cost[mode]; + + /* The loop is performance critical, so unswitch it manually. + */ + switch (recog_data.operand_type[i]) + { + case OP_INOUT: + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] = (intable[class][op_class] + + outtable[op_class][class]); + break; + case OP_IN: + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] = intable[class][op_class]; + break; + case OP_OUT: + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] = outtable[op_class][class]; + break; + } /* If the alternative actually allows memory, make things a bit cheaper since we won't need an extra insn to @@ -1560,7 +1647,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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] @@ -1585,130 +1672,155 @@ record_reg_classes (n_alts, n_ops, ops, modes, any of the constraints. Collect the valid register classes and see if this operand accepts memory. */ - while (*p && (c = *p++) != ',') - switch (c) - { - case '*': - /* Ignore the next letter for this pass. */ - p++; - break; - - case '?': - alt_cost += 2; - case '!': case '#': case '&': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - break; + while ((c = *p)) + { + switch (c) + { + case ',': + break; + case '*': + /* Ignore the next letter for this pass. */ + c = *++p; + break; - case 'p': - allows_addr = 1; - 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. */ - classes[i] - = reg_class_subunion[(int) classes[i]] - [(int) MODE_BASE_REG_CLASS (VOIDmode)]; - break; + case '?': + alt_cost += 2; + case '!': case '#': case '&': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + 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) - win = 1; - break; + case 'p': + allows_addr = 1; + 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, i.e. BASE_REG_CLASS. */ + classes[i] + = reg_class_subunion[(int) classes[i]] + [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; + break; - case '<': - if (GET_CODE (op) == MEM - && (GET_CODE (XEXP (op, 0)) == PRE_DEC - || GET_CODE (XEXP (op, 0)) == POST_DEC)) - win = 1; - 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 (MEM_P (op)) + win = 1; + break; - case '>': - if (GET_CODE (op) == MEM - && (GET_CODE (XEXP (op, 0)) == PRE_INC - || GET_CODE (XEXP (op, 0)) == POST_INC)) - win = 1; - break; + case '<': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || GET_CODE (XEXP (op, 0)) == POST_DEC)) + win = 1; + break; - case 'E': - case 'F': - if (GET_CODE (op) == CONST_DOUBLE) - win = 1; - break; + case '>': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_INC + || GET_CODE (XEXP (op, 0)) == POST_INC)) + win = 1; + break; - case 'G': - case 'H': - if (GET_CODE (op) == CONST_DOUBLE - && CONST_DOUBLE_OK_FOR_LETTER_P (op, c)) - win = 1; - break; + case 'E': + case 'F': + if (GET_CODE (op) == CONST_DOUBLE + || (GET_CODE (op) == CONST_VECTOR + && (GET_MODE_CLASS (GET_MODE (op)) + == MODE_VECTOR_FLOAT))) + win = 1; + break; - case 's': - if (GET_CODE (op) == CONST_INT - || (GET_CODE (op) == CONST_DOUBLE - && GET_MODE (op) == VOIDmode)) + case 'G': + case 'H': + if (GET_CODE (op) == CONST_DOUBLE + && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) + win = 1; break; - case 'i': - if (CONSTANT_P (op) -#ifdef LEGITIMATE_PIC_OPERAND_P - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif - ) - win = 1; - break; - case 'n': - if (GET_CODE (op) == CONST_INT - || (GET_CODE (op) == CONST_DOUBLE - && GET_MODE (op) == VOIDmode)) - win = 1; - break; + case 's': + if (GET_CODE (op) == CONST_INT + || (GET_CODE (op) == CONST_DOUBLE + && GET_MODE (op) == VOIDmode)) + break; + case 'i': + if (CONSTANT_P (op) + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) + win = 1; + break; - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - if (GET_CODE (op) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (op), c)) - win = 1; - break; + case 'n': + if (GET_CODE (op) == CONST_INT + || (GET_CODE (op) == CONST_DOUBLE + && GET_MODE (op) == VOIDmode)) + win = 1; + break; - case 'X': - win = 1; - break; + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + if (GET_CODE (op) == CONST_INT + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) + win = 1; + break; - case 'g': - if (GET_CODE (op) == MEM - || (CONSTANT_P (op) -#ifdef LEGITIMATE_PIC_OPERAND_P - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) -#endif - )) + case 'X': win = 1; - allows_mem[i] = 1; - case 'r': - classes[i] - = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS]; - break; + break; - default: - if (REG_CLASS_FROM_LETTER (c) != NO_REGS) + case 'g': + if (MEM_P (op) + || (CONSTANT_P (op) + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))) + win = 1; + allows_mem[i] = 1; + case 'r': classes[i] - = reg_class_subunion[(int) classes[i]] - [(int) REG_CLASS_FROM_LETTER (c)]; -#ifdef EXTRA_CONSTRAINT - else if (EXTRA_CONSTRAINT (op, c)) - win = 1; + = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS]; + break; + + default: + if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS) + classes[i] + = reg_class_subunion[(int) classes[i]] + [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]; +#ifdef EXTRA_CONSTRAINT_STR + else if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = 1; + + if (EXTRA_MEMORY_CONSTRAINT (c, p)) + { + /* Every MEM can be reloaded to fit. */ + allows_mem[i] = 1; + if (MEM_P (op)) + win = 1; + } + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + { + /* Every address can be reloaded to fit. */ + allows_addr = 1; + if (address_operand (op, GET_MODE (op))) + 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, i.e. BASE_REG_CLASS. */ + classes[i] + = reg_class_subunion[(int) classes[i]] + [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; + } #endif + break; + } + p += CONSTRAINT_LEN (c, p); + if (c == ',') break; - } + } constraints[i] = p; @@ -1719,7 +1831,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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) { @@ -1734,15 +1846,33 @@ record_reg_classes (n_alts, n_ops, ops, modes, else { struct costs *pp = &this_op_costs[i]; - - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] - = ((recog_data.operand_type[i] != OP_OUT - ? may_move_in_cost[mode][class][(int) classes[i]] - : 0) - + (recog_data.operand_type[i] != OP_IN - ? may_move_out_cost[mode][(int) classes[i]][class] - : 0)); + move_table *intable = NULL; + move_table *outtable = NULL; + int op_class = (int) classes[i]; + + if (!move_cost[mode]) + init_move_cost (mode); + intable = may_move_in_cost[mode]; + outtable = may_move_out_cost[mode]; + + /* The loop is performance critical, so unswitch it manually. + */ + switch (recog_data.operand_type[i]) + { + case OP_INOUT: + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] = (intable[class][op_class] + + outtable[op_class][class]); + break; + case OP_IN: + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] = intable[class][op_class]; + break; + case OP_OUT: + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] = outtable[op_class][class]; + break; + } /* If the alternative actually allows memory, make things a bit cheaper since we won't need an extra insn to @@ -1761,7 +1891,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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] @@ -1774,7 +1904,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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)))) ; @@ -1784,10 +1914,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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 @@ -1806,7 +1936,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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]; @@ -1827,7 +1957,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, we may want to adjust the cost of that register class to -1. Avoid the adjustment if the source does not die to avoid stressing of - register allocator by preferrencing two coliding registers into single + register allocator by preferrencing two colliding registers into single class. Also avoid the adjustment if a copy between registers of the class @@ -1837,7 +1967,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, 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) @@ -1845,55 +1975,42 @@ record_reg_classes (n_alts, n_ops, ops, modes, unsigned int regno = REGNO (ops[!i]); enum machine_mode mode = GET_MODE (ops[!i]); 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; if ((reg_class_size[(unsigned char) pref] - == CLASS_MAX_NREGS (pref, mode)) + == (unsigned) CLASS_MAX_NREGS (pref, mode)) && REGISTER_MOVE_COST (mode, pref, pref) < 10 * 2) op_costs[i].cost[(unsigned char) pref] = -1; } else if (regno < FIRST_PSEUDO_REGISTER) for (class = 0; class < N_REG_CLASSES; class++) if (TEST_HARD_REG_BIT (reg_class_contents[class], regno) - && reg_class_size[class] == CLASS_MAX_NREGS (class, mode)) + && reg_class_size[class] == (unsigned) CLASS_MAX_NREGS (class, mode)) { if (reg_class_size[class] == 1) op_costs[i].cost[class] = -1; - else - { - for (nr = 0; nr < HARD_REGNO_NREGS (regno, mode); nr++) - { - if (! TEST_HARD_REG_BIT (reg_class_contents[class], - regno + nr)) - break; - } - - if (nr == HARD_REGNO_NREGS (regno,mode)) - op_costs[i].cost[class] = -1; - } + else if (in_hard_reg_set_p (reg_class_contents[class], + mode, regno)) + op_costs[i].cost[class] = -1; } } } -/* Compute the cost of loading X into (if TO_P is non-zero) or from (if +/* Compute the cost of loading X into (if TO_P is nonzero) or from (if TO_P is zero) a register of class CLASS in mode MODE. X must not be a pseudo. */ static int -copy_cost (x, mode, class, to_p) - 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. */ @@ -1904,58 +2021,63 @@ copy_cost (x, mode, class, to_p) /* 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 + sri.prev_sri = prev_sri; + sri.extra_cost = 0; + secondary_class = targetm.secondary_reload (to_p, x, class, mode, &sri); -#ifdef SECONDARY_OUTPUT_RELOAD_CLASS - if (! to_p) - secondary_class = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x); -#endif + if (!move_cost[mode]) + init_move_cost (mode); 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 (x, class, scale) - 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) { @@ -1996,52 +2118,52 @@ record_address_regs (x, class, 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 @@ -2050,14 +2172,14 @@ record_address_regs (x, class, 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 @@ -2065,12 +2187,10 @@ record_address_regs (x, class, 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; @@ -2080,11 +2200,11 @@ record_address_regs (x, class, 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: @@ -2097,12 +2217,12 @@ record_address_regs (x, class, 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: @@ -2112,6 +2232,8 @@ record_address_regs (x, class, scale) pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2; + if (!move_cost[Pmode]) + init_move_cost (Pmode); for (i = 0; i < N_REG_CLASSES; i++) pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2; } @@ -2123,7 +2245,8 @@ record_address_regs (x, class, 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); } } } @@ -2134,9 +2257,7 @@ record_address_regs (x, class, scale) to an object of MODE. */ static int -auto_inc_dec_reg_p (reg, mode) - rtx reg; - enum machine_mode mode; +auto_inc_dec_reg_p (rtx reg, enum machine_mode mode) { if (HAVE_POST_INCREMENT && memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg))) @@ -2158,228 +2279,46 @@ auto_inc_dec_reg_p (reg, mode) } #endif -static short *renumber; -static size_t regno_allocated; -static unsigned int reg_n_max; - -/* Allocate enough space to hold NUM_REGS registers for the tables used for - reg_scan and flow_analysis that are indexed by the register number. If - NEW_P is non zero, initialize all of the registers, otherwise only - initialize the new registers allocated. The same table is kept from - function to function, only reallocating it when we need more room. If - RENUMBER_P is non zero, allocate the reg_renumber array also. */ - +/* Free up the space allocated by allocate_reg_info. */ void -allocate_reg_info (num_regs, new_p, renumber_p) - size_t num_regs; - int new_p; - int renumber_p; +free_reg_info (void) { - size_t size_info; - size_t size_renumber; - size_t min = (new_p) ? 0 : reg_n_max; - struct reg_info_data *reg_data; - - if (num_regs > regno_allocated) + if (reg_pref) { - size_t old_allocated = regno_allocated; - - regno_allocated = num_regs + (num_regs / 20); /* add some slop space */ - size_renumber = regno_allocated * sizeof (short); - - if (!reg_n_info) - { - VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info"); - renumber = (short *) xmalloc (size_renumber); - reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated - * sizeof (struct reg_pref)); - } - - else - { - VARRAY_GROW (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 = (short *) xmalloc (size_renumber); - reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated - * sizeof (struct reg_pref)); - } - - else - { - renumber = (short *) xrealloc ((char *) renumber, size_renumber); - reg_pref_buffer = (struct reg_pref *) xrealloc ((char *) reg_pref_buffer, - regno_allocated - * sizeof (struct reg_pref)); - } - } - - size_info = (regno_allocated - old_allocated) * sizeof (reg_info) - + sizeof (struct reg_info_data) - sizeof (reg_info); - reg_data = (struct reg_info_data *) xcalloc (size_info, 1); - reg_data->min_index = old_allocated; - reg_data->max_index = regno_allocated - 1; - reg_data->next = reg_info_head; - reg_info_head = reg_data; + free (reg_pref); + reg_pref = NULL; } - reg_n_max = num_regs; - if (min < num_regs) + if (reg_renumber) { - /* Loop through each of the segments allocated for the actual - reg_info pages, and set up the pointers, zero the pages, etc. */ - for (reg_data = reg_info_head; - reg_data && reg_data->max_index >= min; - reg_data = reg_data->next) - { - size_t min_index = reg_data->min_index; - size_t max_index = reg_data->max_index; - size_t max = MIN (max_index, num_regs); - size_t local_min = min - min_index; - size_t i; - - if (reg_data->min_index > num_regs) - continue; - - if (min < min_index) - local_min = 0; - if (!reg_data->used_p) /* page just allocated with calloc */ - reg_data->used_p = 1; /* no need to zero */ - else - memset ((char *) ®_data->data[local_min], 0, - sizeof (reg_info) * (max - min_index - local_min + 1)); - - for (i = min_index+local_min; i <= max; i++) - { - VARRAY_REG (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; - reg_pref_buffer[i].altclass = (char) NO_REGS; - } - } + free (reg_renumber); + reg_renumber = NULL; } - - /* If {pref,alt}class have already been allocated, update the pointers to - the newly realloced ones. */ - if (reg_pref) - reg_pref = reg_pref_buffer; - - 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. */ -void -free_reg_info () -{ - if (reg_n_info) - { - struct reg_info_data *reg_data; - struct reg_info_data *reg_next; - - VARRAY_FREE (reg_n_info); - for (reg_data = reg_info_head; reg_data; reg_data = reg_next) - { - reg_next = reg_data->next; - free ((char *) reg_data); - } - - free (reg_pref_buffer); - reg_pref_buffer = (struct reg_pref *) 0; - reg_info_head = (struct reg_info_data *) 0; - renumber = (short *) 0; - } - regno_allocated = 0; - reg_n_max = 0; -} -/* This is the `regscan' pass of the compiler, run just before cse - and again just before loop. - - It finds the first and last use of each pseudo-register - and records them in the vectors regno_first_uid, regno_last_uid - and counts the number of sets in the vector reg_n_sets. - - REPEAT is nonzero the second time this is called. */ - -/* Maximum number of parallel sets and clobbers in any insn in this fn. - Always at least 3, since the combiner could put that many together - and we want this to remain correct for all the remaining passes. - This corresponds to the maximum number of times note_stores will call - a function for any insn. */ - -int max_parallel; - -/* Used as a temporary to record the largest number of registers in - PARALLEL in a SET_DEST. This is added to max_parallel. */ - -static int max_set_parallel; +/* This is the `regscan' pass of the compiler, run just before cse and + again just before loop. It finds the first and last use of each + pseudo-register. */ void -reg_scan (f, nregs, repeat) - rtx f; - unsigned int nregs; - int repeat ATTRIBUTE_UNUSED; +reg_scan (rtx f, unsigned int nregs ATTRIBUTE_UNUSED) { rtx insn; - 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); - + reg_scan_mark_refs (PATTERN (insn), insn); if (REG_NOTES (insn)) - reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0); + reg_scan_mark_refs (REG_NOTES (insn), insn); } - max_parallel += max_set_parallel; + 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 (first, last, old_max_regno) - 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. @@ -2387,22 +2326,21 @@ reg_scan_update (first, last, old_max_regno) greater than or equal to MIN_REGNO. */ static void -reg_scan_mark_refs (x, insn, note_flag, min_regno) - rtx x; - rtx insn; - int note_flag; - unsigned int min_regno; +reg_scan_mark_refs (rtx x, rtx insn) { enum rtx_code code; rtx dest; rtx note; + if (!x) + return; code = GET_CODE (x); switch (code) { case CONST: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case CC0: case PC: @@ -2410,33 +2348,24 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) case LABEL_REF: case ADDR_VEC: case ADDR_DIFF_VEC: - return; - case REG: - { - 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); - } - } - break; + return; 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); if (XEXP (x, 1)) - reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno); + reg_scan_mark_refs (XEXP (x, 1), insn); 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); + break; + + case CLOBBER: + if (MEM_P (XEXP (x, 0))) + reg_scan_mark_refs (XEXP (XEXP (x, 0), 0), insn); break; case SET: @@ -2447,18 +2376,6 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) dest = XEXP (dest, 0)) ; - /* For a PARALLEL, record the number of things (less the usual one for a - SET) that are set. */ - 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) - { - REG_N_SETS (REGNO (dest))++; - REG_N_REFS (REGNO (dest))++; - } - /* If this is setting a pseudo from another pseudo or the sum of a pseudo and a constant integer and the other pseudo is known to be a pointer, set the destination to be a pointer as well. @@ -2471,23 +2388,22 @@ reg_scan_mark_refs (x, insn, note_flag, 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 presense of global + union in two threads of control in the presence of global optimizations). So only set REG_POINTER on the destination pseudo if this is the only set of that pseudo. */ - && REG_N_SETS (REGNO (SET_DEST (x))) == 1 + && DF_REG_DEF_COUNT (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 @@ -2508,8 +2424,8 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) REG_POINTER (SET_DEST (x)) = 1; /* If this is setting a register from a register or from a simple - conversion of a register, propagate REG_DECL. */ - if (GET_CODE (dest) == REG) + conversion of a register, propagate REG_EXPR. */ + if (REG_P (dest) && !REG_ATTRS (dest)) { rtx src = SET_SRC (x); @@ -2519,10 +2435,7 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src))) src = XEXP (src, 0); - if (GET_CODE (src) == REG && REGNO_DECL (REGNO (src)) == 0) - REGNO_DECL (REGNO (src)) = REGNO_DECL (REGNO (dest)); - else if (GET_CODE (src) == REG && REGNO_DECL (REGNO (dest)) == 0) - REGNO_DECL (REGNO (dest)) = REGNO_DECL (REGNO (src)); + set_reg_attrs_from_value (dest, src); } /* ... fall through ... */ @@ -2534,12 +2447,12 @@ reg_scan_mark_refs (x, insn, note_flag, 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); 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); } } } @@ -2550,52 +2463,253 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) is also in C2. */ int -reg_class_subset_p (c1, c2) - enum reg_class c1; - enum reg_class c2; +reg_class_subset_p (enum reg_class c1, enum reg_class c2) { - if (c1 == c2) return 1; - - if (c2 == ALL_REGS) - win: - return 1; - GO_IF_HARD_REG_SUBSET (reg_class_contents[(int) c1], - reg_class_contents[(int) c2], - win); - return 0; + return (c1 == c2 + || c2 == ALL_REGS + || hard_reg_set_subset_p (reg_class_contents[(int) c1], + reg_class_contents[(int) c2])); } /* Return nonzero if there is a register that is in both C1 and C2. */ int -reg_classes_intersect_p (c1, c2) - enum reg_class c1; - enum reg_class c2; +reg_classes_intersect_p (enum reg_class c1, enum reg_class c2) { -#ifdef HARD_REG_SET - register -#endif - HARD_REG_SET c; + return (c1 == c2 + || c1 == ALL_REGS + || c2 == ALL_REGS + || hard_reg_set_intersect_p (reg_class_contents[(int) c1], + reg_class_contents[(int) c2])); +} - if (c1 == c2) return 1; +#ifdef CANNOT_CHANGE_MODE_CLASS - if (c1 == ALL_REGS || c2 == ALL_REGS) - return 1; +struct subregs_of_mode_node +{ + unsigned int block; + unsigned char modes[MAX_MACHINE_MODE]; +}; - COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]); - AND_HARD_REG_SET (c, reg_class_contents[(int) c2]); +static htab_t subregs_of_mode; - GO_IF_HARD_REG_SUBSET (c, reg_class_contents[(int) NO_REGS], lose); - return 1; +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; +} + + +static 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); +} + + +/* Call record_subregs_of_mode for all the subregs in X. */ + +static void +find_subregs_of_mode (rtx x) +{ + 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); + + /* 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)); + else if (fmt[i] == 'E') + { + int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + find_subregs_of_mode (XVECEXP (x, i, j)); + } + } +} + +static unsigned int +init_subregs_of_mode (void) +{ + basic_block bb; + rtx insn; + + if (subregs_of_mode) + htab_empty (subregs_of_mode); + else + subregs_of_mode = htab_create (100, som_hash, som_eq, free); + + FOR_EACH_BB (bb) + FOR_BB_INSNS (bb, insn) + if (INSN_P (insn)) + find_subregs_of_mode (PATTERN (insn)); - lose: return 0; } -/* Release any memory allocated by register sets. */ + +/* Set bits in *USED which correspond to registers which can't change + their mode from FROM to any mode in which REGNO was encountered. */ void -regset_release_memory () +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; + unsigned char mask; + unsigned int i; + + gcc_assert (subregs_of_mode); + 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 + mode. */ + +bool +invalid_mode_change_p (unsigned int regno, + enum reg_class class ATTRIBUTE_UNUSED, + enum machine_mode from) +{ + struct subregs_of_mode_node dummy, *node; + enum machine_mode to; + unsigned char mask; + + gcc_assert (subregs_of_mode); + 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; +} + +static unsigned int +finish_subregs_of_mode (void) { - bitmap_release_memory (); + htab_delete (subregs_of_mode); + subregs_of_mode = 0; + return 0; +} +#else +static unsigned int +init_subregs_of_mode (void) +{ + return 0; +} +static unsigned int +finish_subregs_of_mode (void) +{ + return 0; } + +#endif /* CANNOT_CHANGE_MODE_CLASS */ + +static bool +gate_subregs_of_mode_init (void) +{ +#ifdef CANNOT_CHANGE_MODE_CLASS + return true; +#else + return false; +#endif +} + +struct rtl_opt_pass pass_subregs_of_mode_init = +{ + { + RTL_PASS, + "subregs_of_mode_init", /* name */ + gate_subregs_of_mode_init, /* gate */ + init_subregs_of_mode, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + +struct rtl_opt_pass pass_subregs_of_mode_finish = +{ + { + RTL_PASS, + "subregs_of_mode_finish", /* name */ + gate_subregs_of_mode_init, /* gate */ + finish_subregs_of_mode, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + + + +#include "gt-regclass.h"