From 4e7ac24200e18bbd6367139a46c1286294a70474 Mon Sep 17 00:00:00 2001 From: kan Date: Fri, 11 Jul 2003 04:00:23 +0000 Subject: FreeBSD uses stock versions of these GCC files. --- contrib/gcc/function.c | 799 ++++++++++++++++++++++--------------------------- 1 file changed, 353 insertions(+), 446 deletions(-) (limited to 'contrib/gcc/function.c') diff --git a/contrib/gcc/function.c b/contrib/gcc/function.c index f733076..daa2cab 100644 --- a/contrib/gcc/function.c +++ b/contrib/gcc/function.c @@ -53,9 +53,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "recog.h" #include "output.h" #include "basic-block.h" -#include "obstack.h" #include "toplev.h" -#include "hash.h" +#include "hashtab.h" #include "ggc.h" #include "tm_p.h" #include "integrate.h" @@ -75,7 +74,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA must define both, or neither. */ #ifndef NAME__MAIN #define NAME__MAIN "__main" -#define SYMBOL__MAIN __main #endif /* Round a value to the lowest integer less than it that is a multiple of @@ -124,24 +122,12 @@ int current_function_uses_only_leaf_regs; post-instantiation libcalls. */ int virtuals_instantiated; -/* Assign unique numbers to labels generated for profiling. */ -static int profile_label_no; +/* Assign unique numbers to labels generated for profiling, debugging, etc. */ +static int funcdef_no; /* These variables hold pointers to functions to create and destroy target specific, per-function data structures. */ -void (*init_machine_status) PARAMS ((struct function *)); -void (*free_machine_status) PARAMS ((struct function *)); -/* This variable holds a pointer to a function to register any - data items in the target specific, per-function data structure - that will need garbage collection. */ -void (*mark_machine_status) PARAMS ((struct function *)); - -/* Likewise, but for language-specific data. */ -void (*init_lang_status) PARAMS ((struct function *)); -void (*save_lang_status) PARAMS ((struct function *)); -void (*restore_lang_status) PARAMS ((struct function *)); -void (*mark_lang_status) PARAMS ((struct function *)); -void (*free_lang_status) PARAMS ((struct function *)); +struct machine_function * (*init_machine_status) PARAMS ((void)); /* The FUNCTION_DECL for an inline function currently being expanded. */ tree inline_function_decl; @@ -150,12 +136,12 @@ tree inline_function_decl; struct function *cfun = 0; /* These arrays record the INSN_UIDs of the prologue and epilogue insns. */ -static varray_type prologue; -static varray_type epilogue; +static GTY(()) varray_type prologue; +static GTY(()) varray_type epilogue; /* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue in this function. */ -static varray_type sibcall_epilogue; +static GTY(()) varray_type sibcall_epilogue; /* In order to evaluate some expressions, such as function calls returning structures in memory, we need to temporarily allocate stack locations. @@ -175,7 +161,7 @@ static varray_type sibcall_epilogue; level where they are defined. They are marked a "kept" so that free_temp_slots will not free them. */ -struct temp_slot +struct temp_slot GTY(()) { /* Points to next temporary slot. */ struct temp_slot *next; @@ -195,13 +181,13 @@ struct temp_slot tree type; /* The value of `sequence_rtl_expr' when this temporary is allocated. */ tree rtl_expr; - /* Non-zero if this temporary is currently in use. */ + /* Nonzero if this temporary is currently in use. */ char in_use; - /* Non-zero if this temporary has its address taken. */ + /* Nonzero if this temporary has its address taken. */ char addr_taken; /* Nesting level at which this slot is being used. */ int level; - /* Non-zero if this should survive a call to free_temp_slots. */ + /* Nonzero if this should survive a call to free_temp_slots. */ int keep; /* The offset of the slot from the frame_pointer, including extra space for alignment. This info is for combine_temp_slots. */ @@ -216,7 +202,7 @@ struct temp_slot maintain this list in case two operands of an insn were required to match; in that case we must ensure we use the same replacement. */ -struct fixup_replacement +struct fixup_replacement GTY(()) { rtx old; rtx new; @@ -225,9 +211,9 @@ struct fixup_replacement struct insns_for_mem_entry { - /* The KEY in HE will be a MEM. */ - struct hash_entry he; - /* These are the INSNS which reference the MEM. */ + /* A MEM. */ + rtx key; + /* These are the INSNs which reference the MEM. */ rtx insns; }; @@ -239,25 +225,25 @@ static struct temp_slot *find_temp_slot_from_address PARAMS ((rtx)); static void put_reg_into_stack PARAMS ((struct function *, rtx, tree, enum machine_mode, enum machine_mode, int, unsigned int, int, - struct hash_table *)); + htab_t)); static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree, enum machine_mode, - struct hash_table *)); + htab_t)); static void fixup_var_refs PARAMS ((rtx, enum machine_mode, int, rtx, - struct hash_table *)); + htab_t)); static struct fixup_replacement *find_fixup_replacement PARAMS ((struct fixup_replacement **, rtx)); static void fixup_var_refs_insns PARAMS ((rtx, rtx, enum machine_mode, int, int, rtx)); static void fixup_var_refs_insns_with_hash - PARAMS ((struct hash_table *, rtx, + PARAMS ((htab_t, rtx, enum machine_mode, int, rtx)); static void fixup_var_refs_insn PARAMS ((rtx, rtx, enum machine_mode, int, int, rtx)); static void fixup_var_refs_1 PARAMS ((rtx, enum machine_mode, rtx *, rtx, struct fixup_replacement **, rtx)); static rtx fixup_memory_subreg PARAMS ((rtx, rtx, enum machine_mode, int)); -static rtx walk_fixup_memory_subreg PARAMS ((rtx, rtx, enum machine_mode, +static rtx walk_fixup_memory_subreg PARAMS ((rtx, rtx, enum machine_mode, int)); static rtx fixup_stack_1 PARAMS ((rtx, rtx)); static void optimize_bit_field PARAMS ((rtx, rtx, rtx *)); @@ -269,10 +255,8 @@ static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int)); static void delete_handlers PARAMS ((void)); static void pad_to_arg_alignment PARAMS ((struct args_size *, int, struct args_size *)); -#ifndef ARGS_GROW_DOWNWARD static void pad_below PARAMS ((struct args_size *, enum machine_mode, tree)); -#endif static rtx round_trampoline_addr PARAMS ((rtx)); static rtx adjust_trampoline_addr PARAMS ((rtx)); static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *)); @@ -290,29 +274,25 @@ static int contains PARAMS ((rtx, varray_type)); #ifdef HAVE_return static void emit_return_into_block PARAMS ((basic_block, rtx)); #endif -static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *)); +static void put_addressof_into_stack PARAMS ((rtx, htab_t)); static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int, - struct hash_table *)); + htab_t)); static void purge_single_hard_subreg_set PARAMS ((rtx)); #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX) static rtx keep_stack_depressed PARAMS ((rtx)); #endif static int is_addressof PARAMS ((rtx *, void *)); -static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *, - struct hash_table *, - hash_table_key)); -static unsigned long insns_for_mem_hash PARAMS ((hash_table_key)); -static bool insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key)); +static hashval_t insns_for_mem_hash PARAMS ((const void *)); +static int insns_for_mem_comp PARAMS ((const void *, const void *)); static int insns_for_mem_walk PARAMS ((rtx *, void *)); -static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *)); -static void mark_function_status PARAMS ((struct function *)); -static void maybe_mark_struct_function PARAMS ((void *)); +static void compute_insns_for_mem PARAMS ((rtx, rtx, htab_t)); static void prepare_function_start PARAMS ((void)); static void do_clobber_return_reg PARAMS ((rtx, void *)); static void do_use_return_reg PARAMS ((rtx, void *)); +static void instantiate_virtual_regs_lossage PARAMS ((rtx)); /* Pointer to chain of `struct function' for containing functions. */ -static struct function *outer_function_chain; +static GTY(()) struct function *outer_function_chain; /* Given a function decl for a containing function, return the `struct function' for it. */ @@ -332,7 +312,7 @@ find_function_data (decl) /* Save the current context for compilation of a nested function. This is called from language-specific code. The caller should use - the save_lang_status callback to save any language-specific state, + the enter_nested langhook to save any language-specific state, since this function knows only about language-independent variables. */ @@ -361,8 +341,7 @@ push_function_context_to (context) outer_function_chain = p; p->fixup_var_refs_queue = 0; - if (save_lang_status) - (*save_lang_status) (p); + (*lang_hooks.function.enter_nested) (p); cfun = 0; } @@ -391,8 +370,7 @@ pop_function_context_from (context) restore_emit_status (p); - if (restore_lang_status) - (*restore_lang_status) (p); + (*lang_hooks.function.leave_nested) (p); /* Finish doing put_var_into_stack for any of our variables which became addressable during the nested function. If only one entry has to be @@ -445,9 +423,8 @@ free_after_parsing (f) /* f->varasm is used by code generation. */ /* f->eh->eh_return_stub_label is used by code generation. */ - if (free_lang_status) - (*free_lang_status) (f); - free_stmt_status (f); + (*lang_hooks.function.final) (f); + f->stmt = NULL; } /* Clear out all parts of the state in F that can safely be discarded @@ -458,16 +435,11 @@ void free_after_compilation (f) struct function *f; { - free_eh_status (f); - free_expr_status (f); - free_emit_status (f); - free_varasm_status (f); - - if (free_machine_status) - (*free_machine_status) (f); - - if (f->x_parm_reg_stack_loc) - free (f->x_parm_reg_stack_loc); + f->eh = NULL; + f->expr = NULL; + f->emit = NULL; + f->varasm = NULL; + f->machine = NULL; f->x_temp_slots = NULL; f->arg_offset_rtx = NULL; @@ -479,6 +451,8 @@ free_after_compilation (f) f->x_nonlocal_goto_stack_level = NULL; f->x_cleanup_label = NULL; f->x_return_label = NULL; + f->computed_goto_common_label = NULL; + f->computed_goto_common_reg = NULL; f->x_save_expr_regs = NULL; f->x_stack_slot_list = NULL; f->x_rtl_expr_chain = NULL; @@ -560,7 +534,7 @@ assign_stack_local_1 (mode, size, align, function) /* Allow the target to (possibly) increase the alignment of this stack slot. */ - type = type_for_mode (mode, 0); + type = (*lang_hooks.types.type_for_mode) (mode, 0); if (type) alignment = LOCAL_ALIGNMENT (type, alignment); @@ -680,7 +654,7 @@ assign_stack_temp_for_type (mode, size, keep, type) align = GET_MODE_ALIGNMENT (mode); if (! type) - type = type_for_mode (mode, 0); + type = (*lang_hooks.types.type_for_mode) (mode, 0); if (type) align = LOCAL_ALIGNMENT (type, align); @@ -902,7 +876,7 @@ assign_temp (type_or_decl, keep, memory_required, dont_promote) /* The size of the temporary may be too large to fit into an integer. */ /* ??? Not sure this should happen except for user silliness, so limit - this to things that aren't compiler-generated temporaries. The + this to things that aren't compiler-generated temporaries. The rest of the time we'll abort in assign_stack_temp_for_type. */ if (decl && size == -1 && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST) @@ -1350,12 +1324,16 @@ init_temp_slots () target_temp_slot_level = 0; } -/* Retroactively move an auto variable from a register to a stack slot. - This is done when an address-reference to the variable is seen. */ +/* Retroactively move an auto variable from a register to a stack + slot. This is done when an address-reference to the variable is + seen. If RESCAN is true, all previously emitted instructions are + examined and modified to handle the fact that DECL is now + addressable. */ void -put_var_into_stack (decl) +put_var_into_stack (decl, rescan) tree decl; + int rescan; { rtx reg; enum machine_mode promoted_mode, decl_mode; @@ -1369,8 +1347,8 @@ put_var_into_stack (decl) context = decl_function_context (decl); /* Get the current rtl used for this object and its original mode. */ - reg = (TREE_CODE (decl) == SAVE_EXPR - ? SAVE_EXPR_RTL (decl) + reg = (TREE_CODE (decl) == SAVE_EXPR + ? SAVE_EXPR_RTL (decl) : DECL_RTL_IF_SET (decl)); /* No need to do anything if decl has no rtx yet @@ -1430,7 +1408,7 @@ put_var_into_stack (decl) to put things in the stack for the sake of setjmp, try to keep it in a register until we know we actually need the address. */ if (can_use_addressof) - gen_mem_addressof (reg, decl); + gen_mem_addressof (reg, decl, rescan); else put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode, decl_mode, volatilep, 0, usedp, 0); @@ -1443,7 +1421,7 @@ put_var_into_stack (decl) to the whole CONCAT, lest we do double fixups for the latter references. */ enum machine_mode part_mode = GET_MODE (XEXP (reg, 0)); - tree part_type = type_for_mode (part_mode, 0); + tree part_type = (*lang_hooks.types.type_for_mode) (part_mode, 0); rtx lopart = XEXP (reg, 0); rtx hipart = XEXP (reg, 1); #ifdef FRAME_GROWS_DOWNWARD @@ -1477,7 +1455,7 @@ put_var_into_stack (decl) /* Prevent sharing of rtl that might lose. */ if (GET_CODE (XEXP (reg, 0)) == PLUS) XEXP (reg, 0) = copy_rtx (XEXP (reg, 0)); - if (usedp) + if (usedp && rescan) { schedule_fixup_var_refs (function, reg, TREE_TYPE (decl), promoted_mode, 0); @@ -1506,7 +1484,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p, int volatile_p; unsigned int original_regno; int used_p; - struct hash_table *ht; + htab_t ht; { struct function *func = function ? function : cfun; rtx new = 0; @@ -1554,7 +1532,7 @@ schedule_fixup_var_refs (function, reg, type, promoted_mode, ht) rtx reg; tree type; enum machine_mode promoted_mode; - struct hash_table *ht; + htab_t ht; { int unsigned_p = type ? TREE_UNSIGNED (type) : 0; @@ -1580,7 +1558,7 @@ fixup_var_refs (var, promoted_mode, unsignedp, may_share, ht) rtx var; enum machine_mode promoted_mode; int unsignedp; - struct hash_table *ht; + htab_t ht; rtx may_share; { tree pending; @@ -1716,17 +1694,18 @@ fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel, may_share) static void fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp, may_share) - struct hash_table *ht; + htab_t ht; rtx var; enum machine_mode promoted_mode; int unsignedp; rtx may_share; { - struct insns_for_mem_entry *ime - = (struct insns_for_mem_entry *) hash_lookup (ht, var, - /*create=*/0, /*copy=*/0); + struct insns_for_mem_entry tmp; + struct insns_for_mem_entry *ime; rtx insn_list; + tmp.key = var; + ime = (struct insns_for_mem_entry *) htab_find (ht, &tmp); for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1)) if (INSN_P (XEXP (insn_list, 0))) fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode, @@ -1872,7 +1851,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel, no_share) /* OLD might be a (subreg (mem)). */ if (GET_CODE (replacements->old) == SUBREG) replacements->old - = fixup_memory_subreg (replacements->old, insn, + = fixup_memory_subreg (replacements->old, insn, promoted_mode, 0); else replacements->old @@ -1890,7 +1869,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel, no_share) start_sequence (); convert_move (replacements->new, replacements->old, unsignedp); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); } else @@ -1972,7 +1951,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) start_sequence (); new_insn = emit_insn (gen_rtx_SET (VOIDmode, y, sub)); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); if (recog_memoized (new_insn) < 0) @@ -1983,7 +1962,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) sub = force_operand (sub, y); if (sub != y) emit_insn (gen_move_insn (y, sub)); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); } @@ -2200,7 +2179,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) return; } - replacement->new = *loc = fixup_memory_subreg (x, insn, + replacement->new = *loc = fixup_memory_subreg (x, insn, promoted_mode, 0); INSN_CODE (insn) = -1; @@ -2408,12 +2387,12 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) copy SET_SRC (x) to SET_DEST (x) in some way. So we generate the move and see whether it requires more than one insn. If it does, we emit those insns and - delete INSN. Otherwise, we an just replace the pattern + delete INSN. Otherwise, we can just replace the pattern of INSN; we have already verified above that INSN has no other function that to do X. */ pat = gen_move_insn (SET_DEST (x), SET_SRC (x)); - if (GET_CODE (pat) == SEQUENCE) + if (NEXT_INSN (pat) != NULL_RTX) { last = emit_insn_before (pat, insn); @@ -2431,7 +2410,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) delete_insn (last); } else - PATTERN (insn) = pat; + PATTERN (insn) = PATTERN (pat); return; } @@ -2448,7 +2427,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) rtx pat, last; if (GET_CODE (SET_DEST (x)) == SUBREG) - SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, + SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, promoted_mode, 0); else SET_DEST (x) = fixup_stack_1 (SET_DEST (x), insn); @@ -2457,7 +2436,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) return; pat = gen_move_insn (SET_DEST (x), SET_SRC (x)); - if (GET_CODE (pat) == SEQUENCE) + if (NEXT_INSN (pat) != NULL_RTX) { last = emit_insn_before (pat, insn); @@ -2475,7 +2454,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) delete_insn (last); } else - PATTERN (insn) = pat; + PATTERN (insn) = PATTERN (pat); return; } @@ -2502,7 +2481,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) /* Convert (SUBREG (MEM)) to a MEM in a changed mode. */ if (GET_CODE (fixeddest) == SUBREG) { - fixeddest = fixup_memory_subreg (fixeddest, insn, + fixeddest = fixup_memory_subreg (fixeddest, insn, promoted_mode, 0); temp_mode = GET_MODE (fixeddest); } @@ -2547,7 +2526,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share) /* Previously, X had the form (SUBREG:m1 (REG:PROMOTED_MODE ...)). The REG was placed on the stack, so X now has the form (SUBREG:m1 - (MEM:m2 ...)). + (MEM:m2 ...)). Return an rtx (MEM:m1 newaddr) which is equivalent. If any insns must be emitted to compute NEWADDR, put them before INSN. @@ -2566,7 +2545,7 @@ fixup_memory_subreg (x, insn, promoted_mode, uncritical) rtx mem = SUBREG_REG (x); rtx addr = XEXP (mem, 0); enum machine_mode mode = GET_MODE (x); - rtx result; + rtx result, seq; /* Paradoxical SUBREGs are usually invalid during RTL generation. */ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (mem)) && ! uncritical) @@ -2576,7 +2555,7 @@ fixup_memory_subreg (x, insn, promoted_mode, uncritical) if (BYTES_BIG_ENDIAN) /* If the PROMOTED_MODE is wider than the mode of the MEM, adjust the offset so that it points to the right location within the - MEM. */ + MEM. */ offset -= (GET_MODE_SIZE (promoted_mode) - GET_MODE_SIZE (GET_MODE (mem))); if (!flag_force_addr @@ -2586,8 +2565,10 @@ fixup_memory_subreg (x, insn, promoted_mode, uncritical) start_sequence (); result = adjust_address (mem, mode, offset); - emit_insn_before (gen_sequence (), insn); + seq = get_insns (); end_sequence (); + + emit_insn_before (seq, insn); return result; } @@ -2596,7 +2577,7 @@ fixup_memory_subreg (x, insn, promoted_mode, uncritical) If X itself is a (SUBREG (MEM ...) ...), return the replacement expression. Otherwise return X, with its contents possibly altered. - INSN, PROMOTED_MODE and UNCRITICAL are as for + INSN, PROMOTED_MODE and UNCRITICAL are as for fixup_memory_subreg. */ static rtx @@ -2624,14 +2605,14 @@ walk_fixup_memory_subreg (x, insn, promoted_mode, uncritical) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, + XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, promoted_mode, uncritical); else if (fmt[i] == 'E') { int j; for (j = 0; j < XVECLEN (x, i); j++) XVECEXP (x, i, j) - = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, + = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, promoted_mode, uncritical); } } @@ -2677,7 +2658,7 @@ fixup_stack_1 (x, insn) start_sequence (); temp = copy_to_reg (ad); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); emit_insn_before (seq, insn); return replace_equiv_address (x, temp); @@ -2788,7 +2769,7 @@ optimize_bit_field (body, insn, equiv_mem) memref = adjust_address (memref, mode, offset); insns = get_insns (); end_sequence (); - emit_insns_before (insns, insn); + emit_insn_before (insns, insn); /* Store this memory reference where we found the bit field reference. */ @@ -2856,7 +2837,7 @@ optimize_bit_field (body, insn, equiv_mem) special; just let the optimization be suppressed. */ if (apply_change_group () && seq) - emit_insns_before (seq, insn); + emit_insn_before (seq, insn); } } } @@ -2914,15 +2895,19 @@ static int cfa_offset; #define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL) #endif -/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had its - address taken. DECL is the decl or SAVE_EXPR for the object stored in the - register, for later use if we do need to force REG into the stack. REG is - overwritten by the MEM like in put_reg_into_stack. */ +/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just + had its address taken. DECL is the decl or SAVE_EXPR for the + object stored in the register, for later use if we do need to force + REG into the stack. REG is overwritten by the MEM like in + put_reg_into_stack. RESCAN is true if previously emitted + instructions must be rescanned and modified now that the REG has + been transformed. */ rtx -gen_mem_addressof (reg, decl) +gen_mem_addressof (reg, decl, rescan) rtx reg; tree decl; + int rescan; { rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg), decl); @@ -2960,10 +2945,11 @@ gen_mem_addressof (reg, decl) if (DECL_P (decl) && decl_rtl == reg) SET_DECL_RTL (decl, reg); - if (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)) + if (rescan + && (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0))) fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0); } - else + else if (rescan) fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0); return reg; @@ -2988,7 +2974,7 @@ flush_addressof (decl) static void put_addressof_into_stack (r, ht) rtx r; - struct hash_table *ht; + htab_t ht; { tree decl, type; int volatile_p, used_p; @@ -3040,7 +3026,7 @@ purge_addressof_1 (loc, insn, force, store, ht) rtx *loc; rtx insn; int force, store; - struct hash_table *ht; + htab_t ht; { rtx x; RTX_CODE code; @@ -3072,7 +3058,7 @@ purge_addressof_1 (loc, insn, force, store, ht) if (GET_CODE (XEXP (x, 0)) != MEM) put_addressof_into_stack (x, ht); - + /* We must create a copy of the rtx because it was created by overwriting a REG rtx which is always shared. */ sub = copy_rtx (XEXP (XEXP (x, 0), 0)); @@ -3086,7 +3072,7 @@ purge_addressof_1 (loc, insn, force, store, ht) && ! validate_replace_rtx (x, sub, insn)) abort (); - insns = gen_sequence (); + insns = get_insns (); end_sequence (); emit_insn_before (insns, insn); return true; @@ -3174,10 +3160,16 @@ purge_addressof_1 (loc, insn, force, store, ht) size_x = GET_MODE_BITSIZE (GET_MODE (x)); size_sub = GET_MODE_BITSIZE (GET_MODE (sub)); + /* Do not frob unchanging MEMs. If a later reference forces the + pseudo to the stack, we can wind up with multiple writes to + an unchanging memory, which is invalid. */ + if (RTX_UNCHANGING_P (x) && size_x != size_sub) + ; + /* Don't even consider working with paradoxical subregs, or the moral equivalent seen here. */ - if (size_x <= size_sub - && int_mode_for_mode (GET_MODE (sub)) != BLKmode) + else if (size_x <= size_sub + && int_mode_for_mode (GET_MODE (sub)) != BLKmode) { /* Do a bitfield insertion to mirror what would happen in memory. */ @@ -3197,7 +3189,7 @@ purge_addressof_1 (loc, insn, force, store, ht) end_sequence (); goto give_up; } - seq = gen_sequence (); + seq = get_insns (); end_sequence (); emit_insn_before (seq, insn); compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (), @@ -3211,7 +3203,7 @@ purge_addressof_1 (loc, insn, force, store, ht) might have created. */ unshare_all_rtl_again (get_insns ()); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); p = emit_insn_after (seq, insn); if (NEXT_INSN (insn)) @@ -3236,7 +3228,7 @@ purge_addressof_1 (loc, insn, force, store, ht) goto give_up; } - seq = gen_sequence (); + seq = get_insns (); end_sequence (); emit_insn_before (seq, insn); compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (), @@ -3297,50 +3289,34 @@ purge_addressof_1 (loc, insn, force, store, ht) return result; } -/* Return a new hash table entry in HT. */ - -static struct hash_entry * -insns_for_mem_newfunc (he, ht, k) - struct hash_entry *he; - struct hash_table *ht; - hash_table_key k ATTRIBUTE_UNUSED; -{ - struct insns_for_mem_entry *ifmhe; - if (he) - return he; - - ifmhe = ((struct insns_for_mem_entry *) - hash_allocate (ht, sizeof (struct insns_for_mem_entry))); - ifmhe->insns = NULL_RTX; - - return &ifmhe->he; -} - /* Return a hash value for K, a REG. */ -static unsigned long +static hashval_t insns_for_mem_hash (k) - hash_table_key k; + const void * k; { - /* K is really a RTX. Just use the address as the hash value. */ - return (unsigned long) k; + /* Use the address of the key for the hash value. */ + struct insns_for_mem_entry *m = (struct insns_for_mem_entry *) k; + return htab_hash_pointer (m->key); } -/* Return non-zero if K1 and K2 (two REGs) are the same. */ +/* Return nonzero if K1 and K2 (two REGs) are the same. */ -static bool +static int insns_for_mem_comp (k1, k2) - hash_table_key k1; - hash_table_key k2; + const void * k1; + const void * k2; { - return k1 == k2; + struct insns_for_mem_entry *m1 = (struct insns_for_mem_entry *) k1; + struct insns_for_mem_entry *m2 = (struct insns_for_mem_entry *) k2; + return m1->key == m2->key; } struct insns_for_mem_walk_info { /* The hash table that we are using to record which INSNs use which MEMs. */ - struct hash_table *ht; + htab_t ht; /* The INSN we are currently processing. */ rtx insn; @@ -3362,18 +3338,26 @@ insns_for_mem_walk (r, data) { struct insns_for_mem_walk_info *ifmwi = (struct insns_for_mem_walk_info *) data; + struct insns_for_mem_entry tmp; + tmp.insns = NULL_RTX; if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF && GET_CODE (XEXP (*r, 0)) == REG) - hash_lookup (ifmwi->ht, XEXP (*r, 0), /*create=*/1, /*copy=*/0); + { + PTR *e; + tmp.key = XEXP (*r, 0); + e = htab_find_slot (ifmwi->ht, &tmp, INSERT); + if (*e == NULL) + { + *e = ggc_alloc (sizeof (tmp)); + memcpy (*e, &tmp, sizeof (tmp)); + } + } else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG) { - /* Lookup this MEM in the hashtable, creating it if necessary. */ - struct insns_for_mem_entry *ifme - = (struct insns_for_mem_entry *) hash_lookup (ifmwi->ht, - *r, - /*create=*/0, - /*copy=*/0); + struct insns_for_mem_entry *ifme; + tmp.key = *r; + ifme = (struct insns_for_mem_entry *) htab_find (ifmwi->ht, &tmp); /* If we have not already recorded this INSN, do so now. Since we process the INSNs in order, we know that if we have @@ -3393,7 +3377,7 @@ static void compute_insns_for_mem (insns, last_insn, ht) rtx insns; rtx last_insn; - struct hash_table *ht; + htab_t ht; { rtx insn; struct insns_for_mem_walk_info ifmwi; @@ -3428,7 +3412,7 @@ purge_addressof (insns) rtx insns; { rtx insn; - struct hash_table ht; + htab_t ht; /* When we actually purge ADDRESSOFs, we turn REGs into MEMs. That requires a fixup pass over the instruction stream to correct @@ -3437,23 +3421,20 @@ purge_addressof (insns) mentioned in very many instructions. So, we speed up the process by pre-calculating which REGs occur in which INSNs; that allows us to perform the fixup passes much more quickly. */ - hash_table_init (&ht, - insns_for_mem_newfunc, - insns_for_mem_hash, - insns_for_mem_comp); - compute_insns_for_mem (insns, NULL_RTX, &ht); + ht = htab_create_ggc (1000, insns_for_mem_hash, insns_for_mem_comp, NULL); + compute_insns_for_mem (insns, NULL_RTX, ht); for (insn = insns; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN) { if (! purge_addressof_1 (&PATTERN (insn), insn, - asm_noperands (PATTERN (insn)) > 0, 0, &ht)) + asm_noperands (PATTERN (insn)) > 0, 0, ht)) /* If we could not replace the ADDRESSOFs in the insn, something is wrong. */ abort (); - if (! purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0, &ht)) + if (! purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0, ht)) { /* If we could not replace the ADDRESSOFs in the insn's notes, we can just remove the offending notes instead. */ @@ -3474,7 +3455,6 @@ purge_addressof (insns) } /* Clean up. */ - hash_table_free (&ht); purge_bitfield_addressof_replacements = 0; purge_addressof_replacements = 0; @@ -3514,7 +3494,7 @@ purge_single_hard_subreg_set (pattern) reg = SUBREG_REG (reg); } - + if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER) { reg = gen_rtx_REG (mode, REGNO (reg) + offset); @@ -3543,7 +3523,7 @@ purge_hard_subreg_sets (insn) case SET: if (GET_CODE (SET_DEST (pattern)) == SUBREG) purge_single_hard_subreg_set (pattern); - break; + break; case PARALLEL: { int j; @@ -3597,11 +3577,19 @@ instantiate_virtual_regs (fndecl, insns) || GET_CODE (insn) == CALL_INSN) { instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1); + if (INSN_DELETED_P (insn)) + continue; instantiate_virtual_regs_1 (®_NOTES (insn), NULL_RTX, 0); /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */ if (GET_CODE (insn) == CALL_INSN) instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn), NULL_RTX, 0); + + /* Past this point all ASM statements should match. Verify that + to avoid failures later in the compilation process. */ + if (asm_noperands (PATTERN (insn)) >= 0 + && ! check_asm_operands (PATTERN (insn))) + instantiate_virtual_regs_lossage (insn); } /* Instantiate the stack slots for the parm registers, for later use in @@ -3664,7 +3652,7 @@ instantiate_decls_1 (let, valid_only) for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) if (DECL_RTL_SET_P (t)) - instantiate_decl (DECL_RTL (t), + instantiate_decl (DECL_RTL (t), int_size_in_bytes (TREE_TYPE (t)), valid_only); @@ -3676,7 +3664,7 @@ instantiate_decls_1 (let, valid_only) /* Subroutine of the preceding procedures: Given RTL representing a decl and the size of the object, do any instantiation required. - If VALID_ONLY is non-zero, it means that the RTL should only be + If VALID_ONLY is nonzero, it means that the RTL should only be changed if the new address is valid. */ static void @@ -3769,6 +3757,22 @@ instantiate_new_reg (x, poffset) return new; } + +/* Called when instantiate_virtual_regs has failed to update the instruction. + Usually this means that non-matching instruction has been emit, however for + asm statements it may be the problem in the constraints. */ +static void +instantiate_virtual_regs_lossage (insn) + rtx insn; +{ + if (asm_noperands (PATTERN (insn)) >= 0) + { + error_for_asm (insn, "impossible constraint in `asm'"); + delete_insn (insn); + } + else + abort (); +} /* Given a pointer to a piece of rtx and an optional pointer to the containing object, instantiate any virtual registers present in it. @@ -3805,6 +3809,10 @@ instantiate_virtual_regs_1 (loc, object, extra_insns) if (x == 0) return 1; + /* We may have detected and deleted invalid asm statements. */ + if (object && INSN_P (object) && INSN_DELETED_P (object)) + return 1; + code = GET_CODE (x); /* Check for some special cases. */ @@ -3842,7 +3850,10 @@ instantiate_virtual_regs_1 (loc, object, extra_insns) /* The only valid sources here are PLUS or REG. Just do the simplest possible thing to handle them. */ if (GET_CODE (src) != REG && GET_CODE (src) != PLUS) - abort (); + { + instantiate_virtual_regs_lossage (object); + return 1; + } start_sequence (); if (GET_CODE (src) != REG) @@ -3853,12 +3864,12 @@ instantiate_virtual_regs_1 (loc, object, extra_insns) seq = get_insns (); end_sequence (); - emit_insns_before (seq, object); + emit_insn_before (seq, object); SET_DEST (x) = new; if (! validate_change (object, &SET_SRC (x), temp, 0) || ! extra_insns) - abort (); + instantiate_virtual_regs_lossage (object); return 1; } @@ -3965,10 +3976,13 @@ instantiate_virtual_regs_1 (loc, object, extra_insns) seq = get_insns (); end_sequence (); - emit_insns_before (seq, object); + emit_insn_before (seq, object); if (! validate_change (object, loc, temp, 0) && ! validate_replace_rtx (x, temp, object)) - abort (); + { + instantiate_virtual_regs_lossage (object); + return 1; + } } } @@ -4119,10 +4133,10 @@ instantiate_virtual_regs_1 (loc, object, extra_insns) seq = get_insns (); end_sequence (); - emit_insns_before (seq, object); + emit_insn_before (seq, object); if (! validate_change (object, loc, temp, 0) && ! validate_replace_rtx (x, temp, object)) - abort (); + instantiate_virtual_regs_lossage (object); } } @@ -4322,17 +4336,6 @@ assign_parms (fndecl) rtx conversion_insns = 0; struct args_size alignment_pad; - /* Nonzero if the last arg is named `__builtin_va_alist', - which is used on some machines for old-fashioned non-ANSI varargs.h; - this should be stuck onto the stack as if it had arrived there. */ - int hide_last_arg - = (current_function_varargs - && fnargs - && (parm = tree_last (fnargs)) != 0 - && DECL_NAME (parm) - && (! strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)), - "__builtin_va_alist"))); - /* Nonzero if function takes extra anonymous args. This means the last named arg must be on the stack right before the anonymous ones. */ @@ -4376,7 +4379,7 @@ assign_parms (fndecl) } max_parm_reg = LAST_VIRTUAL_REGISTER + 1; - parm_reg_stack_loc = (rtx *) xcalloc (max_parm_reg, sizeof (rtx)); + parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx)); #ifdef INIT_CUMULATIVE_INCOMING_ARGS INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX); @@ -4401,7 +4404,7 @@ assign_parms (fndecl) /* Set LAST_NAMED if this is last named arg before last anonymous args. */ - if (stdarg || current_function_varargs) + if (stdarg) { tree tem; @@ -4429,11 +4432,6 @@ assign_parms (fndecl) continue; } - /* For varargs.h function, save info about regs and stack space - used by the individual args, not including the va_alist arg. */ - if (hide_last_arg && last_named) - current_function_args_info = args_so_far; - /* Find mode of arg as it is passed, and mode of arg as it should be during execution of this function. */ passed_mode = TYPE_MODE (passed_type); @@ -4474,6 +4472,15 @@ assign_parms (fndecl) passed_pointer = 1; passed_mode = nominal_mode = Pmode; } + /* See if the frontend wants to pass this by invisible reference. */ + else if (passed_type != nominal_type + && POINTER_TYPE_P (passed_type) + && TREE_TYPE (passed_type) == nominal_type) + { + nominal_type = passed_type; + passed_pointer = 1; + passed_mode = nominal_mode = Pmode; + } promoted_mode = passed_mode; @@ -4581,6 +4588,12 @@ assign_parms (fndecl) if (nregs > 0) { +#if defined (REG_PARM_STACK_SPACE) && !defined (MAYBE_REG_PARM_STACK_SPACE) + /* When REG_PARM_STACK_SPACE is nonzero, stack space for + split parameters was allocated by our caller, so we + won't be pushing it in the prolog. */ + if (REG_PARM_STACK_SPACE (fndecl) == 0) +#endif current_function_pretend_args_size = (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1) / (PARM_BOUNDARY / BITS_PER_UNIT) @@ -4615,8 +4628,8 @@ assign_parms (fndecl) to indicate there is no preallocated stack slot for the parm. */ if (entry_parm == stack_parm - || (GET_CODE (entry_parm) == PARALLEL - && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX) + || (GET_CODE (entry_parm) == PARALLEL + && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX) #if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE) /* On some machines, even if a parm value arrives in a register there is still an (uninitialized) stack slot allocated for it. @@ -4770,7 +4783,7 @@ assign_parms (fndecl) if (passed_pointer) { rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), - parmreg); + parmreg); set_mem_attributes (x, parm, 1); SET_DECL_RTL (parm, x); } @@ -4779,7 +4792,7 @@ assign_parms (fndecl) SET_DECL_RTL (parm, parmreg); maybe_set_unchanging (DECL_RTL (parm), parm); } - + /* Copy the value into the register. */ if (nominal_mode != passed_mode || promoted_nominal_mode != promoted_mode) @@ -4822,7 +4835,7 @@ assign_parms (fndecl) /* The argument is already sign/zero extended, so note it into the subreg. */ SUBREG_PROMOTED_VAR_P (tempreg) = 1; - SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp; + SUBREG_PROMOTED_UNSIGNED_SET (tempreg, unsignedp); } /* TREE_USED gets set erroneously during expand_assignment. */ @@ -4861,7 +4874,7 @@ assign_parms (fndecl) push_to_sequence (conversion_insns); emit_move_insn (tempreg, DECL_RTL (parm)); SET_DECL_RTL (parm, - convert_to_mode (GET_MODE (parmreg), + convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p)); emit_move_insn (parmreg, DECL_RTL (parm)); @@ -4940,7 +4953,7 @@ assign_parms (fndecl) but it's also rare and we need max_parm_reg to be precisely correct. */ max_parm_reg = regno + 1; - new = (rtx *) xrealloc (parm_reg_stack_loc, + new = (rtx *) ggc_realloc (parm_reg_stack_loc, max_parm_reg * sizeof (rtx)); memset ((char *) (new + old_max_parm_reg), 0, (max_parm_reg - old_max_parm_reg) * sizeof (rtx)); @@ -5031,7 +5044,7 @@ assign_parms (fndecl) stack. So, we go back to that sequence, just so that the fixups will happen. */ push_to_sequence (conversion_insns); - put_var_into_stack (parm); + put_var_into_stack (parm, /*rescan=*/true); conversion_insns = get_insns (); end_sequence (); } @@ -5116,7 +5129,7 @@ assign_parms (fndecl) /* Output all parameter conversion instructions (possibly including calls) now that all parameters have been copied out of hard registers. */ - emit_insns (conversion_insns); + emit_insn (conversion_insns); last_parm_insn = get_last_insn (); @@ -5157,8 +5170,7 @@ assign_parms (fndecl) /* For stdarg.h function, save info about regs and stack space used by the named args. */ - if (!hide_last_arg) - current_function_args_info = args_so_far; + current_function_args_info = args_so_far; /* Set the rtx used for the function return value. Put this in its own variable so any optimizers that need this information don't have @@ -5248,7 +5260,7 @@ promoted_input_arg (regno, pmode, punsignedp) The starting offset and size for this parm are returned in *OFFSET_PTR and *ARG_SIZE_PTR, respectively. - IN_REGS is non-zero if the argument will be passed in registers. It will + IN_REGS is nonzero if the argument will be passed in registers. It will never be set if REG_PARM_STACK_SPACE is not defined. FNDECL is the function in which the argument was defined. @@ -5286,6 +5298,9 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl, = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode)); enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type); int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type); +#ifdef ARGS_GROW_DOWNWARD + tree s2 = sizetree; +#endif #ifdef REG_PARM_STACK_SPACE /* If we have found a stack parm before we reach the end of the @@ -5331,13 +5346,20 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl, offset_ptr->constant = -initial_offset_ptr->constant; offset_ptr->var = 0; } + if (where_pad != none && (!host_integerp (sizetree, 1) || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY)) - sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT); - SUB_PARM_SIZE (*offset_ptr, sizetree); - if (where_pad != downward) + s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT); + SUB_PARM_SIZE (*offset_ptr, s2); + + if (!in_regs +#ifdef REG_PARM_STACK_SPACE + || REG_PARM_STACK_SPACE (fndecl) > 0 +#endif + ) pad_to_arg_alignment (offset_ptr, boundary, alignment_pad); + if (initial_offset_ptr->var) arg_size_ptr->var = size_binop (MINUS_EXPR, size_binop (MINUS_EXPR, @@ -5349,6 +5371,13 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl, arg_size_ptr->constant = (-initial_offset_ptr->constant - offset_ptr->constant); + /* Pad_below needs the pre-rounded size to know how much to pad below. + We only pad parameters which are not in registers as they have their + padding done elsewhere. */ + if (where_pad == downward + && !in_regs) + pad_below (offset_ptr, passed_mode, sizetree); + #else /* !ARGS_GROW_DOWNWARD */ if (!in_regs #ifdef REG_PARM_STACK_SPACE @@ -5416,8 +5445,8 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad) (ARGS_SIZE_TREE (*offset_ptr), boundary / BITS_PER_UNIT); offset_ptr->constant = 0; /*?*/ - if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY) - alignment_pad->var = size_binop (MINUS_EXPR, offset_ptr->var, + if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY) + alignment_pad->var = size_binop (MINUS_EXPR, offset_ptr->var, save_var); } else @@ -5434,7 +5463,6 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad) } } -#ifndef ARGS_GROW_DOWNWARD static void pad_below (offset_ptr, passed_mode, sizetree) struct args_size *offset_ptr; @@ -5462,7 +5490,6 @@ pad_below (offset_ptr, passed_mode, sizetree) } } } -#endif /* Walk the tree of blocks describing the binding levels within a function and warn about uninitialized variables. @@ -5477,7 +5504,7 @@ uninitialized_vars_warning (block) for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) { if (warn_uninitialized - && TREE_CODE (decl) == VAR_DECL + && TREE_CODE (decl) == VAR_DECL /* These warnings are unreliable for and aggregates because assigning the fields one by one can fail to convince flow.c that the entire aggregate was initialized. @@ -5497,7 +5524,7 @@ uninitialized_vars_warning (block) warning_with_decl (decl, "`%s' might be used uninitialized in this function"); if (extra_warnings - && TREE_CODE (decl) == VAR_DECL + && TREE_CODE (decl) == VAR_DECL && DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == REG && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) @@ -5553,7 +5580,7 @@ setjmp_protect (block) || #endif ! DECL_REGISTER (decl))) - put_var_into_stack (decl); + put_var_into_stack (decl, /*rescan=*/true); for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) setjmp_protect (sub); } @@ -5580,7 +5607,7 @@ setjmp_protect_args () || #endif ! DECL_REGISTER (decl))) - put_var_into_stack (decl); + put_var_into_stack (decl, /*rescan=*/true); } /* Return the context-pointer register corresponding to DECL, @@ -5739,12 +5766,8 @@ trampoline_address (function) #else /* If rounding needed, allocate extra space to ensure we have TRAMPOLINE_SIZE bytes left after rounding up. */ -#ifdef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_REAL_SIZE \ (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1) -#else -#define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE) -#endif tramp = assign_stack_local_1 (BLKmode, TRAMPOLINE_REAL_SIZE, 0, fp ? fp : cfun); #endif @@ -5779,7 +5802,6 @@ static rtx round_trampoline_addr (tramp) rtx tramp; { -#ifdef TRAMPOLINE_ALIGNMENT /* Round address up to desired boundary. */ rtx temp = gen_reg_rtx (Pmode); rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1); @@ -5789,7 +5811,7 @@ round_trampoline_addr (tramp) temp, 0, OPTAB_LIB_WIDEN); tramp = expand_simple_binop (Pmode, AND, temp, mask, temp, 0, OPTAB_LIB_WIDEN); -#endif + return tramp; } @@ -5942,8 +5964,6 @@ reorder_blocks () /* Remove deleted blocks from the block fragment chains. */ reorder_fix_fragments (block); - - VARRAY_FREE (block_stack); } /* Helper function for reorder_blocks. Reset TREE_ASM_WRITTEN. */ @@ -6031,7 +6051,7 @@ reorder_blocks_1 (insns, current_block, p_block_stack) static void reorder_fix_fragments (block) - tree block; + tree block; { while (block) { @@ -6043,7 +6063,7 @@ reorder_fix_fragments (block) if (! TREE_ASM_WRITTEN (dup_origin)) { new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin); - + /* Find the first of the remaining fragments. There must be at least one -- the current block. */ while (! TREE_ASM_WRITTEN (new_origin)) @@ -6312,8 +6332,7 @@ prepare_function_start () /* Indicate we have no need of a frame pointer yet. */ frame_pointer_needed = 0; - /* By default assume not varargs or stdarg. */ - current_function_varargs = 0; + /* By default assume not stdarg. */ current_function_stdarg = 0; /* We haven't made any trampolines for this function yet. */ @@ -6324,10 +6343,19 @@ prepare_function_start () current_function_outgoing_args_size = 0; - if (init_lang_status) - (*init_lang_status) (cfun); + current_function_funcdef_no = funcdef_no++; + + cfun->arc_profile = profile_arc_flag || flag_test_coverage; + + cfun->arc_profile = profile_arc_flag || flag_test_coverage; + + cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL; + + cfun->max_jumptable_ents = 0; + + (*lang_hooks.function.init) (cfun); if (init_machine_status) - (*init_machine_status) (cfun); + cfun->machine = (*init_machine_status) (); } /* Initialize the rtl expansion mechanism so that we can do simple things @@ -6351,7 +6379,7 @@ init_function_start (subr, filename, line) { prepare_function_start (); - current_function_name = (*decl_printable_name) (subr, 2); + current_function_name = (*lang_hooks.decl_printable_name) (subr, 2); cfun->decl = subr; /* Nonzero if this is a nested function that uses a static chain. */ @@ -6406,15 +6434,6 @@ init_function_for_compilation () VARRAY_GROW (sibcall_epilogue, 0); } -/* Indicate that the current function uses extra args - not explicitly mentioned in the argument list in any fashion. */ - -void -mark_varargs () -{ - current_function_varargs = 1; -} - /* Expand a call to __main at the beginning of a possible main function. */ #if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main) @@ -6444,11 +6463,11 @@ expand_main_function () #endif if (tmp != stack_pointer_rtx) emit_move_insn (stack_pointer_rtx, tmp); - + /* Enlist allocate_dynamic_stack_space to pick up the pieces. */ tmp = force_reg (Pmode, const0_rtx); allocate_dynamic_stack_space (tmp, NULL_RTX, BIGGEST_ALIGNMENT); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); for (tmp = get_last_insn (); tmp; tmp = PREV_INSN (tmp)) @@ -6467,8 +6486,6 @@ expand_main_function () #endif } -extern struct obstack permanent_obstack; - /* The PENDING_SIZES represent the sizes of variable-sized types. Create RTL for the various sizes now (using temporary variables), so that we can refer to the sizes from the RTL we are generating @@ -6597,18 +6614,17 @@ expand_function_start (subr, parms_have_cleanups) subr, 1); /* Structures that are returned in registers are not aggregate_value_p, - so we may see a PARALLEL. Don't play pseudo games with this. */ - if (! REG_P (hard_reg)) - SET_DECL_RTL (DECL_RESULT (subr), hard_reg); + so we may see a PARALLEL or a REG. */ + if (REG_P (hard_reg)) + SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg))); + else if (GET_CODE (hard_reg) == PARALLEL) + SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg)); else - { - /* Create the pseudo. */ - SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg))); + abort (); - /* Needed because we may need to move this to memory - in case it's a named return value whose address is taken. */ - DECL_REGISTER (DECL_RESULT (subr)) = 1; - } + /* Set DECL_REGISTER flag so that expand_function_end will copy the + result to the real return register(s). */ + DECL_REGISTER (DECL_RESULT (subr)) = 1; } /* Initialize rtx for parameters and local variables. @@ -6620,8 +6636,8 @@ expand_function_start (subr, parms_have_cleanups) avoid conflicts with the parameter passing registers. */ if (SMALL_REGISTER_CLASSES && current_function_needs_context) - if (GET_CODE (static_chain_incoming_rtx) != REG) - emit_move_insn (last_ptr, static_chain_incoming_rtx); + if (GET_CODE (static_chain_incoming_rtx) != REG) + emit_move_insn (last_ptr, static_chain_incoming_rtx); /* The following was moved from init_function_start. The move is supposed to make sdb output more accurate. */ @@ -6696,9 +6712,8 @@ expand_function_start (subr, parms_have_cleanups) if (current_function_profile) { - current_function_profile_label_no = profile_label_no++; #ifdef PROFILE_HOOK - PROFILE_HOOK (current_function_profile_label_no); + PROFILE_HOOK (current_function_funcdef_no); #endif } @@ -6798,6 +6813,8 @@ use_return_register () diddle_return_value (do_use_return_reg, NULL); } +static GTY(()) rtx initial_trampoline; + /* Generate RTL for the end of the current function. FILENAME and LINE are the current position in the source file. @@ -6813,10 +6830,6 @@ expand_function_end (filename, line, end_bindings) tree link; rtx clobber_after; -#ifdef TRAMPOLINE_TEMPLATE - static rtx initial_trampoline; -#endif - finish_expr_for_function (); /* If arg_pointer_save_area was referenced only from a nested @@ -6855,8 +6868,6 @@ expand_function_end (filename, line, end_bindings) initial_trampoline = gen_rtx_MEM (BLKmode, assemble_trampoline_template ()); set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT); - - ggc_add_rtx_root (&initial_trampoline, 1); } #endif @@ -6866,14 +6877,14 @@ expand_function_end (filename, line, end_bindings) #ifdef TRAMPOLINE_TEMPLATE blktramp = replace_equiv_address (initial_trampoline, tramp); emit_block_move (blktramp, initial_trampoline, - GEN_INT (TRAMPOLINE_SIZE)); + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); #endif INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context); seq = get_insns (); end_sequence (); /* Put those insns at entry to the containing function (this one). */ - emit_insns_before (seq, tail_recursion_reentry); + emit_insn_before (seq, tail_recursion_reentry); } /* If we are doing stack checking and this function makes calls, @@ -6891,7 +6902,7 @@ expand_function_end (filename, line, end_bindings) GEN_INT (STACK_CHECK_MAX_FRAME_SIZE)); seq = get_insns (); end_sequence (); - emit_insns_before (seq, tail_recursion_reentry); + emit_insn_before (seq, tail_recursion_reentry); break; } } @@ -7021,13 +7032,13 @@ expand_function_end (filename, line, end_bindings) /* If this is a BLKmode structure being returned in registers, then use the mode computed in expand_return. Note that if - decl_rtl is memory, then its mode may have been changed, + decl_rtl is memory, then its mode may have been changed, but that current_function_return_rtx has not. */ if (GET_MODE (real_decl_rtl) == BLKmode) PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl)); /* If a named return value dumped decl_return to memory, then - we may need to re-do the PROMOTE_MODE signed/unsigned + we may need to re-do the PROMOTE_MODE signed/unsigned extension. */ if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl)) { @@ -7041,8 +7052,16 @@ expand_function_end (filename, line, end_bindings) convert_move (real_decl_rtl, decl_rtl, unsignedp); } else if (GET_CODE (real_decl_rtl) == PARALLEL) - emit_group_load (real_decl_rtl, decl_rtl, - int_size_in_bytes (TREE_TYPE (decl_result))); + { + /* If expand_function_start has created a PARALLEL for decl_rtl, + move the result to the real return registers. Otherwise, do + a group load from decl_rtl for a named return. */ + if (GET_CODE (decl_rtl) == PARALLEL) + emit_group_move (real_decl_rtl, decl_rtl); + else + emit_group_load (real_decl_rtl, decl_rtl, + int_size_in_bytes (TREE_TYPE (decl_result))); + } else emit_move_insn (real_decl_rtl, decl_rtl); } @@ -7094,14 +7113,14 @@ expand_function_end (filename, line, end_bindings) /* Emit the actual code to clobber return register. */ { rtx seq, after; - + start_sequence (); clobber_return_register (); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); after = emit_insn_after (seq, clobber_after); - + if (clobber_after != after) cfun->x_clobber_return_insn = after; } @@ -7138,12 +7157,12 @@ get_arg_pointer_save_area (f) { rtx seq; - /* Save the arg pointer at the beginning of the function. The + /* Save the arg pointer at the beginning of the function. The generated stack slot may not be a valid memory address, so we have to check it and fix it if necessary. */ start_sequence (); emit_move_insn (validize_mem (ret), virtual_incoming_args_rtx); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); push_topmost_sequence (); @@ -7154,35 +7173,38 @@ get_arg_pointer_save_area (f) return ret; } -/* Extend a vector that records the INSN_UIDs of INSNS (either a - sequence or a single insn). */ +/* Extend a vector that records the INSN_UIDs of INSNS + (a list of one or more insns). */ static void record_insns (insns, vecp) rtx insns; varray_type *vecp; { - if (GET_CODE (insns) == SEQUENCE) - { - int len = XVECLEN (insns, 0); - int i = VARRAY_SIZE (*vecp); + int i, len; + rtx tmp; - VARRAY_GROW (*vecp, i + len); - while (--len >= 0) - { - VARRAY_INT (*vecp, i) = INSN_UID (XVECEXP (insns, 0, len)); - ++i; - } + tmp = insns; + len = 0; + while (tmp != NULL_RTX) + { + len++; + tmp = NEXT_INSN (tmp); } - else + + i = VARRAY_SIZE (*vecp); + VARRAY_GROW (*vecp, i + len); + tmp = insns; + while (tmp != NULL_RTX) { - int i = VARRAY_SIZE (*vecp); - VARRAY_GROW (*vecp, i + 1); - VARRAY_INT (*vecp, i) = INSN_UID (insns); + VARRAY_INT (*vecp, i) = INSN_UID (tmp); + i++; + tmp = NEXT_INSN (tmp); } } -/* Determine how many INSN_UIDs in VEC are part of INSN. */ +/* Determine how many INSN_UIDs in VEC are part of INSN. Because we can + be running after reorg, SEQUENCE rtl is possible. */ static int contains (insn, vec) @@ -7294,20 +7316,21 @@ struct epi_info static void handle_epilogue_set PARAMS ((rtx, struct epi_info *)); static void emit_equiv_load PARAMS ((struct epi_info *)); -/* Modify SEQ, a SEQUENCE that is part of the epilogue, to no modifications - to the stack pointer. Return the new sequence. */ +/* Modify INSN, a list of one or more insns that is part of the epilogue, to + no modifications to the stack pointer. Return the new list of insns. */ static rtx -keep_stack_depressed (seq) - rtx seq; +keep_stack_depressed (insns) + rtx insns; { - int i, j; + int j; struct epi_info info; + rtx insn, next; /* If the epilogue is just a single instruction, it ust be OK as is. */ - if (GET_CODE (seq) != SEQUENCE) - return seq; + if (NEXT_INSN (insns) == NULL_RTX) + return insns; /* Otherwise, start a sequence, initialize the information we have, and process all the insns we were given. */ @@ -7317,13 +7340,16 @@ keep_stack_depressed (seq) info.sp_offset = 0; info.equiv_reg_src = 0; - for (i = 0; i < XVECLEN (seq, 0); i++) + insn = insns; + next = NULL_RTX; + while (insn != NULL_RTX) { - rtx insn = XVECEXP (seq, 0, i); + next = NEXT_INSN (insn); if (!INSN_P (insn)) { add_insn (insn); + insn = next; continue; } @@ -7359,6 +7385,7 @@ keep_stack_depressed (seq) { emit_equiv_load (&info); add_insn (insn); + insn = next; continue; } else if (GET_CODE (retaddr) == MEM @@ -7459,16 +7486,18 @@ keep_stack_depressed (seq) info.sp_equiv_reg = info.new_sp_equiv_reg; info.sp_offset = info.new_sp_offset; + + insn = next; } - seq = gen_sequence (); + insns = get_insns (); end_sequence (); - return seq; + return insns; } /* SET is a SET from an insn in the epilogue. P is a pointer to the epi_info structure that contains information about what we've seen so far. We - process this SET by either updating that data or by emitting one or + process this SET by either updating that data or by emitting one or more insns. */ static void @@ -7578,12 +7607,10 @@ thread_prologue_and_epilogue_insns (f) emit_insn (seq); /* Retain a map of the prologue insns. */ - if (GET_CODE (seq) != SEQUENCE) - seq = get_insns (); record_insns (seq, &prologue); prologue_end = emit_note (NULL, NOTE_INSN_PROLOGUE_END); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); /* Can't deal with multiple successors of the entry block @@ -7674,19 +7701,8 @@ thread_prologue_and_epilogue_insns (f) that with a conditional return instruction. */ else if (condjump_p (jump)) { - rtx ret, *loc; - - ret = SET_SRC (PATTERN (jump)); - if (GET_CODE (XEXP (ret, 1)) == LABEL_REF) - loc = &XEXP (ret, 1); - else - loc = &XEXP (ret, 2); - ret = gen_rtx_RETURN (VOIDmode); - - if (! validate_change (jump, loc, ret, 0)) + if (! redirect_jump (jump, 0, 0)) continue; - if (JUMP_LABEL (jump)) - LABEL_NUSES (JUMP_LABEL (jump))--; /* If this block has only one successor, it both jumps and falls through to the fallthru block, so we can't @@ -7742,11 +7758,9 @@ thread_prologue_and_epilogue_insns (f) emit_jump_insn (seq); /* Retain a map of the epilogue insns. */ - if (GET_CODE (seq) != SEQUENCE) - seq = get_insns (); record_insns (seq, &epilogue); - seq = gen_sequence (); + seq = get_insns (); end_sequence (); insert_insn_on_edge (seq, e); @@ -7772,16 +7786,17 @@ epilogue_done: continue; start_sequence (); - seq = gen_sibcall_epilogue (); + emit_insn (gen_sibcall_epilogue ()); + seq = get_insns (); end_sequence (); + /* Retain a map of the epilogue insns. Used in life analysis to + avoid getting rid of sibcall epilogue insns. Do this before we + actually emit the sequence. */ + record_insns (seq, &sibcall_epilogue); + i = PREV_INSN (insn); newinsn = emit_insn_before (seq, insn); - - /* Retain a map of the epilogue insns. Used in life analysis to - avoid getting rid of sibcall epilogue insns. */ - record_insns (GET_CODE (seq) == SEQUENCE - ? seq : newinsn, &sibcall_epilogue); } #endif @@ -7797,7 +7812,7 @@ epilogue_done: note before the end of the first basic block, if there isn't one already there. - ??? This behaviour is completely broken when dealing with + ??? This behavior is completely broken when dealing with multiple entry functions. We simply place the note always into first basic block and let alternate entry points to be missed. @@ -7818,7 +7833,7 @@ epilogue_done: } /* Find the last line number note in the first block. */ - for (insn = BASIC_BLOCK (0)->end; + for (insn = ENTRY_BLOCK_PTR->next_bb->end; insn != prologue_end && insn; insn = PREV_INSN (insn)) if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) @@ -7891,7 +7906,7 @@ reposition_prologue_and_epilogue_notes (f) break; } } - + if (last) { rtx next; @@ -7956,122 +7971,14 @@ reposition_prologue_and_epilogue_notes (f) #endif /* HAVE_prologue or HAVE_epilogue */ } -/* Mark P for GC. */ - -static void -mark_function_status (p) - struct function *p; -{ - struct var_refs_queue *q; - struct temp_slot *t; - int i; - rtx *r; - - if (p == 0) - return; - - ggc_mark_rtx (p->arg_offset_rtx); - - if (p->x_parm_reg_stack_loc) - for (i = p->x_max_parm_reg, r = p->x_parm_reg_stack_loc; - i > 0; --i, ++r) - ggc_mark_rtx (*r); - - ggc_mark_rtx (p->return_rtx); - ggc_mark_rtx (p->x_cleanup_label); - ggc_mark_rtx (p->x_return_label); - ggc_mark_rtx (p->x_save_expr_regs); - ggc_mark_rtx (p->x_stack_slot_list); - ggc_mark_rtx (p->x_parm_birth_insn); - ggc_mark_rtx (p->x_tail_recursion_label); - ggc_mark_rtx (p->x_tail_recursion_reentry); - ggc_mark_rtx (p->internal_arg_pointer); - ggc_mark_rtx (p->x_arg_pointer_save_area); - ggc_mark_tree (p->x_rtl_expr_chain); - ggc_mark_rtx (p->x_last_parm_insn); - ggc_mark_tree (p->x_context_display); - ggc_mark_tree (p->x_trampoline_list); - ggc_mark_rtx (p->epilogue_delay_list); - ggc_mark_rtx (p->x_clobber_return_insn); - - for (t = p->x_temp_slots; t != 0; t = t->next) - { - ggc_mark (t); - ggc_mark_rtx (t->slot); - ggc_mark_rtx (t->address); - ggc_mark_tree (t->rtl_expr); - ggc_mark_tree (t->type); - } - - for (q = p->fixup_var_refs_queue; q != 0; q = q->next) - { - ggc_mark (q); - ggc_mark_rtx (q->modified); - } - - ggc_mark_rtx (p->x_nonlocal_goto_handler_slots); - ggc_mark_rtx (p->x_nonlocal_goto_handler_labels); - ggc_mark_rtx (p->x_nonlocal_goto_stack_level); - ggc_mark_tree (p->x_nonlocal_labels); - - mark_hard_reg_initial_vals (p); -} - -/* Mark the struct function pointed to by *ARG for GC, if it is not - NULL. This is used to mark the current function and the outer - function chain. */ - -static void -maybe_mark_struct_function (arg) - void *arg; -{ - struct function *f = *(struct function **) arg; - - if (f == 0) - return; - - ggc_mark_struct_function (f); -} - -/* Mark a struct function * for GC. This is called from ggc-common.c. */ - -void -ggc_mark_struct_function (f) - struct function *f; -{ - ggc_mark (f); - ggc_mark_tree (f->decl); - - mark_function_status (f); - mark_eh_status (f->eh); - mark_stmt_status (f->stmt); - mark_expr_status (f->expr); - mark_emit_status (f->emit); - mark_varasm_status (f->varasm); - - if (mark_machine_status) - (*mark_machine_status) (f); - if (mark_lang_status) - (*mark_lang_status) (f); - - if (f->original_arg_vector) - ggc_mark_rtvec ((rtvec) f->original_arg_vector); - if (f->original_decl_initial) - ggc_mark_tree (f->original_decl_initial); - if (f->outer) - ggc_mark_struct_function (f->outer); -} - /* Called once, at initialization, to initialize function.c. */ void init_function_once () { - ggc_add_root (&cfun, 1, sizeof cfun, maybe_mark_struct_function); - ggc_add_root (&outer_function_chain, 1, sizeof outer_function_chain, - maybe_mark_struct_function); - VARRAY_INT_INIT (prologue, 0, "prologue"); VARRAY_INT_INIT (epilogue, 0, "epilogue"); VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue"); } + +#include "gt-function.h" -- cgit v1.1