diff options
-rw-r--r-- | gcc/ChangeLog | 89 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 61 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 10 | ||||
-rw-r--r-- | gcc/function.c | 27 | ||||
-rw-r--r-- | gcc/function.h | 28 | ||||
-rw-r--r-- | gcc/integrate.c | 1091 | ||||
-rw-r--r-- | gcc/output.h | 3 | ||||
-rw-r--r-- | gcc/rtl.h | 4 | ||||
-rw-r--r-- | gcc/toplev.c | 64 | ||||
-rw-r--r-- | gcc/tree.c | 144 | ||||
-rw-r--r-- | gcc/varasm.c | 247 |
11 files changed, 354 insertions, 1414 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 16b5aedff98..60c82c66a90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,92 @@ +Sat Sep 4 13:11:01 1999 Bernd Schmidt <bernds@cygnus.co.uk> + + Change obstack memory management and varasm constant pool handling so + that nested functions are treated like any other functions. + * function.c (init_machine_status): New variable. + (push_function_context_to): Set contains_functions for the outer + function. Don't call save_varasm_status. + (pop_function_context_from): Don't call restore_varasm_status. Don't + set current_function_contains_functions. + (prepare_function_start): Call init_varasm_status rather than + init_const_rtx_hash_table. Call (*init_machine_status) if the pointer + is non-null. + * function.h (struct function) Add field varasm. Delete fields + inline_obstacks, inl_emit, const_rtx_hash_table, first_pool, + last_pool, const_rtx_sym_hash_table, pool_offset, const_double_chain. + (init_machine_status): Declare. + (save_varasm_status, restore_varasm_status): Delete declarations. + (save_tree_status, restore_tree_status): Delete last argument. + * integrate.c (initialize_for_inline): Lose arg COPY. Delete copying + code. All callers changed. + (copy_decl_list, copy_decl_tree, copy_decl_rtls, copy_for_inline, + save_constants_in_decl_trees, restore_constants, save_constants, + save_for_inline_eh_labelmap, save_for_inline_copying): Delete + functions. + (inlining): New variable. + (reg_map, label_map, insn_map, orig_asm_operands_vector, + copy_asm_operands_vector, copy_asm_constraints_vector): Delete + variables. + (save_for_inline_nocopy): Don't save constants. + Don't set inl_emit field in current_function. + (expand_inline_function): Use emit field, not inl_emit, of the inlined + function. Set new variable inlining before + calling copy_rtx_and_substitute. + (copy_rtx_and_substitute): In MEM and SYMBOL_REF cases, handle + constant pool references if inlining is nonzero. + Delete ADDRESS and (most of the) CONST cases. + (output_inline_function): Save and restore current_function/ + current_function_decl. Delete restore_constants code. Don't call + init_const_rtx_hash_table. + * output.h (init_const_rtx_hash_table): Don't declare. + * rtl.h (struct function): Declare. + (get_pool_constant_for_function, get_pool_mode_for_function): Declare. + * toplev.c (rest_of_compilation): Don't treat nested functions or + functions containing them specially. Delete all code to deal with + save_for_inline_copying. + * tree.c (toplev_inline_obstacks, extra_inline_obstacks, + inline_obstacks): Delete variables. + (save_tree_status): Lose arg CONTEXT. All callers changed. + Simply allocate a new function_maybepermanent_obstack for the new + function, delete all the special cases. + Don't save inline_obstacks. + (restore_tree_status): Lose arg CONTEXT. All callers changed. + Delete special handling for function_maybepermanent_obstack; simply + free it if empty. + Don't restore inline_obstacks. + (permanent_allocation): Delete code that frees inline_obstacks. + (print_inline_obstack_statistics): Delete function. + (dump_tree_statistics): Don't call it. + * varasm.c (struct varasm_status): New. + (const_rtx_hash_table, const_rtx_sym_hash_table, first_pool, + last_pool, pool_offset, const_double_chain): Delete global + variables, replace with accessor macros. + (immed_double_const): Don't walk const_double_chain outside a + function, but don't treat nested functions specially anymore. + (immed_real_const_1): Likewise. + (clear_const_double_mem): Don't treat nested functions specially. + (init_const_rtx_hash_table): Deleted, code moved to init_varasm_status. + (save_varasm_status, restore_varasm_status): Delete functions. + (init_varasm_status): New function. + (force_const_mem): Don't treat nested functions specially. + (find_pool_constant): Accept new arg F, search for constants in + that function's pool rather than the current one. All callers + changed. + (get_pool_constant_for_function, get_pool_mode_for_function): New + functions. + + * i386.c (init_386_machine_status): New function, mostly from + clear_386_stack_locals. + (struct machine_functions): Rename element names to avoid name + clashes. + (pic_label_rtx, pic_label_name, i386_stack_locals): New accessor + macros, replacing global variables. + (clear_386_stack_locals, save_386_machine_status, + restore_386_machine_status): Delete functions. + (override_options): Initialize init_machine_status. + * i386.h (INIT_EXPANDERS): Delete macro. + (save_386_machine_status, restore_386_machine_status, + clear_386_stack_locals): Delete declarations. + Sat Sep 4 16:56:28 1999 Michael Hayes <m.hayes@elec.canterbury.ac.nz> * config/c4x/c4x.md (rptb_init): Renamed from *rptb_init. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 001443ba236..04b79b8d7e8 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -168,6 +168,18 @@ enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] = struct rtx_def *ix86_compare_op0 = NULL_RTX; struct rtx_def *ix86_compare_op1 = NULL_RTX; +#define MAX_386_STACK_LOCALS 2 + +/* Define the structure for the machine field in struct function. */ +struct machine_function +{ + rtx stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; +}; + +static int pic_label_no = 0; + +#define ix86_stack_locals (current_function->machine->stack_locals) + /* which cpu are we scheduling for */ enum processor_type ix86_cpu; @@ -235,6 +247,7 @@ static void ix86_dump_ppro_packet PROTO ((FILE *)); static void ix86_reorder_insn PROTO ((rtx *, rtx *)); static rtx * ix86_pent_find_pair PROTO ((rtx *, rtx *, enum attr_pent_pair, rtx)); +static void ix86_init_machine_status PROTO ((struct function *)); struct ix86_address { @@ -338,6 +351,9 @@ override_options () target_flags |= processor_target_table[ix86_cpu].target_enable; target_flags &= ~processor_target_table[ix86_cpu].target_disable; + /* Arrange to set up i386_stack_locals for all functions. */ + init_machine_status = ix86_init_machine_status; + /* Validate registers in register allocation order. */ if (ix86_reg_alloc_order) { @@ -4940,58 +4956,23 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch) emit_label (end_0_label); } -#define MAX_386_STACK_LOCALS 2 - -static rtx ix86_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; - -/* Define the structure for the machine field in struct function. */ -struct machine_function -{ - rtx ix86_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; -}; - -/* Functions to save and restore ix86_stack_locals. - These will be called, via pointer variables, - from push_function_context and pop_function_context. */ - -void -save_386_machine_status (p) - struct function *p; -{ - p->machine - = (struct machine_function *) xmalloc (sizeof (struct machine_function)); - bcopy ((char *) ix86_stack_locals, (char *) p->machine->ix86_stack_locals, - sizeof ix86_stack_locals); -} - -void -restore_386_machine_status (p) - struct function *p; -{ - bcopy ((char *) p->machine->ix86_stack_locals, (char *) ix86_stack_locals, - sizeof ix86_stack_locals); - free (p->machine); - p->machine = NULL; -} - /* Clear stack slot assignments remembered from previous functions. This is called from INIT_EXPANDERS once before RTL is emitted for each function. */ -void -clear_386_stack_locals () +static void +ix86_init_machine_status (p) + struct function *p; { enum machine_mode mode; int n; + p->machine + = (struct machine_function *) xmalloc (sizeof (struct machine_function)); for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1)) for (n = 0; n < MAX_386_STACK_LOCALS; n++) ix86_stack_locals[(int) mode][n] = NULL_RTX; - - /* Arrange to save and restore ix86_stack_locals around nested functions. */ - save_machine_status = save_386_machine_status; - restore_machine_status = restore_386_machine_status; } /* Return a MEM corresponding to a stack slot with mode MODE. diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index ec05ac468f8..c3efd72c245 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1603,13 +1603,6 @@ do \ } \ while (0) -/* Initialize data used by insn expanders. This is called from - init_emit, once for each function, before code is generated. - For 386, clear stack slot assignments remembered from previous - functions. */ - -#define INIT_EXPANDERS clear_386_stack_locals () - /* The `FINALIZE_PIC' macro serves as a hook to emit these special codes once the function is being compiled into assembly code, but not before. (It is not done before, because in the case of @@ -2498,9 +2491,6 @@ extern void ix86_split_ashrdi XPARAMS((xrtx *, xrtx)); extern void ix86_split_lshrdi XPARAMS((xrtx *, xrtx)); extern void ix86_expand_strlensi_unroll_1 XPARAMS((xrtx, xrtx, xrtx)); -extern void save_386_machine_status XPARAMS((struct function *)); -extern void restore_386_machine_status XPARAMS((struct function *)); -extern void clear_386_stack_locals XPARAMS((void)); extern xrtx assign_386_stack_local XPARAMS((xmode, int)); extern int ix86_attr_length_default XPARAMS((xrtx)); diff --git a/gcc/function.c b/gcc/function.c index c86792164eb..6d07ff351cc 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -117,6 +117,7 @@ static int virtuals_instantiated; /* These variables hold pointers to functions to save and restore machine-specific data, in push_function_context and pop_function_context. */ +void (*init_machine_status) PROTO((struct function *)); void (*save_machine_status) PROTO((struct function *)); void (*restore_machine_status) PROTO((struct function *)); @@ -300,7 +301,15 @@ void push_function_context_to (context) tree context; { - struct function *p; + struct function *p, *context_data; + + if (context) + { + context_data = (context == current_function_decl + ? current_function + : find_function_data (context)); + context_data->contains_functions = 1; + } if (current_function == 0) init_dummy_function_start (); @@ -311,8 +320,7 @@ push_function_context_to (context) p->decl = current_function_decl; p->fixup_var_refs_queue = 0; - save_tree_status (p, context); - save_varasm_status (p, context); + save_tree_status (p); if (save_lang_status) (*save_lang_status) (p); if (save_machine_status) @@ -340,14 +348,11 @@ pop_function_context_from (context) current_function = p; outer_function_chain = p->next; - current_function_contains_functions - |= p->inline_obstacks || context == current_function_decl; current_function_decl = p->decl; reg_renumber = 0; - restore_tree_status (p, context); + restore_tree_status (p); restore_emit_status (p); - restore_varasm_status (p); if (restore_machine_status) (*restore_machine_status) (p); @@ -365,7 +370,8 @@ pop_function_context_from (context) virtuals_instantiated = 0; } -void pop_function_context () +void +pop_function_context () { pop_function_context_from (current_function_decl); } @@ -5576,7 +5582,7 @@ prepare_function_start () /* We haven't done register allocation yet. */ reg_renumber = 0; - init_const_rtx_hash_table (); + init_varasm_status (current_function); /* Set if a call to setjmp is seen. */ current_function_calls_setjmp = 0; @@ -5640,6 +5646,9 @@ prepare_function_start () inhibit_defer_pop = 0; current_function_outgoing_args_size = 0; + + if (init_machine_status) + (*init_machine_status) (current_function); } /* Initialize the rtl expansion mechanism so that we can do simple things diff --git a/gcc/function.h b/gcc/function.h index 9a9156ae2a8..d34da4010a0 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -182,6 +182,7 @@ struct function struct stmt_status *stmt; struct expr_status *expr; struct emit_status *emit; + struct varasm_status *varasm; /* For function.c. */ @@ -415,12 +416,9 @@ struct function struct obstack *expression_obstack; struct obstack *saveable_obstack; struct obstack *rtl_obstack; - struct simple_obstack_stack *inline_obstacks; - /* For integrate.c. We duplicate some of the fields so that - save_for_inline_copying can keep two versions. */ + /* For integrate.c. */ int inlinable; - struct emit_status *inl_emit; /* This is in fact an rtvec. */ void *original_arg_vector; tree original_decl_initial; @@ -448,13 +446,6 @@ struct function /* If some insns can be deferred to the delay slots of the epilogue, the delay list for them is recorded here. */ rtx epilogue_delay_list; - - /* For varasm. */ - struct constant_descriptor **const_rtx_hash_table; - struct pool_sym **const_rtx_sym_hash_table; - struct pool_constant *first_pool, *last_pool; - int pool_offset; - rtx const_double_chain; }; extern struct function *current_function; @@ -534,25 +525,24 @@ extern tree *identify_blocks PROTO((tree, rtx)); /* Return size needed for stack frame based on slots so far allocated. This size counts from zero. It is not rounded to STACK_BOUNDARY; the caller may have to do that. */ -extern HOST_WIDE_INT get_frame_size PROTO((void)); +extern HOST_WIDE_INT get_frame_size PROTO((void)); /* Likewise, but for a different than the current function. */ -extern HOST_WIDE_INT get_func_frame_size PROTO((struct function *)); +extern HOST_WIDE_INT get_func_frame_size PROTO((struct function *)); /* These variables hold pointers to functions to save and restore machine-specific data, in push_function_context and pop_function_context. */ -extern void (*save_machine_status) PROTO((struct function *)); -extern void (*restore_machine_status) PROTO((struct function *)); +extern void (*init_machine_status) PROTO((struct function *)); +extern void (*save_machine_status) PROTO((struct function *)); +extern void (*restore_machine_status) PROTO((struct function *)); /* Likewise, but for language-specific data. */ extern void (*save_lang_status) PROTO((struct function *)); extern void (*restore_lang_status) PROTO((struct function *)); /* Save and restore status information for a nested function. */ -extern void save_tree_status PROTO((struct function *, tree)); -extern void restore_tree_status PROTO((struct function *, tree)); -extern void save_varasm_status PROTO((struct function *, tree)); -extern void restore_varasm_status PROTO((struct function *)); +extern void save_tree_status PROTO((struct function *)); +extern void restore_tree_status PROTO((struct function *)); extern void restore_emit_status PROTO((struct function *)); extern rtx get_first_block_beg PROTO((void)); diff --git a/gcc/integrate.c b/gcc/integrate.c index 56d09c2010e..ce7d773912f 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -60,22 +60,15 @@ extern struct obstack *function_maybepermanent_obstack; : (8 * (8 + list_length (DECL_ARGUMENTS (DECL))))) #endif -static rtvec initialize_for_inline PROTO((tree, int)); +static rtvec initialize_for_inline PROTO((tree)); static void adjust_copied_decl_tree PROTO((tree)); -static tree copy_decl_list PROTO((tree)); -static tree copy_decl_tree PROTO((tree)); -static void copy_decl_rtls PROTO((tree)); -static void save_constants PROTO((rtx *)); static void note_modified_parmregs PROTO((rtx, rtx)); -static rtx copy_for_inline PROTO((rtx)); static void integrate_parm_decls PROTO((tree, struct inline_remap *, rtvec)); static void integrate_decl_tree PROTO((tree, int, struct inline_remap *)); -static void save_constants_in_decl_trees PROTO ((tree)); static void subst_constants PROTO((rtx *, rtx, struct inline_remap *)); -static void restore_constants PROTO((rtx *)); static void set_block_origin_self PROTO((tree)); static void set_decl_origin_self PROTO((tree)); static void set_block_abstract_flags PROTO((tree, int)); @@ -95,6 +88,11 @@ static tree copy_and_set_decl_abstract_origin PROTO((tree)); int inline_max_insns = 10000; +/* Used by copy_rtx_and_substitute; this indicates whether the function is + called for the purpose of inlining or some other purpose (i.e. loop + unrolling). This affects how constant pool references are handled. + This variable contains the FUNCTION_DECL for the inlined function. */ +static struct function *inlining = 0; /* Returns the Ith entry in the label_map contained in MAP. If the Ith entry has not yet been set, return a fresh label. This function @@ -231,63 +229,20 @@ function_cannot_inline_p (fndecl) return 0; } -/* Variables used within save_for_inline. */ - -/* Mapping from old pseudo-register to new pseudo-registers. - The first element of this map is reg_map[FIRST_PSEUDO_REGISTER]. - It is allocated in `save_for_inline' and `expand_inline_function', - and deallocated on exit from each of those routines. */ -static rtx *reg_map; - -/* Mapping from old code-labels to new code-labels. - The first element of this map is label_map[min_labelno]. - It is allocated in `save_for_inline' and `expand_inline_function', - and deallocated on exit from each of those routines. */ -static rtx *label_map; - -/* Mapping from old insn uid's to copied insns. - It is allocated in `save_for_inline' and `expand_inline_function', - and deallocated on exit from each of those routines. */ -static rtx *insn_map; - /* Map pseudo reg number into the PARM_DECL for the parm living in the reg. Zero for a reg that isn't a parm's home. Only reg numbers less than max_parm_reg are mapped here. */ static tree *parmdecl_map; -/* When an insn is being copied by copy_for_inline, - this is nonzero if we have copied an ASM_OPERANDS. - In that case, it is the original input-operand vector. */ -static rtvec orig_asm_operands_vector; - -/* When an insn is being copied by copy_for_inline, - this is nonzero if we have copied an ASM_OPERANDS. - In that case, it is the copied input-operand vector. */ -static rtvec copy_asm_operands_vector; - -/* Likewise, this is the copied constraints vector. */ -static rtvec copy_asm_constraints_vector; - /* In save_for_inline, nonzero if past the parm-initialization insns. */ static int in_nonparm_insns; -/* subroutines passed to duplicate_eh_handlers to map exception labels */ - -static rtx -save_for_inline_eh_labelmap (label) - rtx label; -{ - int index = CODE_LABEL_NUMBER (label); - return label_map[index]; -} - -/* Subroutine for `save_for_inline{copying,nocopy}'. Performs initialization +/* Subroutine for `save_for_inline_nocopy'. Performs initialization needed to save FNDECL's insns and info for future inline expansion. */ - + static rtvec -initialize_for_inline (fndecl, copy) +initialize_for_inline (fndecl) tree fndecl; - int copy; { int i; rtvec arg_vector; @@ -302,7 +257,6 @@ initialize_for_inline (fndecl, copy) parms = TREE_CHAIN (parms), i++) { rtx p = DECL_RTL (parms); - int copied_incoming = 0; /* If we have (mem (addressof (mem ...))), use the inner MEM since otherwise the copy_rtx call below will not unshare the MEM since @@ -311,25 +265,6 @@ initialize_for_inline (fndecl, copy) && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM) p = XEXP (XEXP (p, 0), 0); - if (GET_CODE (p) == MEM && copy) - { - /* Copy the rtl so that modifications of the addresses - later in compilation won't affect this arg_vector. - Virtual register instantiation can screw the address - of the rtl. */ - rtx new = copy_rtx (p); - - /* Don't leave the old copy anywhere in this decl. */ - if (DECL_RTL (parms) == DECL_INCOMING_RTL (parms) - || (GET_CODE (DECL_RTL (parms)) == MEM - && GET_CODE (DECL_INCOMING_RTL (parms)) == MEM - && (XEXP (DECL_RTL (parms), 0) - == XEXP (DECL_INCOMING_RTL (parms), 0)))) - DECL_INCOMING_RTL (parms) = new, copied_incoming = 1; - - DECL_RTL (parms) = new; - } - RTVEC_ELT (arg_vector, i) = p; if (GET_CODE (p) == REG) @@ -348,23 +283,6 @@ initialize_for_inline (fndecl, copy) /* This flag is cleared later if the function ever modifies the value of the parm. */ TREE_READONLY (parms) = 1; - - /* Copy DECL_INCOMING_RTL if not done already. This can - happen if DECL_RTL is a reg. */ - if (copy && ! copied_incoming) - { - p = DECL_INCOMING_RTL (parms); - - /* If we have (mem (addressof (mem ...))), use the inner MEM since - otherwise the copy_rtx call below will not unshare the MEM since - it shares ADDRESSOF. */ - if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF - && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM) - p = XEXP (XEXP (p, 0), 0); - - if (GET_CODE (p) == MEM) - DECL_INCOMING_RTL (parms) = copy_rtx (p); - } } return arg_vector; @@ -394,314 +312,6 @@ adjust_copied_decl_tree (block) adjust_copied_decl_tree (subblock); } -/* Make the insns and PARM_DECLs of the current function permanent - and record other information in DECL_SAVED_INSNS to allow inlining - of this function in subsequent calls. - - This function is called when we are going to immediately compile - the insns for FNDECL. The insns in maybepermanent_obstack cannot be - modified by the compilation process, so we copy all of them to - new storage and consider the new insns to be the insn chain to be - compiled. Our caller (rest_of_compilation) saves the original - DECL_INITIAL and DECL_ARGUMENTS; here we copy them. */ - -/* ??? The nonlocal_label list should be adjusted also. However, since - a function that contains a nested function never gets inlined currently, - the nonlocal_label list will always be empty, so we don't worry about - it for now. */ - -void -save_for_inline_copying (fndecl) - tree fndecl; -{ - rtvec argvec; - rtx new_first_insn, new_last_insn, insn; - int max_labelno, min_labelno, i, len; - int max_reg; - int max_uid; - rtx first_nonparm_insn; - char *new, *new1; - rtx *new_parm_reg_stack_loc; - rtx *new2; - struct emit_status *es - = (struct emit_status *) xmalloc (sizeof (struct emit_status)); - - /* Make and emit a return-label if we have not already done so. - Do this before recording the bounds on label numbers. */ - - if (return_label == 0) - { - return_label = gen_label_rtx (); - emit_label (return_label); - } - - *es = *current_function->emit; - - /* Get some bounds on the labels and registers used. */ - - max_labelno = max_label_num (); - min_labelno = get_first_label_num (); - max_reg = max_reg_num (); - - /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL. - Later we set TREE_READONLY to 0 if the parm is modified inside the fn. - Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values - for the parms, prior to elimination of virtual registers. - These values are needed for substituting parms properly. */ - - parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree)); - - argvec = initialize_for_inline (fndecl, 1); - - if (current_function_uses_const_pool) - { - /* Replace any constant pool references with the actual constant. We - will put the constants back in the copy made below. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') - { - save_constants (&PATTERN (insn)); - if (REG_NOTES (insn)) - save_constants (®_NOTES (insn)); - } - - /* Also scan all decls, and replace any constant pool references with the - actual constant. */ - save_constants_in_decl_trees (DECL_INITIAL (fndecl)); - - /* Clear out the constant pool so that we can recreate it with the - copied constants below. */ - init_const_rtx_hash_table (); - clear_const_double_mem (); - } - - max_uid = get_max_uid (); - - /* We have now allocated all that needs to be allocated permanently - on the rtx obstack. Set our high-water mark, so that we - can free the rest of this when the time comes. */ - - preserve_data (); - - /* Copy the chain insns of this function. - Install the copied chain as the insns of this function, - for continued compilation; - the original chain is recorded as the DECL_SAVED_INSNS - for inlining future calls. */ - - /* If there are insns that copy parms from the stack into pseudo registers, - those insns are not copied. `expand_inline_function' must - emit the correct code to handle such things. */ - - insn = get_insns (); - if (GET_CODE (insn) != NOTE) - abort (); - new_first_insn = rtx_alloc (NOTE); - NOTE_SOURCE_FILE (new_first_insn) = NOTE_SOURCE_FILE (insn); - NOTE_LINE_NUMBER (new_first_insn) = NOTE_LINE_NUMBER (insn); - INSN_UID (new_first_insn) = INSN_UID (insn); - PREV_INSN (new_first_insn) = NULL; - NEXT_INSN (new_first_insn) = NULL; - new_last_insn = new_first_insn; - - /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy. - Make these new rtx's now, and install them in regno_reg_rtx, so they - will be the official pseudo-reg rtx's for the rest of compilation. */ - - reg_map = (rtx *) savealloc (es->regno_pointer_flag_length * sizeof (rtx)); - - len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion); - for (i = max_reg - 1; i > LAST_VIRTUAL_REGISTER; i--) - reg_map[i] = (rtx)obstack_copy (function_maybepermanent_obstack, - regno_reg_rtx[i], len); - - es->x_regno_reg_rtx = reg_map; - - /* Put copies of all the virtual register rtx into the new regno_reg_rtx. */ - init_virtual_regs (es); - - /* Likewise each label rtx must have a unique rtx as its copy. */ - - /* We used to use alloca here, but the size of what it would try to - allocate would occasionally cause it to exceed the stack limit and - cause unpredictable core dumps. Some examples were > 2Mb in size. */ - label_map = (rtx *) xmalloc ((max_labelno) * sizeof (rtx)); - - for (i = min_labelno; i < max_labelno; i++) - label_map[i] = gen_label_rtx (); - - /* Likewise for parm_reg_stack_slot. */ - new_parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx)); - for (i = 0; i < max_parm_reg; i++) - new_parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]); - - parm_reg_stack_loc = new_parm_reg_stack_loc; - - /* Record the mapping of old insns to copied insns. */ - - insn_map = (rtx *) alloca (max_uid * sizeof (rtx)); - bzero ((char *) insn_map, max_uid * sizeof (rtx)); - - /* Get the insn which signals the end of parameter setup code. */ - first_nonparm_insn = get_first_nonparm_insn (); - - /* Copy any entries in regno_reg_rtx or DECL_RTLs that reference MEM - (the former occurs when a variable has its address taken) - since these may be shared and can be changed by virtual - register instantiation. DECL_RTL values for our arguments - have already been copied by initialize_for_inline. */ - for (i = LAST_VIRTUAL_REGISTER + 1; i < max_reg; i++) - if (GET_CODE (regno_reg_rtx[i]) == MEM) - XEXP (regno_reg_rtx[i], 0) - = copy_for_inline (XEXP (regno_reg_rtx[i], 0)); - - /* Copy the parm_reg_stack_loc array, and substitute for all of the rtx - contained in it. */ - new2 = (rtx *) savealloc (max_parm_reg * sizeof (rtx)); - bcopy ((char *) parm_reg_stack_loc, (char *) new2, - max_parm_reg * sizeof (rtx)); - parm_reg_stack_loc = new2; - for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; ++i) - if (parm_reg_stack_loc[i]) - parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]); - - /* Copy the tree of subblocks of the function, and the decls in them. - We will use the copy for compiling this function, then restore the original - subblocks and decls for use when inlining this function. - - Several parts of the compiler modify BLOCK trees. In particular, - instantiate_virtual_regs will instantiate any virtual regs - mentioned in the DECL_RTLs of the decls, and loop - unrolling will replicate any BLOCK trees inside an unrolled loop. - - The modified subblocks or DECL_RTLs would be incorrect for the original rtl - which we will use for inlining. The rtl might even contain pseudoregs - whose space has been freed. */ - - DECL_INITIAL (fndecl) = copy_decl_tree (DECL_INITIAL (fndecl)); - DECL_ARGUMENTS (fndecl) = copy_decl_list (DECL_ARGUMENTS (fndecl)); - - /* Now copy each DECL_RTL which is a MEM, - so it is safe to modify their addresses. */ - copy_decl_rtls (DECL_INITIAL (fndecl)); - - /* The fndecl node acts as its own progenitor, so mark it as such. */ - DECL_ABSTRACT_ORIGIN (fndecl) = fndecl; - - /* Now copy the chain of insns. Do this twice. The first copy the insn - itself and its body. The second time copy of REG_NOTES. This is because - a REG_NOTE may have a forward pointer to another insn. */ - - for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) - { - rtx copy; - orig_asm_operands_vector = 0; - - if (insn == first_nonparm_insn) - in_nonparm_insns = 1; - - switch (GET_CODE (insn)) - { - case NOTE: - /* No need to keep these. */ - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) - continue; - - copy = rtx_alloc (NOTE); - NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn); - if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_END) - NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn); - else - { - NOTE_SOURCE_FILE (insn) = (char *) copy; - NOTE_SOURCE_FILE (copy) = 0; - } - if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG - || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END) - { - int new_region = CODE_LABEL_NUMBER - (label_map[NOTE_BLOCK_NUMBER (copy)]); - - /* we have to duplicate the handlers for the original */ - if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) - duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region, - save_for_inline_eh_labelmap); - - /* We have to forward these both to match the new exception - region. */ - NOTE_BLOCK_NUMBER (copy) = new_region; - - } - RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn); - break; - - case INSN: - case JUMP_INSN: - case CALL_INSN: - copy = rtx_alloc (GET_CODE (insn)); - - if (GET_CODE (insn) == CALL_INSN) - CALL_INSN_FUNCTION_USAGE (copy) - = copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn)); - - PATTERN (copy) = copy_for_inline (PATTERN (insn)); - INSN_CODE (copy) = -1; - LOG_LINKS (copy) = NULL_RTX; - RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn); - break; - - case CODE_LABEL: - copy = label_map[CODE_LABEL_NUMBER (insn)]; - LABEL_NAME (copy) = LABEL_NAME (insn); - break; - - case BARRIER: - copy = rtx_alloc (BARRIER); - break; - - default: - abort (); - } - INSN_UID (copy) = INSN_UID (insn); - insn_map[INSN_UID (insn)] = copy; - NEXT_INSN (new_last_insn) = copy; - PREV_INSN (copy) = new_last_insn; - new_last_insn = copy; - } - - adjust_copied_decl_tree (DECL_INITIAL (fndecl)); - - /* Now copy the REG_NOTES. */ - for (insn = NEXT_INSN (get_insns ()); insn; insn = NEXT_INSN (insn)) - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && insn_map[INSN_UID(insn)]) - REG_NOTES (insn_map[INSN_UID (insn)]) - = copy_for_inline (REG_NOTES (insn)); - - NEXT_INSN (new_last_insn) = NULL; - - /* Make new versions of the register tables. */ - new = (char *) savealloc (es->regno_pointer_flag_length); - memcpy (new, es->regno_pointer_flag, es->regno_pointer_flag_length); - new1 = (char *) savealloc (es->regno_pointer_flag_length); - memcpy (new1, es->regno_pointer_align, es->regno_pointer_flag_length); - es->regno_pointer_flag = new; - es->regno_pointer_align = new1; - - free (label_map); - - current_function->inl_max_label_num = max_label_num (); - current_function->inl_last_parm_insn = current_function->x_last_parm_insn; - current_function->original_arg_vector = argvec; - current_function->original_decl_initial = DECL_INITIAL (fndecl); - /* Use the copy we made for compiling the function now, and - use the original values for inlining. */ - current_function->inl_emit = current_function->emit; - current_function->emit = es; - set_new_first_and_last_insn (new_first_insn, new_last_insn); - DECL_SAVED_INSNS (fndecl) = current_function; -} - /* Copy NODE (as with copy_node). NODE must be a DECL. Set the DECL_ABSTRACT_ORIGIN for the new accordinly. */ @@ -723,81 +333,6 @@ copy_and_set_decl_abstract_origin (node) return copy; } -/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field. - For example, this can copy a list made of TREE_LIST nodes. While copying, - set DECL_ABSTRACT_ORIGIN appropriately. */ - -static tree -copy_decl_list (list) - tree list; -{ - tree head; - register tree prev, next; - - if (list == 0) - return 0; - - head = prev = copy_and_set_decl_abstract_origin (list); - next = TREE_CHAIN (list); - while (next) - { - register tree copy; - - copy = copy_and_set_decl_abstract_origin (next); - TREE_CHAIN (prev) = copy; - prev = copy; - next = TREE_CHAIN (next); - } - return head; -} - -/* Make a copy of the entire tree of blocks BLOCK, and return it. */ - -static tree -copy_decl_tree (block) - tree block; -{ - tree t, vars, subblocks; - - vars = copy_decl_list (BLOCK_VARS (block)); - subblocks = 0; - - /* Process all subblocks. */ - for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t)) - { - tree copy = copy_decl_tree (t); - TREE_CHAIN (copy) = subblocks; - subblocks = copy; - } - - t = copy_node (block); - BLOCK_VARS (t) = vars; - BLOCK_SUBBLOCKS (t) = nreverse (subblocks); - /* If the BLOCK being cloned is already marked as having been instantiated - from something else, then leave that `origin' marking alone. Otherwise, - mark the clone as having originated from the BLOCK we are cloning. */ - if (BLOCK_ABSTRACT_ORIGIN (t) == NULL_TREE) - BLOCK_ABSTRACT_ORIGIN (t) = block; - return t; -} - -/* Copy DECL_RTLs in all decls in the given BLOCK node. */ - -static void -copy_decl_rtls (block) - tree block; -{ - tree t; - - for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t)) - if (DECL_RTL (t) && GET_CODE (DECL_RTL (t)) == MEM) - DECL_RTL (t) = copy_for_inline (DECL_RTL (t)); - - /* Process all subblocks. */ - for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t)) - copy_decl_rtls (t); -} - /* Make the insns and PARM_DECLs of the current function permanent and record other information in DECL_SAVED_INSNS to allow inlining of this function in subsequent calls. @@ -841,7 +376,7 @@ save_for_inline_nocopy (fndecl) emit_label (return_label); } - argvec = initialize_for_inline (fndecl, 0); + argvec = initialize_for_inline (fndecl); /* If there are insns that copy parms from the stack into pseudo registers, those insns are not copied. `expand_inline_function' must @@ -867,33 +402,16 @@ save_for_inline_nocopy (fndecl) in_nonparm_insns = 1; if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') - { - if (current_function_uses_const_pool) - { - /* Replace any constant pool references with the actual constant. - We will put the constant back if we need to write the - function out after all. */ - save_constants (&PATTERN (insn)); - if (REG_NOTES (insn)) - save_constants (®_NOTES (insn)); - } - - /* Record what interesting things happen to our parameters. */ - note_stores (PATTERN (insn), note_modified_parmregs); - } + /* Record what interesting things happen to our parameters. */ + note_stores (PATTERN (insn), note_modified_parmregs); } - /* Also scan all decls, and replace any constant pool references with the - actual constant. */ - save_constants_in_decl_trees (DECL_INITIAL (fndecl)); - /* We have now allocated all that needs to be allocated permanently on the rtx obstack. Set our high-water mark, so that we can free the rest of this when the time comes. */ preserve_data (); - current_function->inl_emit = current_function->emit; current_function->inl_max_label_num = max_label_num (); current_function->inl_last_parm_insn = current_function->x_last_parm_insn; current_function->original_arg_vector = argvec; @@ -901,87 +419,6 @@ save_for_inline_nocopy (fndecl) DECL_SAVED_INSNS (fndecl) = current_function; } -/* Given PX, a pointer into an insn, search for references to the constant - pool. Replace each with a CONST that has the mode of the original - constant, contains the constant, and has RTX_INTEGRATED_P set. - Similarly, constant pool addresses not enclosed in a MEM are replaced - with an ADDRESS and CONST rtx which also gives the constant, its - mode, the mode of the address, and has RTX_INTEGRATED_P set. */ - -static void -save_constants (px) - rtx *px; -{ - rtx x; - int i, j; - - again: - x = *px; - - /* If this is a CONST_DOUBLE, don't try to fix things up in - CONST_DOUBLE_MEM, because this is an infinite recursion. */ - if (GET_CODE (x) == CONST_DOUBLE) - return; - else if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (x,0))) - { - enum machine_mode const_mode = get_pool_mode (XEXP (x, 0)); - rtx new = gen_rtx_CONST (const_mode, get_pool_constant (XEXP (x, 0))); - RTX_INTEGRATED_P (new) = 1; - - /* If the MEM was in a different mode than the constant (perhaps we - were only looking at the low-order part), surround it with a - SUBREG so we can save both modes. */ - - if (GET_MODE (x) != const_mode) - { - new = gen_rtx_SUBREG (GET_MODE (x), new, 0); - RTX_INTEGRATED_P (new) = 1; - } - - *px = new; - save_constants (&XEXP (*px, 0)); - } - else if (GET_CODE (x) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (x)) - { - *px = gen_rtx_ADDRESS (GET_MODE (x), - gen_rtx_CONST (get_pool_mode (x), - get_pool_constant (x))); - save_constants (&XEXP (*px, 0)); - RTX_INTEGRATED_P (*px) = 1; - } - - else - { - const char *fmt = GET_RTX_FORMAT (GET_CODE (x)); - int len = GET_RTX_LENGTH (GET_CODE (x)); - - for (i = len-1; i >= 0; i--) - { - switch (fmt[i]) - { - case 'E': - for (j = 0; j < XVECLEN (x, i); j++) - save_constants (&XVECEXP (x, i, j)); - break; - - case 'e': - if (XEXP (x, i) == 0) - continue; - if (i == 0) - { - /* Hack tail-recursion here. */ - px = &XEXP (x, 0); - goto again; - } - save_constants (&XEXP (x, i)); - break; - } - } - } -} - /* Note whether a parameter is modified or not. */ static void @@ -996,262 +433,6 @@ note_modified_parmregs (reg, x) TREE_READONLY (parmdecl_map[REGNO (reg)]) = 0; } -/* Copy the rtx ORIG recursively, replacing pseudo-regs and labels - according to `reg_map' and `label_map'. The original rtl insns - will be saved for inlining; this is used to make a copy - which is used to finish compiling the inline function itself. - - If we find a "saved" constant pool entry, one which was replaced with - the value of the constant, convert it back to a constant pool entry. - Since the pool wasn't touched, this should simply restore the old - address. - - All other kinds of rtx are copied except those that can never be - changed during compilation. */ - -static rtx -copy_for_inline (orig) - rtx orig; -{ - register rtx x = orig; - register rtx new; - register int i; - register enum rtx_code code; - register const char *format_ptr; - - if (x == 0) - return x; - - code = GET_CODE (x); - - /* These types may be freely shared. */ - - switch (code) - { - case QUEUED: - case CONST_INT: - case PC: - case CC0: - return x; - - case SYMBOL_REF: - if (! SYMBOL_REF_NEED_ADJUST (x)) - return x; - return rethrow_symbol_map (x, save_for_inline_eh_labelmap); - - case CONST_DOUBLE: - /* We have to make a new CONST_DOUBLE to ensure that we account for - it correctly. Using the old CONST_DOUBLE_MEM data is wrong. */ - if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) - { - REAL_VALUE_TYPE d; - - REAL_VALUE_FROM_CONST_DOUBLE (d, x); - return CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x)); - } - else - return immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x), - VOIDmode); - - case CONST: - /* Get constant pool entry for constant in the pool. */ - if (RTX_INTEGRATED_P (x)) - return validize_mem (force_const_mem (GET_MODE (x), - copy_for_inline (XEXP (x, 0)))); - break; - - case SUBREG: - /* Get constant pool entry, but access in different mode. */ - if (RTX_INTEGRATED_P (x)) - { - new = force_const_mem (GET_MODE (SUBREG_REG (x)), - copy_for_inline (XEXP (SUBREG_REG (x), 0))); - - PUT_MODE (new, GET_MODE (x)); - return validize_mem (new); - } - break; - - case ADDRESS: - /* If not special for constant pool error. Else get constant pool - address. */ - if (! RTX_INTEGRATED_P (x)) - abort (); - - new = force_const_mem (GET_MODE (XEXP (x, 0)), - copy_for_inline (XEXP (XEXP (x, 0), 0))); - new = XEXP (new, 0); - -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (new) != GET_MODE (x)) - new = convert_memory_address (GET_MODE (x), new); -#endif - - return new; - - case ASM_OPERANDS: - /* If a single asm insn contains multiple output operands - then it contains multiple ASM_OPERANDS rtx's that share operand 3. - We must make sure that the copied insn continues to share it. */ - if (orig_asm_operands_vector == XVEC (orig, 3)) - { - x = rtx_alloc (ASM_OPERANDS); - x->volatil = orig->volatil; - XSTR (x, 0) = XSTR (orig, 0); - XSTR (x, 1) = XSTR (orig, 1); - XINT (x, 2) = XINT (orig, 2); - XVEC (x, 3) = copy_asm_operands_vector; - XVEC (x, 4) = copy_asm_constraints_vector; - XSTR (x, 5) = XSTR (orig, 5); - XINT (x, 6) = XINT (orig, 6); - return x; - } - break; - - case MEM: - /* A MEM is usually allowed to be shared if its address is constant - or is a constant plus one of the special registers. - - We do not allow sharing of addresses that are either a special - register or the sum of a constant and a special register because - it is possible for unshare_all_rtl to copy the address, into memory - that won't be saved. Although the MEM can safely be shared, and - won't be copied there, the address itself cannot be shared, and may - need to be copied. - - There are also two exceptions with constants: The first is if the - constant is a LABEL_REF or the sum of the LABEL_REF - and an integer. This case can happen if we have an inline - function that supplies a constant operand to the call of another - inline function that uses it in a switch statement. In this case, - we will be replacing the LABEL_REF, so we have to replace this MEM - as well. - - The second case is if we have a (const (plus (address ..) ...)). - In that case we need to put back the address of the constant pool - entry. */ - - if (CONSTANT_ADDRESS_P (XEXP (x, 0)) - && GET_CODE (XEXP (x, 0)) != LABEL_REF - && ! (GET_CODE (XEXP (x, 0)) == CONST - && (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS - && ((GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) - == LABEL_REF) - || (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) - == ADDRESS))))) - return x; - break; - - case LABEL_REF: - /* If this is a non-local label, just make a new LABEL_REF. - Otherwise, use the new label as well. */ - x = gen_rtx_LABEL_REF (GET_MODE (orig), - LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0) - : label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]); - LABEL_REF_NONLOCAL_P (x) = LABEL_REF_NONLOCAL_P (orig); - LABEL_OUTSIDE_LOOP_P (x) = LABEL_OUTSIDE_LOOP_P (orig); - return x; - - case REG: - if (REGNO (x) > LAST_VIRTUAL_REGISTER) - return reg_map [REGNO (x)]; - else - return x; - - case SET: - /* If a parm that gets modified lives in a pseudo-reg, - clear its TREE_READONLY to prevent certain optimizations. */ - { - rtx dest = SET_DEST (x); - - while (GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == ZERO_EXTRACT - || GET_CODE (dest) == SUBREG) - dest = XEXP (dest, 0); - - if (GET_CODE (dest) == REG - && REGNO (dest) < max_parm_reg - && REGNO (dest) >= FIRST_PSEUDO_REGISTER - && parmdecl_map[REGNO (dest)] != 0 - /* The insn to load an arg pseudo from a stack slot - does not count as modifying it. */ - && in_nonparm_insns) - TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0; - } - break; - -#if 0 /* This is a good idea, but here is the wrong place for it. */ - /* Arrange that CONST_INTs always appear as the second operand - if they appear, and that `frame_pointer_rtx' or `arg_pointer_rtx' - always appear as the first. */ - case PLUS: - if (GET_CODE (XEXP (x, 0)) == CONST_INT - || (XEXP (x, 1) == frame_pointer_rtx - || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM - && XEXP (x, 1) == arg_pointer_rtx))) - { - rtx t = XEXP (x, 0); - XEXP (x, 0) = XEXP (x, 1); - XEXP (x, 1) = t; - } - break; -#endif - default: - break; - } - - /* Replace this rtx with a copy of itself. */ - - x = rtx_alloc (code); - bcopy ((char *) orig, (char *) x, - (sizeof (*x) - sizeof (x->fld) - + sizeof (x->fld[0]) * GET_RTX_LENGTH (code))); - - /* Now scan the subexpressions recursively. - We can store any replaced subexpressions directly into X - since we know X is not shared! Any vectors in X - must be copied if X was copied. */ - - format_ptr = GET_RTX_FORMAT (code); - - for (i = 0; i < GET_RTX_LENGTH (code); i++) - { - switch (*format_ptr++) - { - case 'e': - XEXP (x, i) = copy_for_inline (XEXP (x, i)); - break; - - case 'u': - /* Change any references to old-insns to point to the - corresponding copied insns. */ - XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))]; - break; - - case 'E': - if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0) - { - register int j; - - XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), XVEC (x, i)->elem); - for (j = 0; j < XVECLEN (x, i); j++) - XVECEXP (x, i, j) - = copy_for_inline (XVECEXP (x, i, j)); - } - break; - } - } - - if (code == ASM_OPERANDS && orig_asm_operands_vector == 0) - { - orig_asm_operands_vector = XVEC (orig, 3); - copy_asm_operands_vector = XVEC (x, 3); - copy_asm_constraints_vector = XVEC (x, 4); - } - - return x; -} - /* Unfortunately, we need a global copy of const_equiv map for communication with a function called from note_stores. Be *very* careful that this is used properly in the presence of recursion. */ @@ -1326,9 +507,10 @@ expand_inline_function (fndecl, parms, target, ignore, type, tree type; rtx structure_value_addr; { + struct function *inlining_previous; struct function *inl_f = DECL_SAVED_INSNS (fndecl); tree formal, actual, block; - rtx parm_insns = inl_f->inl_emit->x_first_insn; + rtx parm_insns = inl_f->emit->x_first_insn; rtx insns = (inl_f->inl_last_parm_insn ? NEXT_INSN (inl_f->inl_last_parm_insn) : parm_insns); @@ -1337,7 +519,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, rtx insn; int max_regno; register int i; - int min_labelno = inl_f->inl_emit->x_first_label_num; + int min_labelno = inl_f->emit->x_first_label_num; int max_labelno = inl_f->inl_max_label_num; int nargs; rtx local_return_label = 0; @@ -1357,7 +539,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, rtx *real_label_map = 0; /* Allow for equivalences of the pseudos we make for virtual fp and ap. */ - max_regno = inl_f->inl_emit->x_reg_rtx_no + 3; + max_regno = inl_f->emit->x_reg_rtx_no + 3; if (max_regno < FIRST_PSEUDO_REGISTER) abort (); @@ -1500,7 +682,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, = (rtx *) xmalloc ((max_labelno) * sizeof (rtx)); map->label_map = real_label_map; - inl_max_uid = (inl_f->inl_emit->x_cur_insn_uid + 1); + inl_max_uid = (inl_f->emit->x_cur_insn_uid + 1); map->insn_map = (rtx *) alloca (inl_max_uid * sizeof (rtx)); bzero ((char *) map->insn_map, inl_max_uid * sizeof (rtx)); map->min_insnno = 0; @@ -1536,8 +718,8 @@ expand_inline_function (fndecl, parms, target, ignore, type, if (map->insns_at_start == 0) map->insns_at_start = emit_note (NULL_PTR, NOTE_INSN_DELETED); - map->regno_pointer_flag = inl_f->inl_emit->regno_pointer_flag; - map->regno_pointer_align = inl_f->inl_emit->regno_pointer_align; + map->regno_pointer_flag = inl_f->emit->regno_pointer_flag; + map->regno_pointer_align = inl_f->emit->regno_pointer_align; /* Update the outgoing argument size to allow for those in the inlined function. */ @@ -1625,6 +807,12 @@ expand_inline_function (fndecl, parms, target, ignore, type, abort (); } + /* Tell copy_rtx_and_substitute to handle constant pool SYMBOL_REFs + specially. This function can be called recursively, so we need to + save the previous value. */ + inlining_previous = inlining; + inlining = inl_f; + /* Now do the parameters that will be placed in memory. */ for (formal = DECL_ARGUMENTS (fndecl), i = 0; @@ -2132,6 +1320,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, free (real_label_map); if (map) VARRAY_FREE (map->const_equiv_varray); + inlining = inlining_previous; return target; } @@ -2236,23 +1425,6 @@ integrate_decl_tree (let, level, map) } } } - -/* Given a BLOCK node LET, search for all DECL_RTL fields, and pass them - through save_constants. */ - -static void -save_constants_in_decl_trees (let) - tree let; -{ - tree t; - - for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) - if (DECL_RTL (t) != 0) - save_constants (&DECL_RTL (t)); - - for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) - save_constants_in_decl_trees (t); -} /* Create a new copy of an rtx. Recursively copies the operands of the rtx, @@ -2506,8 +1678,38 @@ copy_rtx_and_substitute (orig, map) remapped label. Otherwise, symbols are returned unchanged. */ if (CONSTANT_POOL_ADDRESS_P (orig)) { - rtx constant = get_pool_constant (orig); - if (GET_CODE (constant) == LABEL_REF) + struct function *f = inlining ? inlining : current_function; + rtx constant = get_pool_constant_for_function (f, orig); + enum machine_mode const_mode = get_pool_mode_for_function (f, orig); + if (inlining) + { + rtx temp = force_const_mem (const_mode, + copy_rtx_and_substitute (constant, map)); +#if 0 + /* Legitimizing the address here is incorrect. + + Since we had a SYMBOL_REF before, we can assume it is valid + to have one in this position in the insn. + + Also, change_address may create new registers. These + registers will not have valid reg_map entries. This can + cause try_constants() to fail because assumes that all + registers in the rtx have valid reg_map entries, and it may + end up replacing one of these new registers with junk. */ + + if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) + temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0)); +#endif + + temp = XEXP (temp, 0); + +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (temp) != GET_MODE (orig)) + temp = convert_memory_address (GET_MODE (orig), temp); +#endif + return temp; + } + else if (GET_CODE (constant) == LABEL_REF) return XEXP (force_const_mem (GET_MODE (orig), copy_rtx_and_substitute (constant, map)), @@ -2542,62 +1744,8 @@ copy_rtx_and_substitute (orig, map) /* Make new constant pool entry for a constant that was in the pool of the inline function. */ if (RTX_INTEGRATED_P (orig)) - { - /* If this was an address of a constant pool entry that itself - had to be placed in the constant pool, it might not be a - valid address. So the recursive call below might turn it - into a register. In that case, it isn't a constant any - more, so return it. This has the potential of changing a - MEM into a REG, but we'll assume that it safe. */ - temp = copy_rtx_and_substitute (XEXP (orig, 0), map); - if (! CONSTANT_P (temp)) - return temp; - return validize_mem (force_const_mem (GET_MODE (orig), temp)); - } - break; - - case ADDRESS: - /* If from constant pool address, make new constant pool entry and - return its address. */ - if (! RTX_INTEGRATED_P (orig)) abort (); - - temp - = force_const_mem (GET_MODE (XEXP (orig, 0)), - copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), - map)); - -#if 0 - /* Legitimizing the address here is incorrect. - - The only ADDRESS rtx's that can reach here are ones created by - save_constants. Hence the operand of the ADDRESS is always valid - in this position of the instruction, since the original rtx without - the ADDRESS was valid. - - The reason we don't legitimize the address here is that on the - Sparc, the caller may have a (high ...) surrounding this ADDRESS. - This code forces the operand of the address to a register, which - fails because we can not take the HIGH part of a register. - - Also, change_address may create new registers. These registers - will not have valid reg_map entries. This can cause try_constants() - to fail because assumes that all registers in the rtx have valid - reg_map entries, and it may end up replacing one of these new - registers with junk. */ - - if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) - temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0)); -#endif - - temp = XEXP (temp, 0); - -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (temp) != GET_MODE (orig)) - temp = convert_memory_address (GET_MODE (orig), temp); -#endif - - return temp; + break; case ASM_OPERANDS: /* If a single asm insn contains multiple output operands @@ -2666,6 +1814,23 @@ copy_rtx_and_substitute (orig, map) break; case MEM: + if (inlining + && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (orig, 0))) + { + enum machine_mode const_mode = get_pool_mode_for_function (inlining, XEXP (orig, 0)); + rtx constant = get_pool_constant_for_function (inlining, XEXP (orig, 0)); + constant = copy_rtx_and_substitute (constant, map); + /* If this was an address of a constant pool entry that itself + had to be placed in the constant pool, it might not be a + valid address. So the recursive call might have turned it + into a register. In that case, it isn't a constant any + more, so return it. This has the potential of changing a + MEM into a REG, but we'll assume that it safe. */ + if (! CONSTANT_P (constant)) + return constant; + return validize_mem (force_const_mem (const_mode, constant)); + } copy = rtx_alloc (MEM); PUT_MODE (copy, mode); XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map); @@ -3122,88 +2287,6 @@ mark_stores (dest, x) } } -/* If any CONST expressions with RTX_INTEGRATED_P are present in the rtx - pointed to by PX, they represent constants in the constant pool. - Replace these with a new memory reference obtained from force_const_mem. - Similarly, ADDRESS expressions with RTX_INTEGRATED_P represent the - address of a constant pool entry. Replace them with the address of - a new constant pool entry obtained from force_const_mem. */ - -static void -restore_constants (px) - rtx *px; -{ - rtx x = *px; - int i, j; - const char *fmt; - - if (x == 0) - return; - - if (GET_CODE (x) == CONST_DOUBLE) - { - /* We have to make a new CONST_DOUBLE to ensure that we account for - it correctly. Using the old CONST_DOUBLE_MEM data is wrong. */ - if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) - { - REAL_VALUE_TYPE d; - - REAL_VALUE_FROM_CONST_DOUBLE (d, x); - *px = CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x)); - } - else - *px = immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x), - VOIDmode); - } - - else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == CONST) - { - restore_constants (&XEXP (x, 0)); - *px = validize_mem (force_const_mem (GET_MODE (x), XEXP (x, 0))); - } - else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == SUBREG) - { - /* This must be (subreg/i:M1 (const/i:M2 ...) 0). */ - rtx new = XEXP (SUBREG_REG (x), 0); - - restore_constants (&new); - new = force_const_mem (GET_MODE (SUBREG_REG (x)), new); - PUT_MODE (new, GET_MODE (x)); - *px = validize_mem (new); - } - else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == ADDRESS) - { - rtx new = XEXP (force_const_mem (GET_MODE (XEXP (x, 0)), - XEXP (XEXP (x, 0), 0)), - 0); - -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (new) != GET_MODE (x)) - new = convert_memory_address (GET_MODE (x), new); -#endif - - *px = new; - } - else - { - fmt = GET_RTX_FORMAT (GET_CODE (x)); - for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) - { - switch (*fmt++) - { - case 'E': - for (j = 0; j < XVECLEN (x, i); j++) - restore_constants (&XVECEXP (x, i, j)); - break; - - case 'e': - restore_constants (&XEXP (x, i)); - break; - } - } - } -} - /* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so that it points to the node itself, thus indicating that the node is its @@ -3331,26 +2414,16 @@ void output_inline_function (fndecl) tree fndecl; { + struct function *curf = current_function; struct function *f = DECL_SAVED_INSNS (fndecl); - rtx last; - /* Things we allocate from here on are part of this function, not - permanent. */ - temporary_allocation (); current_function = f; current_function_decl = fndecl; clear_emit_caches (); - /* Find last insn and rebuild the constant pool. */ - init_const_rtx_hash_table (); - for (last = get_insns (); NEXT_INSN (last); last = NEXT_INSN (last)) - { - if (GET_RTX_CLASS (GET_CODE (last)) == 'i') - { - restore_constants (&PATTERN (last)); - restore_constants (®_NOTES (last)); - } - } + /* Things we allocate from here on are part of this function, not + permanent. */ + temporary_allocation (); set_new_last_label_num (f->inl_max_label_num); @@ -3375,6 +2448,6 @@ output_inline_function (fndecl) /* Compile this function all the way down to assembly code. */ rest_of_compilation (fndecl); - current_function = 0; - current_function_decl = 0; + current_function = curf; + current_function_decl = curf ? curf->decl : 0; } diff --git a/gcc/output.h b/gcc/output.h index b0a731e59bb..97794d1f781 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -309,9 +309,6 @@ extern void defer_addressed_constants PROTO((void)); and output now all those that have been deferred. */ extern void output_deferred_addressed_constants PROTO((void)); -/* Initialize constant pool hashing for next function. */ -extern void init_const_rtx_hash_table PROTO((void)); - /* Return the size of the constant pool. */ extern int get_pool_size PROTO((void)); diff --git a/gcc/rtl.h b/gcc/rtl.h index 9ac8680da69..acb9f756bb8 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -21,6 +21,8 @@ Boston, MA 02111-1307, USA. */ #ifndef _RTL_H #define _RTL_H +struct function; + #include "machmode.h" #undef FFS /* Some systems predefine this symbol; don't let it interfere. */ @@ -1001,6 +1003,8 @@ extern rtx force_const_mem PROTO((enum machine_mode, rtx)); extern rtx force_reg PROTO((enum machine_mode, rtx)); extern rtx get_pool_constant PROTO((rtx)); extern enum machine_mode get_pool_mode PROTO((rtx)); +extern rtx get_pool_constant_for_function PROTO((struct function *, rtx)); +extern enum machine_mode get_pool_mode_for_function PROTO((struct function *, rtx)); extern int get_pool_offset PROTO((rtx)); extern rtx simplify_subtraction PROTO((rtx)); extern rtx assign_stack_local PROTO((enum machine_mode, diff --git a/gcc/toplev.c b/gcc/toplev.c index ab1cf9ba0c5..3534da7f6e9 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3648,30 +3648,16 @@ rest_of_compilation (decl) compile it by itself, defer decision till end of compilation. finish_compilation will call rest_of_compilation again for those functions that need to be output. Also defer those - functions that we are supposed to defer. We cannot defer - functions containing nested functions since the nested function - data is in our non-saved obstack. We cannot defer nested - functions for the same reason. */ - - /* If this is a nested inline, remove ADDRESSOF now so we can - finish compiling ourselves. Otherwise, wait until EOF. - We have to do this because the purge_addressof transformation - changes the DECL_RTL for many variables, which confuses integrate. - Also, save_for_inline_copying can be very expensive. */ + functions that we are supposed to defer. */ + if (inlinable) - { - if (decl_function_context (decl)) - purge_addressof (insns); - else - DECL_DEFER_OUTPUT (decl) = 1; - } + DECL_DEFER_OUTPUT (decl) = 1; - if (! current_function_contains_functions - && (DECL_DEFER_OUTPUT (decl) - || (DECL_INLINE (decl) - && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) - && ! flag_keep_inline_functions) - || DECL_EXTERNAL (decl))))) + if (DECL_DEFER_OUTPUT (decl) + || (DECL_INLINE (decl) + && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) + && ! flag_keep_inline_functions) + || DECL_EXTERNAL (decl)))) { DECL_DEFER_OUTPUT (decl) = 1; @@ -3720,40 +3706,6 @@ rest_of_compilation (decl) goto exit_rest_of_compilation; } - /* If we have to compile the function now, save its rtl and subdecls - so that its compilation will not affect what others get. */ - if (inlinable || DECL_DEFER_OUTPUT (decl)) - { -#ifdef DWARF_DEBUGGING_INFO - /* Generate the DWARF info for the "abstract" instance of - a function which we will generate an out-of-line instance - of almost immediately (and which we may also later generate - various inlined instances of). */ - if (write_symbols == DWARF_DEBUG) - { - set_decl_abstract_flags (decl, 1); - TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0)); - set_decl_abstract_flags (decl, 0); - } -#endif -#ifdef DWARF2_DEBUGGING_INFO - /* Generate the DWARF2 info for the "abstract" instance of - a function which we will generate an out-of-line instance - of almost immediately (and which we may also later generate - various inlined instances of). */ - if (write_symbols == DWARF2_DEBUG) - { - set_decl_abstract_flags (decl, 1); - TIMEVAR (symout_time, dwarf2out_decl (decl)); - set_decl_abstract_flags (decl, 0); - } -#endif - saved_block_tree = DECL_INITIAL (decl); - saved_arguments = DECL_ARGUMENTS (decl); - TIMEVAR (integration_time, save_for_inline_copying (decl)); - DECL_SAVED_INSNS (decl)->inlinable = inlinable; - } - /* If specified extern inline but we aren't inlining it, we are done. This goes for anything that gets here with DECL_EXTERNAL set, not just things with DECL_INLINE. */ diff --git a/gcc/tree.c b/gcc/tree.c index c9abd06ffda..e280190fcd5 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -64,21 +64,6 @@ struct obstack *function_maybepermanent_obstack; struct obstack maybepermanent_obstack; -/* This is a list of function_maybepermanent_obstacks for top-level inline - functions that are compiled in the middle of compiling other functions. */ - -struct simple_obstack_stack *toplev_inline_obstacks; - -/* Former elements of toplev_inline_obstacks that have been recycled. */ - -struct simple_obstack_stack *extra_inline_obstacks; - -/* This is a list of function_maybepermanent_obstacks for inline functions - nested in the current function that were compiled in the middle of - compiling other functions. */ - -struct simple_obstack_stack *inline_obstacks; - /* The contents of the current function definition are allocated in this obstack, and all are freed at the end of the function. For top-level functions, this is temporary_obstack. @@ -331,9 +316,8 @@ gcc_obstack_init (obstack) compile; if it isn't current_function_decl, we have to play some games. */ void -save_tree_status (p, context) +save_tree_status (p) struct function *p; - tree context; { p->all_types_permanent = all_types_permanent; p->momentary_stack = momentary_stack; @@ -347,50 +331,10 @@ save_tree_status (p, context) p->expression_obstack = expression_obstack; p->saveable_obstack = saveable_obstack; p->rtl_obstack = rtl_obstack; - p->inline_obstacks = inline_obstacks; - - if (current_function_decl && context == current_function_decl) - /* Objects that need to be saved in this function can be in the nonsaved - obstack of the enclosing function since they can't possibly be needed - once it has returned. */ - function_maybepermanent_obstack = function_obstack; - else - { - /* We're compiling a function which isn't nested in the current - function. We need to create a new maybepermanent_obstack for this - function, since it can't go onto any of the existing obstacks. */ - struct simple_obstack_stack **head; - struct simple_obstack_stack *current; - - if (context == NULL_TREE) - head = &toplev_inline_obstacks; - else - { - struct function *f = find_function_data (context); - head = &f->inline_obstacks; - } - - if (context == NULL_TREE && extra_inline_obstacks) - { - current = extra_inline_obstacks; - extra_inline_obstacks = current->next; - } - else - { - current = ((struct simple_obstack_stack *) - xmalloc (sizeof (struct simple_obstack_stack))); - - current->obstack - = (struct obstack *) xmalloc (sizeof (struct obstack)); - gcc_obstack_init (current->obstack); - } - - function_maybepermanent_obstack = current->obstack; - - current->next = *head; - *head = current; - } + function_maybepermanent_obstack + = (struct obstack *) xmalloc (sizeof (struct obstack)); + gcc_obstack_init (function_maybepermanent_obstack); maybepermanent_firstobj = (char *) obstack_finish (function_maybepermanent_obstack); @@ -410,9 +354,8 @@ save_tree_status (p, context) This is used after a nested function. */ void -restore_tree_status (p, context) +restore_tree_status (p) struct function *p; - tree context; { all_types_permanent = p->all_types_permanent; momentary_stack = p->momentary_stack; @@ -420,41 +363,16 @@ restore_tree_status (p, context) obstack_free (&momentary_obstack, momentary_function_firstobj); /* Free saveable storage used by the function just compiled and not - saved. - - CAUTION: This is in function_obstack of the containing function. - So we must be sure that we never allocate from that obstack during - the compilation of a nested function if we expect it to survive - past the nested function's end. */ + saved. */ obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj); - /* If we were compiling a toplevel function, we can free this space now. */ - if (context == NULL_TREE) - { - obstack_free (&temporary_obstack, temporary_firstobj); - obstack_free (&momentary_obstack, momentary_function_firstobj); - } - - /* If we were compiling a toplevel function that we don't actually want - to save anything from, return the obstack to the pool. */ - if (context == NULL_TREE - && obstack_empty_p (function_maybepermanent_obstack)) - { - struct simple_obstack_stack *current, **p = &toplev_inline_obstacks; - - if ((*p) != NULL) - { - while ((*p)->obstack != function_maybepermanent_obstack) - p = &((*p)->next); - current = *p; - *p = current->next; - - current->next = extra_inline_obstacks; - extra_inline_obstacks = current; - } - } + obstack_free (&temporary_obstack, temporary_firstobj); + obstack_free (&momentary_obstack, momentary_function_firstobj); obstack_free (function_obstack, 0); + + if (obstack_empty_p (function_maybepermanent_obstack)) + free (function_maybepermanent_obstack); free (function_obstack); temporary_firstobj = p->temporary_firstobj; @@ -467,7 +385,6 @@ restore_tree_status (p, context) expression_obstack = p->expression_obstack; saveable_obstack = p->saveable_obstack; rtl_obstack = p->rtl_obstack; - inline_obstacks = p->inline_obstacks; } /* Start allocating on the temporary (per function) obstack. @@ -484,7 +401,6 @@ temporary_allocation () expression_obstack = function_obstack; rtl_obstack = saveable_obstack = function_maybepermanent_obstack; momentary_stack = 0; - inline_obstacks = 0; } /* Start allocating on the permanent obstack but don't @@ -612,17 +528,6 @@ permanent_allocation (function_end) obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj); obstack_free (&temp_decl_obstack, temp_decl_firstobj); - /* Free up the maybepermanent_obstacks for any of our nested functions - which were compiled at a lower level. */ - while (inline_obstacks) - { - struct simple_obstack_stack *current = inline_obstacks; - inline_obstacks = current->next; - obstack_free (current->obstack, 0); - free (current->obstack); - free (current); - } - current_obstack = &permanent_obstack; expression_obstack = &permanent_obstack; rtl_obstack = saveable_obstack = &permanent_obstack; @@ -4751,32 +4656,6 @@ decl_type_context (decl) return NULL_TREE; } -/* Print debugging information about the size of the - toplev_inline_obstacks. */ - -void -print_inline_obstack_statistics () -{ - struct simple_obstack_stack *current = toplev_inline_obstacks; - int n_obstacks = 0; - int n_alloc = 0; - int n_chunks = 0; - - for (; current; current = current->next, ++n_obstacks) - { - struct obstack *o = current->obstack; - struct _obstack_chunk *chunk = o->chunk; - - n_alloc += o->next_free - chunk->contents; - chunk = chunk->prev; - ++n_chunks; - for (; chunk; chunk = chunk->prev, ++n_chunks) - n_alloc += chunk->limit - &chunk->contents[0]; - } - fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n", - n_obstacks, n_alloc, n_chunks); -} - /* Print debugging information about the obstack O, named STR. */ void @@ -4835,7 +4714,6 @@ dump_tree_statistics () print_obstack_statistics ("temporary_obstack", &temporary_obstack); print_obstack_statistics ("momentary_obstack", &momentary_obstack); print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack); - print_inline_obstack_statistics (); print_lang_statistics (); } diff --git a/gcc/varasm.c b/gcc/varasm.c index 0be810aa2a9..e7df584a147 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -85,6 +85,48 @@ extern struct obstack *rtl_obstack; extern struct obstack permanent_obstack; #define obstack_chunk_alloc xmalloc +struct addr_const; +struct constant_descriptor; +struct rtx_const; +struct pool_constant; + +#define MAX_RTX_HASH_TABLE 61 + +struct varasm_status +{ + /* Hash facility for making memory-constants + from constant rtl-expressions. It is used on RISC machines + where immediate integer arguments and constant addresses are restricted + so that such constants must be stored in memory. + + This pool of constants is reinitialized for each function + so each function gets its own constants-pool that comes right before + it. */ + struct constant_descriptor **x_const_rtx_hash_table; + struct pool_sym **x_const_rtx_sym_hash_table; + + /* Pointers to first and last constant in pool. */ + struct pool_constant *x_first_pool, *x_last_pool; + + /* Current offset in constant pool (does not include any machine-specific + header. */ + int x_pool_offset; + + /* Chain of all CONST_DOUBLE rtx's constructed for the current function. + They are chained through the CONST_DOUBLE_CHAIN. + A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain. + In that case, CONST_DOUBLE_MEM is either a MEM, + or const0_rtx if no MEM has been made for this CONST_DOUBLE yet. */ + rtx x_const_double_chain; +}; + +#define const_rtx_hash_table (current_function->varasm->x_const_rtx_hash_table) +#define const_rtx_sym_hash_table (current_function->varasm->x_const_rtx_sym_hash_table) +#define first_pool (current_function->varasm->x_first_pool) +#define last_pool (current_function->varasm->x_last_pool) +#define pool_offset (current_function->varasm->x_pool_offset) +#define const_double_chain (current_function->varasm->x_const_double_chain) + /* Number for making the label on the next constant that is stored in memory. */ @@ -111,11 +153,6 @@ tree last_assemble_variable_decl; static int function_defined; -struct addr_const; -struct constant_descriptor; -struct rtx_const; -struct pool_constant; - static const char *strip_reg_name PROTO((const char *)); static int contains_pointers_p PROTO((tree)); static void decode_addr_const PROTO((tree, struct addr_const *)); @@ -134,7 +171,7 @@ static int compare_constant_rtx PROTO((enum machine_mode, rtx, struct constant_descriptor *)); static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode, rtx)); -static struct pool_constant *find_pool_constant PROTO((rtx)); +static struct pool_constant *find_pool_constant PROTO((struct function *, rtx)); static void mark_constant_pool PROTO((void)); static void mark_constants PROTO((rtx)); static int output_addressed_constants PROTO((tree)); @@ -1960,17 +1997,6 @@ assemble_real (d, mode) /* Here we combine duplicate floating constants to make CONST_DOUBLE rtx's, and force those out to memory when necessary. */ -/* Chain of all CONST_DOUBLE rtx's constructed for the current function. - They are chained through the CONST_DOUBLE_CHAIN. - A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain. - In that case, CONST_DOUBLE_MEM is either a MEM, - or const0_rtx if no MEM has been made for this CONST_DOUBLE yet. - - (CONST_DOUBLE_MEM is used only for top-level functions. - See force_const_mem for explanation.) */ - -static rtx const_double_chain; - /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair of ints. For an integer, I0 is the low-order word and I1 is the high-order word. For a real number, I0 is the word with the low address @@ -2045,11 +2071,11 @@ immed_double_const (i0, i1, mode) /* Search the chain for an existing CONST_DOUBLE with the right value. If one is found, return it. */ - - for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r)) - if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1 - && GET_MODE (r) == mode) - return r; + if (current_function != 0) + for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r)) + if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1 + && GET_MODE (r) == mode) + return r; /* No; make a new one and add it to the chain. @@ -2064,9 +2090,8 @@ immed_double_const (i0, i1, mode) r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1); pop_obstacks (); - /* Don't touch const_double_chain in nested function; see force_const_mem. - Also, don't touch it if not inside any function. */ - if (outer_function_chain == 0 && current_function_decl != 0) + /* Don't touch const_double_chain if not inside any function. */ + if (current_function_decl != 0) { CONST_DOUBLE_CHAIN (r) = const_double_chain; const_double_chain = r; @@ -2118,11 +2143,11 @@ immed_real_const_1 (d, mode) /* Search the chain for an existing CONST_DOUBLE with the right value. If one is found, return it. */ - - for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r)) - if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u) - && GET_MODE (r) == mode) - return r; + if (current_function != 0) + for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r)) + if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u) + && GET_MODE (r) == mode) + return r; /* No; make a new one and add it to the chain. @@ -2131,17 +2156,15 @@ immed_real_const_1 (d, mode) we will be leaving this constant on the chain, so we cannot tolerate freed memory. So switch to saveable_obstack for this allocation and then switch back if we were in current_obstack. */ - push_obstacks_nochange (); rtl_in_saveable_obstack (); r = rtx_alloc (CONST_DOUBLE); + pop_obstacks (); PUT_MODE (r, mode); bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u); - pop_obstacks (); - /* Don't touch const_double_chain in nested function; see force_const_mem. - Also, don't touch it if not inside any function. */ - if (outer_function_chain == 0 && current_function_decl != 0) + /* Don't touch const_double_chain if not inside any function. */ + if (current_function_decl != 0) { CONST_DOUBLE_CHAIN (r) = const_double_chain; const_double_chain = r; @@ -2175,11 +2198,6 @@ clear_const_double_mem () { register rtx r, next; - /* Don't touch CONST_DOUBLE_MEM for nested functions. - See force_const_mem for explanation. */ - if (outer_function_chain != 0) - return; - for (r = const_double_chain; r; r = next) { next = CONST_DOUBLE_CHAIN (r); @@ -3110,20 +3128,6 @@ output_constant_def_contents (exp, reloc, labelno) } -/* Similar hash facility for making memory-constants - from constant rtl-expressions. It is used on RISC machines - where immediate integer arguments and constant addresses are restricted - so that such constants must be stored in memory. - - This pool of constants is reinitialized for each function - so each function gets its own constants-pool that comes right before it. - - All structures allocated here are discarded when functions are saved for - inlining, so they do not need to be allocated permanently. */ - -#define MAX_RTX_HASH_TABLE 61 -static struct constant_descriptor **const_rtx_hash_table; - /* Structure to represent sufficient information about a constant so that it can be output when the constant pool is output, so that function integration can be done, and to simplify handling on machines that reference @@ -3141,15 +3145,6 @@ struct pool_constant int mark; }; -/* Pointers to first and last constant in pool. */ - -static struct pool_constant *first_pool, *last_pool; - -/* Current offset in constant pool (does not include any machine-specific - header. */ - -static int pool_offset; - /* Structure used to maintain hash table mapping symbols used to their corresponding constants. */ @@ -3160,63 +3155,35 @@ struct pool_sym struct pool_sym *next; }; -static struct pool_sym **const_rtx_sym_hash_table; - /* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true. The argument is XSTR (... , 0) */ #define SYMHASH(LABEL) \ ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE) -/* Initialize constant pool hashing for next function. */ +/* Initialize constant pool hashing for a new function. */ void -init_const_rtx_hash_table () +init_varasm_status (f) + struct function *f; { - const_rtx_hash_table + struct varasm_status *p; + p = (struct varasm_status *) xmalloc (sizeof (struct varasm_status)); + f->varasm = p; + p->x_const_rtx_hash_table = ((struct constant_descriptor **) - oballoc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *))); - const_rtx_sym_hash_table + xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *))); + p->x_const_rtx_sym_hash_table = ((struct pool_sym **) - oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *))); - bzero ((char *) const_rtx_hash_table, + xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *))); + bzero ((char *) p->x_const_rtx_hash_table, MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)); - bzero ((char *) const_rtx_sym_hash_table, + bzero ((char *) p->x_const_rtx_sym_hash_table, MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)); - first_pool = last_pool = 0; - pool_offset = 0; -} - -/* Save and restore status for a nested function. */ - -void -save_varasm_status (p, context) - struct function *p; - tree context; -{ - p->const_rtx_hash_table = const_rtx_hash_table; - p->const_rtx_sym_hash_table = const_rtx_sym_hash_table; - p->first_pool = first_pool; - p->last_pool = last_pool; - p->pool_offset = pool_offset; - p->const_double_chain = const_double_chain; - - /* If we are pushing to toplevel, we can't reuse const_double_chain. */ - if (context == NULL_TREE) - const_double_chain = 0; -} - -void -restore_varasm_status (p) - struct function *p; -{ - const_rtx_hash_table = p->const_rtx_hash_table; - const_rtx_sym_hash_table = p->const_rtx_sym_hash_table; - first_pool = p->first_pool; - last_pool = p->last_pool; - pool_offset = p->pool_offset; - const_double_chain = p->const_double_chain; + p->x_first_pool = p->x_last_pool = 0; + p->x_pool_offset = 0; + p->x_const_double_chain = 0; } enum kind { RTX_DOUBLE, RTX_INT }; @@ -3439,15 +3406,10 @@ force_const_mem (mode, x) modes in an alternating fashion, we will allocate a lot of different memory locations, but this should be extremely rare. */ - /* Don't use CONST_DOUBLE_MEM in a nested function. - Nested functions have their own constant pools, - so they can't share the same values in CONST_DOUBLE_MEM - with the containing function. */ - if (outer_function_chain == 0) - if (GET_CODE (x) == CONST_DOUBLE - && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM - && GET_MODE (CONST_DOUBLE_MEM (x)) == mode) - return CONST_DOUBLE_MEM (x); + if (GET_CODE (x) == CONST_DOUBLE + && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM + && GET_MODE (CONST_DOUBLE_MEM (x)) == mode) + return CONST_DOUBLE_MEM (x); /* Compute hash code of X. Search the descriptors for that hash code to see if any of them describes X. If yes, the descriptor records @@ -3558,16 +3520,15 @@ force_const_mem (mode, x) CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1; current_function_uses_const_pool = 1; - if (outer_function_chain == 0) - if (GET_CODE (x) == CONST_DOUBLE) - { - if (CONST_DOUBLE_MEM (x) == cc0_rtx) - { - CONST_DOUBLE_CHAIN (x) = const_double_chain; - const_double_chain = x; - } - CONST_DOUBLE_MEM (x) = def; - } + if (GET_CODE (x) == CONST_DOUBLE) + { + if (CONST_DOUBLE_MEM (x) == cc0_rtx) + { + CONST_DOUBLE_CHAIN (x) = const_double_chain; + const_double_chain = x; + } + CONST_DOUBLE_MEM (x) = def; + } return def; } @@ -3576,13 +3537,14 @@ force_const_mem (mode, x) the corresponding pool_constant structure. */ static struct pool_constant * -find_pool_constant (addr) +find_pool_constant (f, addr) + struct function *f; rtx addr; { struct pool_sym *sym; char *label = XSTR (addr, 0); - for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next) + for (sym = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next) if (sym->label == label) return sym->pool; @@ -3595,7 +3557,17 @@ rtx get_pool_constant (addr) rtx addr; { - return (find_pool_constant (addr))->constant; + return (find_pool_constant (current_function, addr))->constant; +} + +/* Likewise, but for the constant pool of a specific function. */ + +rtx +get_pool_constant_for_function (f, addr) + struct function *f; + rtx addr; +{ + return (find_pool_constant (f, addr))->constant; } /* Similar, return the mode. */ @@ -3604,7 +3576,15 @@ enum machine_mode get_pool_mode (addr) rtx addr; { - return (find_pool_constant (addr))->mode; + return (find_pool_constant (current_function, addr))->mode; +} + +enum machine_mode +get_pool_mode_for_function (f, addr) + struct function *f; + rtx addr; +{ + return (find_pool_constant (f, addr))->mode; } /* Similar, return the offset in the constant pool. */ @@ -3613,7 +3593,7 @@ int get_pool_offset (addr) rtx addr; { - return (find_pool_constant (addr))->offset; + return (find_pool_constant (current_function, addr))->offset; } /* Return the size of the constant pool. */ @@ -3786,14 +3766,11 @@ mark_constants (x) if (GET_CODE (x) == SYMBOL_REF) { if (CONSTANT_POOL_ADDRESS_P (x)) - find_pool_constant (x)->mark = 1; + find_pool_constant (current_function, x)->mark = 1; return; } /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be - a MEM, but does not constitute a use of that MEM. This is particularly - important inside a nested function, because CONST_DOUBLE_MEM may be - a reference to a MEM in the parent's constant pool. See the comment - in force_const_mem. */ + a MEM, but does not constitute a use of that MEM. */ else if (GET_CODE (x) == CONST_DOUBLE) return; |