diff options
author | Richard Henderson <rth@redhat.com> | 2009-05-29 17:33:46 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2009-05-29 17:33:46 -0700 |
commit | cd9c1ca866b6aa5041a352e0ed07ae5f91e235e5 (patch) | |
tree | f977a6cde3ef60ef5e2fd7e916cfad3c81f71215 /gcc/function.c | |
parent | 36bac386ae2339359ebcee2473192c4171c5c7df (diff) | |
download | gcc-cd9c1ca866b6aa5041a352e0ed07ae5f91e235e5.tar.gz |
cfgcleanup.c (try_crossjump_to_edge): Only skip past NOTE_INSN_BASIC_BLOCK.
* cfgcleanup.c (try_crossjump_to_edge): Only skip past
NOTE_INSN_BASIC_BLOCK.
* cfglayout.c (duplicate_insn_chain): Copy epilogue insn marks.
Duplicate NOTE_INSN_EPILOGUE_BEG notes.
* cfgrtl.c (can_delete_note_p): Allow NOTE_INSN_EPILOGUE_BEG
to be deleted.
* dwarf2out.c (struct cfa_loc): Change indirect field to bitfield,
add in_use field.
(add_cfi): Disable check redefining cfa away from drap.
(lookup_cfa_1): Add remember argument; handle remember/restore.
(lookup_cfa): Pass remember argument.
(cfa_remember): New.
(compute_barrier_args_size_1): Remove sibcall check.
(dwarf2out_frame_debug_def_cfa): New.
(dwarf2out_frame_debug_adjust_cfa): New.
(dwarf2out_frame_debug_cfa_offset): New.
(dwarf2out_frame_debug_cfa_register): New.
(dwarf2out_frame_debug_cfa_restore): New.
(dwarf2out_frame_debug): Handle REG_CFA_* notes.
(dwarf2out_begin_epilogue): New.
(dwarf2out_frame_debug_restore_state): New.
(dw_cfi_oprnd1_desc): Handle DW_CFA_remember_state,
DW_CFA_restore_state.
(output_cfi_directive): Likewise.
(convert_cfa_to_fb_loc_list): Likewise.
(dw_cfi_oprnd1_desc): Handle DW_CFA_restore.
* dwarf2out.h: Update.
* emit-rtl.c (try_split): Don't split RTX_FRAME_RELATED_P.
(copy_insn_1): Early out for null.
* final.c (final_scan_insn): Call dwarf2out_begin_epilogue
and dwarf2out_frame_debug_restore_state.
* function.c (prologue, epilogue, sibcall_epilogue): Remove.
(prologue_insn_hash, epilogue_insn_hash): New.
(free_after_compilation): Adjust freeing accordingly.
(record_insns): Create hash table if needed; push insns into
hash instead of array.
(maybe_copy_epilogue_insn): New.
(contains): Search hash table instead of array.
(sibcall_epilogue_contains): Remove.
(thread_prologue_and_epilogue_insns): Split eh_return insns
and mark them as epilogues.
(reposition_prologue_and_epilogue_notes): Rewrite epilogue
scanning in terms of basic blocks.
* insn-notes.def (CFA_RESTORE_STATE): New.
* jump.c (returnjump_p_1): Accept EH_RETURN.
(eh_returnjump_p_1, eh_returnjump_p): New.
* reg-notes.def (CFA_DEF_CFA, CFA_ADJUST_CFA, CFA_OFFSET,
CFA_REGISTER, CFA_RESTORE): New.
* rtl.def (EH_RETURN): New.
* rtl.h (eh_returnjump_p, maybe_copy_epilogue_insn): Declare.
* config/bfin/bfin.md (UNSPEC_VOLATILE_EH_RETURN): Remove.
(eh_return_internal): Use eh_return rtx; split w/ epilogue.
* config/i386/i386.c (gen_push): Update cfa state.
(pro_epilogue_adjust_stack): Add set_cfa argument. When true,
add a CFA_ADJUST_CFA note.
(ix86_dwarf_handle_frame_unspec): Remove.
(ix86_expand_prologue): Update cfa state.
(ix86_emit_restore_reg_using_pop): New.
(ix86_emit_restore_regs_using_pop): New.
(ix86_emit_leave): New.
(ix86_emit_restore_regs_using_mov): Add CFA_RESTORE notes.
(ix86_expand_epilogue): Add notes for unwinding the epilogue.
* config/i386/i386.h (struct machine_cfa_state): New.
(ix86_cfa_state): New.
* config/i386/i386.md (UNSPEC_EH_RETURN): Remove.
(eh_return_internal): Merge from eh_return_<mode>,
use eh_return rtx, split w/ epilogue.
From-SVN: r147995
Diffstat (limited to 'gcc/function.c')
-rw-r--r-- | gcc/function.c | 248 |
1 files changed, 145 insertions, 103 deletions
diff --git a/gcc/function.c b/gcc/function.c index 9d9d3ad5066..ddf08b04602 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -124,13 +124,11 @@ struct machine_function * (*init_machine_status) (void); /* The currently compiled function. */ struct function *cfun = 0; -/* These arrays record the INSN_UIDs of the prologue and epilogue insns. */ -static VEC(int,heap) *prologue; -static VEC(int,heap) *epilogue; - -/* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue - in this function. */ -static VEC(int,heap) *sibcall_epilogue; +/* These hashes record the prologue and epilogue insns. */ +static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) + htab_t prologue_insn_hash; +static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) + htab_t epilogue_insn_hash; /* Forward declarations. */ @@ -143,8 +141,8 @@ static tree *get_block_vector (tree, int *); extern tree debug_find_var_in_block_tree (tree, tree); /* We always define `record_insns' even if it's not used so that we can always export `prologue_epilogue_contains'. */ -static void record_insns (rtx, VEC(int,heap) **) ATTRIBUTE_UNUSED; -static int contains (const_rtx, VEC(int,heap) **); +static void record_insns (rtx, rtx, htab_t *) ATTRIBUTE_UNUSED; +static bool contains (const_rtx, htab_t); #ifdef HAVE_return static void emit_return_into_block (basic_block); #endif @@ -207,9 +205,9 @@ free_after_parsing (struct function *f) void free_after_compilation (struct function *f) { - VEC_free (int, heap, prologue); - VEC_free (int, heap, epilogue); - VEC_free (int, heap, sibcall_epilogue); + prologue_insn_hash = NULL; + epilogue_insn_hash = NULL; + if (crtl->emit.regno_pointer_align) free (crtl->emit.regno_pointer_align); @@ -4196,18 +4194,11 @@ init_function_start (tree subr) warning (OPT_Waggregate_return, "function returns an aggregate"); } -/* Make sure all values used by the optimization passes have sane - defaults. */ +/* Make sure all values used by the optimization passes have sane defaults. */ unsigned int init_function_for_compilation (void) { reg_renumber = 0; - - /* No prologue/epilogue insns yet. Make sure that these vectors are - empty. */ - gcc_assert (VEC_length (int, prologue) == 0); - gcc_assert (VEC_length (int, epilogue) == 0); - gcc_assert (VEC_length (int, sibcall_epilogue) == 0); return 0; } @@ -4873,16 +4864,42 @@ get_arg_pointer_save_area (void) return ret; } -/* Extend a vector that records the INSN_UIDs of INSNS - (a list of one or more insns). */ +/* Add a list of INSNS to the hash HASHP, possibly allocating HASHP + for the first time. */ static void -record_insns (rtx insns, VEC(int,heap) **vecp) +record_insns (rtx insns, rtx end, htab_t *hashp) { rtx tmp; + htab_t hash = *hashp; + + if (hash == NULL) + *hashp = hash + = htab_create_ggc (17, htab_hash_pointer, htab_eq_pointer, NULL); + + for (tmp = insns; tmp != end; tmp = NEXT_INSN (tmp)) + { + void **slot = htab_find_slot (hash, tmp, INSERT); + gcc_assert (*slot == NULL); + *slot = tmp; + } +} + +/* INSN has been duplicated as COPY, as part of duping a basic block. + If INSN is an epilogue insn, then record COPY as epilogue as well. */ - for (tmp = insns; tmp != NULL_RTX; tmp = NEXT_INSN (tmp)) - VEC_safe_push (int, heap, *vecp, INSN_UID (tmp)); +void +maybe_copy_epilogue_insn (rtx insn, rtx copy) +{ + void **slot; + + if (epilogue_insn_hash == NULL + || htab_find (epilogue_insn_hash, insn) == NULL) + return; + + slot = htab_find_slot (epilogue_insn_hash, copy, INSERT); + gcc_assert (*slot == NULL); + *slot = copy; } /* Set the locator of the insn chain starting at INSN to LOC. */ @@ -4897,52 +4914,37 @@ set_insn_locators (rtx insn, int loc) } } -/* Determine how many INSN_UIDs in VEC are part of INSN. Because we can - be running after reorg, SEQUENCE rtl is possible. */ +/* Determine if any INSNs in HASH are, or are part of, INSN. Because + we can be running after reorg, SEQUENCE rtl is possible. */ -static int -contains (const_rtx insn, VEC(int,heap) **vec) +static bool +contains (const_rtx insn, htab_t hash) { - int i, j; + if (hash == NULL) + return false; - if (NONJUMP_INSN_P (insn) - && GET_CODE (PATTERN (insn)) == SEQUENCE) + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) { - int count = 0; + int i; for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) - for (j = VEC_length (int, *vec) - 1; j >= 0; --j) - if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) - == VEC_index (int, *vec, j)) - count++; - return count; + if (htab_find (hash, XVECEXP (PATTERN (insn), 0, i))) + return true; + return false; } - else - { - for (j = VEC_length (int, *vec) - 1; j >= 0; --j) - if (INSN_UID (insn) == VEC_index (int, *vec, j)) - return 1; - } - return 0; + + return htab_find (hash, insn) != NULL; } int prologue_epilogue_contains (const_rtx insn) { - if (contains (insn, &prologue)) + if (contains (insn, prologue_insn_hash)) return 1; - if (contains (insn, &epilogue)) + if (contains (insn, epilogue_insn_hash)) return 1; return 0; } -int -sibcall_epilogue_contains (const_rtx insn) -{ - if (sibcall_epilogue) - return contains (insn, &sibcall_epilogue); - return 0; -} - #ifdef HAVE_return /* Insert gen_return at the end of block BB. This also means updating block_for_insn appropriately. */ @@ -4985,7 +4987,7 @@ thread_prologue_and_epilogue_insns (void) emit_use (hard_frame_pointer_rtx); /* Retain a map of the prologue insns. */ - record_insns (seq, &prologue); + record_insns (seq, NULL, &prologue_insn_hash); emit_note (NOTE_INSN_PROLOGUE_END); #ifndef PROFILE_BEFORE_PROLOGUE @@ -5117,6 +5119,38 @@ thread_prologue_and_epilogue_insns (void) } } #endif + + /* A small fib -- epilogue is not yet completed, but we wish to re-use + this marker for the splits of EH_RETURN patterns, and nothing else + uses the flag in the meantime. */ + epilogue_completed = 1; + +#ifdef HAVE_eh_return + /* Find non-fallthru edges that end with EH_RETURN instructions. On + some targets, these get split to a special version of the epilogue + code. In order to be able to properly annotate these with unwind + info, try to split them now. If we get a valid split, drop an + EPILOGUE_BEG note and mark the insns as epilogue insns. */ + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) + { + rtx prev, last, trial; + + if (e->flags & EDGE_FALLTHRU) + continue; + last = BB_END (e->src); + if (!eh_returnjump_p (last)) + continue; + + prev = PREV_INSN (last); + trial = try_split (PATTERN (last), last, 1); + if (trial == last) + continue; + + record_insns (NEXT_INSN (prev), NEXT_INSN (trial), &epilogue_insn_hash); + emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev); + } +#endif + /* Find the edge that falls through to EXIT. Other edges may exist due to RETURN instructions, but those don't need epilogues. There really shouldn't be a mixture -- either all should have @@ -5137,7 +5171,7 @@ thread_prologue_and_epilogue_insns (void) emit_jump_insn (seq); /* Retain a map of the epilogue insns. */ - record_insns (seq, &epilogue); + record_insns (seq, NULL, &epilogue_insn_hash); set_insn_locators (seq, epilogue_locator); seq = get_insns (); @@ -5199,6 +5233,7 @@ epilogue_done: } start_sequence (); + emit_note (NOTE_INSN_EPILOGUE_BEG); emit_insn (gen_sibcall_epilogue ()); seq = get_insns (); end_sequence (); @@ -5206,7 +5241,7 @@ epilogue_done: /* 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); + record_insns (seq, NULL, &epilogue_insn_hash); set_insn_locators (seq, epilogue_locator); emit_insn_before (seq, insn); @@ -5240,23 +5275,29 @@ epilogue_done: df_update_entry_exit_and_calls (); } -/* Reposition the prologue-end and epilogue-begin notes after instruction - scheduling and delayed branch scheduling. */ +/* Reposition the prologue-end and epilogue-begin notes after + instruction scheduling. */ void reposition_prologue_and_epilogue_notes (void) { -#if defined (HAVE_prologue) || defined (HAVE_epilogue) +#if defined (HAVE_prologue) || defined (HAVE_epilogue) \ + || defined (HAVE_sibcall_epilogue) rtx insn, last, note; - int len; + basic_block bb; - if ((len = VEC_length (int, prologue)) > 0) + /* Since the hash table is created on demand, the fact that it is + non-null is a signal that it is non-empty. */ + if (prologue_insn_hash != NULL) { + size_t len = htab_elements (prologue_insn_hash); last = 0, note = 0; - /* Scan from the beginning until we reach the last prologue insn. - We apparently can't depend on basic_block_{head,end} after - reorg has run. */ + /* Scan from the beginning until we reach the last prologue insn. */ + /* ??? While we do have the CFG intact, there are two problems: + (1) The prologue can contain loops (typically probing the stack), + which means that the end of the prologue isn't in the first bb. + (2) Sometimes the PROLOGUE_END note gets pushed into the next bb. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { if (NOTE_P (insn)) @@ -5264,7 +5305,7 @@ reposition_prologue_and_epilogue_notes (void) if (NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END) note = insn; } - else if (contains (insn, &prologue)) + else if (contains (insn, prologue_insn_hash)) { last = insn; if (--len == 0) @@ -5274,14 +5315,17 @@ reposition_prologue_and_epilogue_notes (void) if (last) { - /* Find the prologue-end note if we haven't already, and - move it to just after the last prologue insn. */ - if (note == 0) + if (note == NULL) { - for (note = last; (note = NEXT_INSN (note));) - if (NOTE_P (note) - && NOTE_KIND (note) == NOTE_INSN_PROLOGUE_END) - break; + /* Scan forward looking for the PROLOGUE_END note. It should + be right at the beginning of the block, possibly with other + insn notes that got moved there. */ + for (note = NEXT_INSN (last); ; note = NEXT_INSN (note)) + { + if (NOTE_P (note) + && NOTE_KIND (note) == NOTE_INSN_PROLOGUE_END) + break; + } } /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note. */ @@ -5291,41 +5335,39 @@ reposition_prologue_and_epilogue_notes (void) } } - if ((len = VEC_length (int, epilogue)) > 0) + if (epilogue_insn_hash != NULL) { - last = 0, note = 0; + edge_iterator ei; + edge e; - /* Scan from the end until we reach the first epilogue insn. - We apparently can't depend on basic_block_{head,end} after - reorg has run. */ - for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) { - if (NOTE_P (insn)) - { - if (NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG) - note = insn; - } - else if (contains (insn, &epilogue)) - { - last = insn; - if (--len == 0) - break; - } - } + last = 0, note = 0; + bb = e->src; - if (last) - { - /* Find the epilogue-begin note if we haven't already, and - move it to just before the first epilogue insn. */ - if (note == 0) + /* Scan from the beginning until we reach the first epilogue insn. + Take the cue for whether this is a plain or sibcall epilogue + from the kind of note we find first. */ + FOR_BB_INSNS (bb, insn) { - for (note = insn; (note = PREV_INSN (note));) - if (NOTE_P (note) - && NOTE_KIND (note) == NOTE_INSN_EPILOGUE_BEG) - break; + if (NOTE_P (insn)) + { + if (NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG) + { + note = insn; + if (last) + break; + } + } + else if (contains (insn, epilogue_insn_hash)) + { + last = insn; + if (note != NULL) + break; + } } - - if (PREV_INSN (last) != note) + + if (last && note && PREV_INSN (last) != note) reorder_insns (note, note, PREV_INSN (last)); } } |