From b5deb7b691b1ef2afe673899d021e17143e0c957 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Mon, 27 Aug 2007 09:34:14 -0400 Subject: [PATCH] Separate target-specific initialization from general back-end initialization. 2007-08-27 Sandra Loosemore David Ung Nigel Stephens gcc/ 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. Co-Authored-By: David Ung Co-Authored-By: Nigel Stephens From-SVN: r127832 --- gcc/ChangeLog | 57 +++++++++++++++++++++ gcc/alias.c | 4 +- gcc/cfgloopanal.c | 1 + gcc/emit-rtl.c | 129 +++++++++++++++++++++++++----------------------- gcc/expr.c | 7 +-- gcc/expr.h | 6 +-- gcc/optabs.c | 2 +- gcc/regclass.c | 121 ++++++++++++++++++++++++++++++++++----------- gcc/reload1.c | 3 +- gcc/rtl.h | 5 +- gcc/toplev.c | 144 ++++++++++++++++++++++++++++++++++++++++-------------- gcc/toplev.h | 2 + 12 files changed, 344 insertions(+), 137 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fe67c4f..e88e7c9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,60 @@ +2007-08-27 Sandra Loosemore + David Ung + Nigel Stephens + + 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 * rtl.h (XCNMPFV): Preserve const-ness of parameters through use of diff --git a/gcc/alias.c b/gcc/alias.c index 612139b..870fbc4 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 d6a74bf..c00d1c5 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 32dce93..6a4604d 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 2112895..9f321c8 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 24a391c..f9532ec 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 4ef28aa..f2b47fc 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 81ac098..c41ec4d 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 0d6b632..4178969 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 9f36cda..8599658 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 c138c17..fe7918f 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 906fd3d..2397dee 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; -- 2.7.4