summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog57
-rw-r--r--gcc/alias.c4
-rw-r--r--gcc/cfgloopanal.c1
-rw-r--r--gcc/emit-rtl.c129
-rw-r--r--gcc/expr.c7
-rw-r--r--gcc/expr.h6
-rw-r--r--gcc/optabs.c2
-rw-r--r--gcc/regclass.c121
-rw-r--r--gcc/reload1.c3
-rw-r--r--gcc/rtl.h5
-rw-r--r--gcc/toplev.c144
-rw-r--r--gcc/toplev.h2
12 files changed, 344 insertions, 137 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fe67c4f8206..e88e7c95765 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,60 @@
+2007-08-27 Sandra Loosemore <sandra@codesourcery.com>
+ David Ung <davidu@mips.com>
+ Nigel Stephens <nigel@mips.com>
+
+ Separate target-specific initialization from general
+ back-end initialization.
+
+ * toplev.c (init_alignments): New, split out from...
+ (process_options): ...here.
+ (backend_init_target): New, split out from...
+ (backend_init): ...here.
+ (lang_dependent_init_target): New, split out from...
+ (lang_dependent_init): ...here.
+ (target_reinit): New.
+ * toplev.h (target_reinit): Declare.
+ * expr.c (init_expr_target): Renamed from init_expr_once, since it
+ now can be called more than once. Update comments.
+ * expr.h (init_expr_target): Likewise.
+ * alias.c (init_alias_target): Renamed from init_alias_once, since it
+ now can be called more than once. Explicitly zero
+ static_reg_base_value.
+ * emit-rtl.c (init_emit_regs): New, split out from...
+ (init_emit_once): Here.
+ * regclass.c (initial_fixed_regs, initial_call_used_regs): Make
+ non-const, so that changes from command-line arguments can overwrite
+ values provided by the static initializers.
+ (initial_call_really_used_regs): New, used similarly to the above.
+ (initial_reg_names): Likewise.
+ (last_mode_for_init_move_cost): Promoted function-local static to
+ file-scope static to make it accessible outside init_move_cost.
+ (init_reg_sets): Do not initialize fixed_regs and call_used_regs yet.
+ Do not initialize inv_reg_alloc_order yet, either. Do initialize
+ reg_names since it is needed for parsing command-line options.
+ (init_move_cost): Use last_mode_for_init_move_cost instead of
+ function-local static.
+ (init_reg_sets_1): Initialize fixed_regs, call_used_regs, and
+ call_really_used_regs now. Reinitialize reg_names. Also
+ initialize inv_reg_alloc_order. Zero reg_class_subunion and
+ reg_class_superunion. Clear losing_caller_save_reg_set.
+ Preserve global registers if called more than once. Reset
+ move cost, may_move_in_cost, may_move_out_cost, and
+ last_mode_for_init_move_cost.
+ (init_reg_modes_target): Renamed from init_reg_modes_once, since it
+ can now be invoked more than once. Update comments.
+ (init_regs): Update comments.
+ (fix_register): Update initial_fixed_regs, initial_call_used_regs,
+ and initial_call_really_used_regs, instead of the non-initial
+ variables. This allows us to save the command-line register settings
+ after target reinitialization.
+ (init_reg_autoinc): Zero forbidden_inc_dec_classes.
+ * rtl.h (init_emit_regs): Declare.
+ (init_reg_modes_target, init_alias_target): Renamed as described
+ above.
+ * reload1.c (init_reload): Update comments.
+ * optabs.c (init_optabs): Likewise.
+ * cfgloopanal.c (init_set_costs): Explicitly zero target_avail_regs.
+
2007-08-26 Chao-ying Fu <fu@mips.com>
* rtl.h (XCNMPFV): Preserve const-ness of parameters through use of
diff --git a/gcc/alias.c b/gcc/alias.c
index 612139b3b0b..870fbc47adb 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -2325,10 +2325,12 @@ output_dependence (const_rtx mem, const_rtx x)
void
-init_alias_once (void)
+init_alias_target (void)
{
int i;
+ memset (static_reg_base_value, 0, sizeof static_reg_base_value);
+
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
/* Check whether this register can hold an incoming pointer
argument. FUNCTION_ARG_REGNO_P tests outgoing register
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index d6a74bfe519..c00d1c501be 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -334,6 +334,7 @@ init_set_costs (void)
rtx mem = validize_mem (gen_rtx_MEM (SImode, addr));
unsigned i;
+ target_avail_regs = 0;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)
&& !fixed_regs[i])
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 32dce933290..6a4604d40e9 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -5260,6 +5260,74 @@ gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v)
return gen_rtx_raw_CONST_VECTOR (mode, v);
}
+/* Initialise global register information required by all functions. */
+
+void
+init_emit_regs (void)
+{
+ int i;
+
+ /* Reset register attributes */
+ htab_empty (reg_attrs_htab);
+
+ /* We need reg_raw_mode, so initialize the modes now. */
+ init_reg_modes_target ();
+
+ /* Assign register numbers to the globally defined register rtx. */
+ pc_rtx = gen_rtx_PC (VOIDmode);
+ cc0_rtx = gen_rtx_CC0 (VOIDmode);
+ stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);
+ frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
+ hard_frame_pointer_rtx = gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);
+ arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
+ virtual_incoming_args_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
+ virtual_stack_vars_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
+ virtual_stack_dynamic_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
+ virtual_outgoing_args_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
+ virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+
+ /* Initialize RTL for commonly used hard registers. These are
+ copied into regno_reg_rtx as we begin to compile each function. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
+
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+ return_address_pointer_rtx
+ = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
+#endif
+
+#ifdef STATIC_CHAIN_REGNUM
+ static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+
+#ifdef STATIC_CHAIN_INCOMING_REGNUM
+ if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
+ static_chain_incoming_rtx
+ = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
+ else
+#endif
+ static_chain_incoming_rtx = static_chain_rtx;
+#endif
+
+#ifdef STATIC_CHAIN
+ static_chain_rtx = STATIC_CHAIN;
+
+#ifdef STATIC_CHAIN_INCOMING
+ static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
+#else
+ static_chain_incoming_rtx = static_chain_rtx;
+#endif
+#endif
+
+ if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+ pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
+ else
+ pic_offset_table_rtx = NULL_RTX;
+}
+
/* Create some permanent unique rtl objects shared between all functions.
LINE_NUMBERS is nonzero if line numbers are to be generated. */
@@ -5270,9 +5338,6 @@ init_emit_once (int line_numbers)
enum machine_mode mode;
enum machine_mode double_mode;
- /* We need reg_raw_mode, so initialize the modes now. */
- init_reg_modes_once ();
-
/* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
hash tables. */
const_int_htab = htab_create_ggc (37, const_int_htab_hash,
@@ -5321,34 +5386,6 @@ init_emit_once (int line_numbers)
ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
- /* Assign register numbers to the globally defined register rtx.
- This must be done at runtime because the register number field
- is in a union and some compilers can't initialize unions. */
-
- pc_rtx = gen_rtx_PC (VOIDmode);
- cc0_rtx = gen_rtx_CC0 (VOIDmode);
- stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);
- frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
- if (hard_frame_pointer_rtx == 0)
- hard_frame_pointer_rtx = gen_raw_REG (Pmode,
- HARD_FRAME_POINTER_REGNUM);
- if (arg_pointer_rtx == 0)
- arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
- virtual_incoming_args_rtx =
- gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
- virtual_stack_vars_rtx =
- gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
- virtual_stack_dynamic_rtx =
- gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
- virtual_outgoing_args_rtx =
- gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
- virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
-
- /* Initialize RTL for commonly used hard registers. These are
- copied into regno_reg_rtx as we begin to compile each function. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
-
#ifdef INIT_EXPANDERS
/* This is to initialize {init|mark|free}_machine_status before the first
call to push_function_context_to. This is needed by the Chill front
@@ -5558,36 +5595,6 @@ init_emit_once (int line_numbers)
const_tiny_rtx[0][(int) BImode] = const0_rtx;
if (STORE_FLAG_VALUE == 1)
const_tiny_rtx[1][(int) BImode] = const1_rtx;
-
-#ifdef RETURN_ADDRESS_POINTER_REGNUM
- return_address_pointer_rtx
- = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
-#endif
-
-#ifdef STATIC_CHAIN_REGNUM
- static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
-
-#ifdef STATIC_CHAIN_INCOMING_REGNUM
- if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
- static_chain_incoming_rtx
- = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
- else
-#endif
- static_chain_incoming_rtx = static_chain_rtx;
-#endif
-
-#ifdef STATIC_CHAIN
- static_chain_rtx = STATIC_CHAIN;
-
-#ifdef STATIC_CHAIN_INCOMING
- static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
-#else
- static_chain_incoming_rtx = static_chain_rtx;
-#endif
-#endif
-
- if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
- pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
}
/* Produce exact duplicate of insn INSN after AFTER.
diff --git a/gcc/expr.c b/gcc/expr.c
index 21128958e73..9f321c80ad9 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -243,11 +243,12 @@ enum insn_code sync_lock_release[NUM_MACHINE_MODES];
#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
#endif
-/* This is run once per compilation to set up which modes can be used
- directly in memory and to initialize the block move optab. */
+/* This is run to set up which modes can be used
+ directly in memory and to initialize the block move optab. It is run
+ at the beginning of compilation and when the target is reinitialized. */
void
-init_expr_once (void)
+init_expr_target (void)
{
rtx insn, pat;
enum machine_mode mode;
diff --git a/gcc/expr.h b/gcc/expr.h
index 24a391cc7f6..f9532eceb96 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -352,9 +352,9 @@ extern rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
/* Functions from expr.c: */
-/* This is run once per compilation to set up which modes can be used
- directly in memory and to initialize the block move optab. */
-extern void init_expr_once (void);
+/* This is run during target initialization to set up which modes can be
+ used directly in memory and to initialize the block move optab. */
+extern void init_expr_target (void);
/* This is run at the start of compiling a function. */
extern void init_expr (void);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 4ef28aa7c2f..f2b47fc4f68 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -5563,7 +5563,7 @@ set_conv_libfunc (convert_optab optable, enum machine_mode tmode,
convert_optab_handler (optable, tmode, fmode)->libfunc = 0;
}
-/* Call this once to initialize the contents of the optabs
+/* Call this to initialize the contents of the optabs
appropriately for the current target machine. */
void
diff --git a/gcc/regclass.c b/gcc/regclass.c
index 81ac098f218..c41ec4d9bfc 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -81,7 +81,7 @@ HARD_REG_SET fixed_reg_set;
/* Data for initializing the above. */
-static const char initial_fixed_regs[] = FIXED_REGISTERS;
+static char initial_fixed_regs[] = FIXED_REGISTERS;
/* Indexed by hard register number, contains 1 for registers
that are fixed use or are clobbered by function calls.
@@ -100,7 +100,7 @@ HARD_REG_SET losing_caller_save_reg_set;
/* Data for initializing the above. */
-static const char initial_call_used_regs[] = CALL_USED_REGISTERS;
+static char initial_call_used_regs[] = CALL_USED_REGISTERS;
/* This is much like call_used_regs, except it doesn't have to
be a superset of FIXED_REGISTERS. This vector indicates
@@ -108,7 +108,8 @@ static const char initial_call_used_regs[] = CALL_USED_REGISTERS;
regs_invalidated_by_call. */
#ifdef CALL_REALLY_USED_REGISTERS
-char call_really_used_regs[] = CALL_REALLY_USED_REGISTERS;
+static char initial_call_really_used_regs[] = CALL_REALLY_USED_REGISTERS;
+char call_really_used_regs[FIRST_PSEUDO_REGISTER];
#endif
#ifdef CALL_REALLY_USED_REGISTERS
@@ -192,7 +193,11 @@ enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES];
/* Array containing all of the register names. */
-const char * reg_names[] = REGISTER_NAMES;
+const char * reg_names[FIRST_PSEUDO_REGISTER];
+
+/* Data for initializing the above. */
+
+const char * initial_reg_names[] = REGISTER_NAMES;
/* Array containing all of the register class names. */
@@ -230,6 +235,9 @@ static move_table *may_move_in_cost[MAX_MACHINE_MODE];
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
/* These are the classes that regs which are auto-incremented or decremented
@@ -298,19 +306,12 @@ 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);
-#ifdef REG_ALLOC_ORDER
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- inv_reg_alloc_order[reg_alloc_order[i]] = i;
-#endif
+ /* Processing of command-line options like -ffixed needs to know the
+ initial set of register names, so initialize that now. */
+ gcc_assert (sizeof reg_names == sizeof initial_reg_names);
+ memcpy (reg_names, initial_reg_names, sizeof reg_names);
}
/* Initialize may_move_cost and friends for mode M. */
@@ -319,7 +320,6 @@ static void
init_move_cost (enum machine_mode m)
{
static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
- static int last_mode = -1;
bool all_match = true;
unsigned int i, j;
@@ -339,14 +339,14 @@ init_move_cost (enum machine_mode m)
all_match &= (last_move_cost[i][j] == cost);
last_move_cost[i][j] = cost;
}
- if (all_match && last_mode != -1)
+ if (all_match && last_mode_for_init_move_cost != -1)
{
- move_cost[m] = move_cost[last_mode];
- may_move_in_cost[m] = may_move_in_cost[last_mode];
- may_move_out_cost[m] = may_move_out_cost[last_mode];
+ 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 = m;
+ 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)
@@ -412,6 +412,31 @@ init_reg_sets_1 (void)
unsigned int i, j;
unsigned int /* enum machine_mode */ m;
+ /* 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);
+
+ /* Likewise for call_really_used_regs. */
+#ifdef CALL_REALLY_USED_REGISTERS
+ gcc_assert (sizeof call_really_used_regs
+ == sizeof initial_call_really_used_regs);
+ memcpy (call_really_used_regs, initial_call_really_used_regs,
+ sizeof call_really_used_regs);
+#endif
+
+ /* And similarly for reg_names. */
+ gcc_assert (sizeof reg_names == sizeof initial_reg_names);
+ memcpy (reg_names, initial_reg_names, sizeof reg_names);
+
+#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. */
@@ -431,6 +456,7 @@ init_reg_sets_1 (void)
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++)
@@ -453,6 +479,7 @@ init_reg_sets_1 (void)
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++)
@@ -511,6 +538,7 @@ init_reg_sets_1 (void)
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);
@@ -564,6 +592,18 @@ init_reg_sets_1 (void)
SET_HARD_REG_BIT (regs_invalidated_by_call, i);
}
+ /* 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++)
@@ -582,14 +622,36 @@ init_reg_sets_1 (void)
have_regs_of_mode [m] = 1;
}
}
+
+ /* 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])
+ {
+ 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]);
+ }
+ }
+ 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.
+*/
void
-init_reg_modes_once (void)
+init_reg_modes_target (void)
{
int i, j;
@@ -611,8 +673,10 @@ init_reg_modes_once (void)
}
}
-/* 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 (void)
@@ -782,11 +846,11 @@ fix_register (const char *name, int fixed, int call_used)
}
else
{
- fixed_regs[i] = fixed;
- call_used_regs[i] = call_used;
+ initial_fixed_regs[i] = fixed;
+ initial_call_used_regs[i] = call_used;
#ifdef CALL_REALLY_USED_REGISTERS
if (fixed == 0)
- call_really_used_regs[i] = call_used;
+ initial_call_really_used_regs[i] = call_used;
#endif
}
}
@@ -1157,6 +1221,7 @@ init_reg_autoinc (void)
#ifdef FORBIDDEN_INC_DEC_CLASSES
int i;
+ memset (forbidden_inc_dec_class, 0, sizeof forbidden_inc_dec_classes);
for (i = 0; i < N_REG_CLASSES; i++)
{
rtx r = gen_rtx_raw_REG (VOIDmode, 0);
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 0d6b6325184..41789696685 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -448,7 +448,8 @@ static int reloads_conflict (int, int);
static rtx gen_reload (rtx, rtx, int, enum reload_type);
static rtx emit_insn_if_valid_for_reload (rtx);
-/* Initialize the reload pass once per compilation. */
+/* Initialize the reload pass. This is called at the beginning of compilation
+ and may be called again if the target is reinitialized. */
void
init_reload (void)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 9f36cdaf22d..85996585848 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2077,6 +2077,7 @@ extern int get_max_uid (void);
extern int in_sequence_p (void);
extern void force_next_line_note (void);
extern void init_emit (void);
+extern void init_emit_regs (void);
extern void init_emit_once (int);
extern void push_topmost_sequence (void);
extern void pop_topmost_sequence (void);
@@ -2186,7 +2187,7 @@ extern void build_insn_chain (rtx);
extern int reg_classes_intersect_p (enum reg_class, enum reg_class);
extern int reg_class_subset_p (enum reg_class, enum reg_class);
extern void globalize_reg (int);
-extern void init_reg_modes_once (void);
+extern void init_reg_modes_target (void);
extern void init_regs (void);
extern void init_fake_stack_mems (void);
extern void init_reg_sets (void);
@@ -2254,7 +2255,7 @@ extern int canon_true_dependence (const_rtx, enum machine_mode, rtx, const_rtx,
extern int read_dependence (const_rtx, const_rtx);
extern int anti_dependence (const_rtx, const_rtx);
extern int output_dependence (const_rtx, const_rtx);
-extern void init_alias_once (void);
+extern void init_alias_target (void);
extern void init_alias_analysis (void);
extern void end_alias_analysis (void);
extern bool memory_modified_in_insn_p (const_rtx, const_rtx);
diff --git a/gcc/toplev.c b/gcc/toplev.c
index c138c178d51..fe7918fd736 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1685,6 +1685,31 @@ target_supports_section_anchors_p (void)
return true;
}
+/* Default the align_* variables to 1 if they're still unset, and
+ set up the align_*_log variables. */
+static void
+init_alignments (void)
+{
+ if (align_loops <= 0)
+ align_loops = 1;
+ if (align_loops_max_skip > align_loops)
+ align_loops_max_skip = align_loops - 1;
+ align_loops_log = floor_log2 (align_loops * 2 - 1);
+ if (align_jumps <= 0)
+ align_jumps = 1;
+ if (align_jumps_max_skip > align_jumps)
+ align_jumps_max_skip = align_jumps - 1;
+ align_jumps_log = floor_log2 (align_jumps * 2 - 1);
+ if (align_labels <= 0)
+ align_labels = 1;
+ align_labels_log = floor_log2 (align_labels * 2 - 1);
+ if (align_labels_max_skip > align_labels)
+ align_labels_max_skip = align_labels - 1;
+ if (align_functions <= 0)
+ align_functions = 1;
+ align_functions_log = floor_log2 (align_functions * 2 - 1);
+}
+
/* Process the options that have been parsed. */
static void
process_options (void)
@@ -1730,23 +1755,6 @@ process_options (void)
else
aux_base_name = "gccaux";
- /* Set up the align_*_log variables, defaulting them to 1 if they
- were still unset. */
- if (align_loops <= 0) align_loops = 1;
- if (align_loops_max_skip > align_loops || !align_loops)
- align_loops_max_skip = align_loops - 1;
- align_loops_log = floor_log2 (align_loops * 2 - 1);
- if (align_jumps <= 0) align_jumps = 1;
- if (align_jumps_max_skip > align_jumps || !align_jumps)
- align_jumps_max_skip = align_jumps - 1;
- align_jumps_log = floor_log2 (align_jumps * 2 - 1);
- if (align_labels <= 0) align_labels = 1;
- align_labels_log = floor_log2 (align_labels * 2 - 1);
- if (align_labels_max_skip > align_labels || !align_labels)
- align_labels_max_skip = align_labels - 1;
- if (align_functions <= 0) align_functions = 1;
- align_functions_log = floor_log2 (align_functions * 2 - 1);
-
/* Unrolling all loops implies that standard loop unrolling must also
be done. */
if (flag_unroll_all_loops)
@@ -1998,7 +2006,50 @@ process_options (void)
}
}
-/* Initialize the compiler back end. */
+/* This function can be called multiple times to reinitialize the compiler
+ back end when register classes or instruction sets have changed,
+ before each function. */
+static void
+backend_init_target (void)
+{
+ /* Initialize alignment variables. */
+ init_alignments ();
+
+ /* This reinitializes hard_frame_pointer, and calls init_reg_modes_target()
+ to initialize reg_raw_mode[]. */
+ init_emit_regs ();
+
+ /* This invokes target hooks to set fixed_reg[] etc, which is
+ mode-dependent. */
+ init_regs ();
+
+ /* This depends on stack_pointer_rtx. */
+ init_fake_stack_mems ();
+
+ /* Sets static_base_value[HARD_FRAME_POINTER_REGNUM], which is
+ mode-dependent. */
+ init_alias_target ();
+
+ /* Depends on HARD_FRAME_POINTER_REGNUM. */
+ init_reload ();
+
+ /* The following initialization functions need to generate rtl, so
+ provide a dummy function context for them. */
+ init_dummy_function_start ();
+
+ /* rtx_cost is mode-dependent, so cached values need to be recomputed
+ on a mode change. */
+ init_expmed ();
+
+ /* We may need to recompute regno_save_code[] and regno_restore_code[]
+ after a mode change as well. */
+ if (flag_caller_saves)
+ init_caller_save ();
+ expand_dummy_function_end ();
+}
+
+/* Initialize the compiler back end. This function is called only once,
+ when starting the compiler. */
static void
backend_init (void)
{
@@ -2011,19 +2062,34 @@ backend_init (void)
|| flag_test_coverage);
init_rtlanal ();
- init_regs ();
- init_fake_stack_mems ();
- init_alias_once ();
init_inline_once ();
- init_reload ();
init_varasm_once ();
+ /* Initialize the target-specific back end pieces. */
+ backend_init_target ();
+}
+
+/* Initialize things that are both lang-dependent and target-dependent.
+ This function can be called more than once if target parameters change. */
+static void
+lang_dependent_init_target (void)
+{
+ /* This creates various _DECL nodes, so needs to be called after the
+ front end is initialized. It also depends on the HAVE_xxx macros
+ generated from the target machine description. */
+ init_optabs ();
+
/* The following initialization functions need to generate rtl, so
provide a dummy function context for them. */
init_dummy_function_start ();
- init_expmed ();
- if (flag_caller_saves)
- init_caller_save ();
+
+ /* Do the target-specific parts of expr initialization. */
+ init_expr_target ();
+
+ /* Although the actions of init_set_costs are language-independent,
+ it uses optabs, so we cannot call it from backend_init. */
+ init_set_costs ();
+
expand_dummy_function_end ();
}
@@ -2048,21 +2114,12 @@ lang_dependent_init (const char *name)
init_asm_output (name);
- /* These create various _DECL nodes, so need to be called after the
+ /* This creates various _DECL nodes, so needs to be called after the
front end is initialized. */
init_eh ();
- init_optabs ();
-
- /* The following initialization functions need to generate rtl, so
- provide a dummy function context for them. */
- init_dummy_function_start ();
- init_expr_once ();
-
- /* Although the actions of init_set_costs are language-independent,
- it uses optabs, so we cannot call it from backend_init. */
- init_set_costs ();
- expand_dummy_function_end ();
+ /* Do the target-specific parts of the initialization. */
+ lang_dependent_init_target ();
/* If dbx symbol table desired, initialize writing it and output the
predefined types. */
@@ -2082,6 +2139,19 @@ lang_dependent_init (const char *name)
return 1;
}
+
+/* Reinitialize everything when target parameters, such as register usage,
+ have changed. */
+void
+target_reinit (void)
+{
+ /* Reinitialise RTL backend. */
+ backend_init_target ();
+
+ /* Reinitialize lang-dependent parts. */
+ lang_dependent_init_target ();
+}
+
void
dump_memory_report (bool final)
{
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 906fd3de832..2397dee6dbf 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -101,6 +101,8 @@ extern void write_global_declarations (void);
extern void dump_memory_report (bool);
+extern void target_reinit (void);
+
/* A unique local time stamp, might be zero if none is available. */
extern unsigned local_tick;