diff options
author | dberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-06-11 18:02:15 +0000 |
---|---|---|
committer | dberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-06-11 18:02:15 +0000 |
commit | 3072d30e7983a3ca5ad030f1f98a5c39bcc2c07b (patch) | |
tree | fdb9e9f8a0700a2713dc690fed1a2cf20dae8392 /gcc/function.c | |
parent | 8ceb1bfd33bc40bf0cbe1fab8903c2c31efd10ee (diff) | |
download | gcc-3072d30e7983a3ca5ad030f1f98a5c39bcc2c07b.tar.gz |
Merge dataflow branch into mainline
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@125624 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/function.c')
-rw-r--r-- | gcc/function.c | 128 |
1 files changed, 111 insertions, 17 deletions
diff --git a/gcc/function.c b/gcc/function.c index 7d2063c3a22..10fe7febe6c 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -63,6 +63,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tree-gimple.h" #include "tree-pass.h" #include "predict.h" +#include "df.h" +#include "timevar.h" #include "vecprim.h" #ifndef LOCAL_ALIGNMENT @@ -100,7 +102,7 @@ int current_function_is_leaf; /* Nonzero if function being compiled doesn't modify the stack pointer (ignoring the prologue and epilogue). This is only valid after - life_analysis has run. */ + pass_stack_ptr_mod has run. */ int current_function_sp_is_unchanging; /* Nonzero if the function being compiled is a leaf function which only @@ -3485,13 +3487,32 @@ pad_below (struct args_size *offset_ptr, enum machine_mode passed_mode, tree siz } } -/* Walk the tree of blocks describing the binding levels within a function - and warn about variables the might be killed by setjmp or vfork. - This is done after calling flow_analysis and before global_alloc - clobbers the pseudo-regs to hard regs. */ -void -setjmp_vars_warning (tree block) +/* True if register REGNO was alive at a place where `setjmp' was + called and was set more than once or is an argument. Such regs may + be clobbered by `longjmp'. */ + +static bool +regno_clobbered_at_setjmp (bitmap setjmp_crosses, int regno) +{ + /* There appear to be cases where some local vars never reach the + backend but have bogus regnos. */ + if (regno >= max_reg_num ()) + return false; + + return ((REG_N_SETS (regno) > 1 + || REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR), regno)) + && REGNO_REG_SET_P (setjmp_crosses, regno)); +} + +/* Walk the tree of blocks describing the binding levels within a + function and warn about variables the might be killed by setjmp or + vfork. This is done after calling flow_analysis before register + allocation since that will clobber the pseudo-regs to hard + regs. */ + +static void +setjmp_vars_warning (bitmap setjmp_crosses, tree block) { tree decl, sub; @@ -3500,32 +3521,47 @@ setjmp_vars_warning (tree block) if (TREE_CODE (decl) == VAR_DECL && DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)) - && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) + && regno_clobbered_at_setjmp (setjmp_crosses, REGNO (DECL_RTL (decl)))) warning (OPT_Wclobbered, "variable %q+D might be clobbered by" " %<longjmp%> or %<vfork%>", decl); } for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) - setjmp_vars_warning (sub); + setjmp_vars_warning (setjmp_crosses, sub); } /* Do the appropriate part of setjmp_vars_warning but for arguments instead of local variables. */ -void -setjmp_args_warning (void) +static void +setjmp_args_warning (bitmap setjmp_crosses) { tree decl; for (decl = DECL_ARGUMENTS (current_function_decl); decl; decl = TREE_CHAIN (decl)) if (DECL_RTL (decl) != 0 && REG_P (DECL_RTL (decl)) - && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) + && regno_clobbered_at_setjmp (setjmp_crosses, REGNO (DECL_RTL (decl)))) warning (OPT_Wclobbered, "argument %q+D might be clobbered by %<longjmp%> or %<vfork%>", decl); } +/* Generate warning messages for variables live across setjmp. */ + +void +generate_setjmp_warnings (void) +{ + bitmap setjmp_crosses = regstat_get_setjmp_crosses (); + + if (n_basic_blocks == NUM_FIXED_BLOCKS + || bitmap_empty_p (setjmp_crosses)) + return; + + setjmp_vars_warning (setjmp_crosses, DECL_INITIAL (current_function_decl)); + setjmp_args_warning (setjmp_crosses); +} + /* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks. */ @@ -4328,6 +4364,14 @@ expand_function_end (void) if (flag_exceptions) sjlj_emit_function_exit_after (get_last_insn ()); } + else + { + /* We want to ensure that instructions that may trap are not + moved into the epilogue by scheduling, because we don't + always emit unwind information for the epilogue. */ + if (flag_non_call_exceptions) + emit_insn (gen_blockage ()); + } /* If this is an implementation of throw, do what's necessary to communicate between __builtin_eh_return and the epilogue. */ @@ -4782,7 +4826,7 @@ keep_stack_depressed (rtx insns) && !fixed_regs[regno] && TEST_HARD_REG_BIT (regs_invalidated_by_call, regno) && !REGNO_REG_SET_P - (EXIT_BLOCK_PTR->il.rtl->global_live_at_start, regno) + (DF_LR_IN (EXIT_BLOCK_PTR), regno) && !refers_to_regno_p (regno, end_hard_regno (Pmode, regno), info.equiv_reg_src, NULL) @@ -4993,8 +5037,8 @@ emit_equiv_load (struct epi_info *p) this into place with notes indicating where the prologue ends and where the epilogue begins. Update the basic block information when possible. */ -void -thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) +static void +thread_prologue_and_epilogue_insns (void) { int inserted = 0; edge e; @@ -5016,6 +5060,11 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) seq = gen_prologue (); emit_insn (seq); + /* Insert an explicit USE for the frame pointer + if the profiling is on and the frame pointer is required. */ + if (current_function_profile && frame_pointer_needed) + emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); + /* Retain a map of the prologue insns. */ record_insns (seq, &prologue); prologue_end = emit_note (NOTE_INSN_PROLOGUE_END); @@ -5254,13 +5303,18 @@ epilogue_done: } } #endif + + /* Threading the prologue and epilogue changes the artificial refs + in the entry and exit blocks. */ + epilogue_completed = 1; + df_update_entry_exit_and_calls (); } /* Reposition the prologue-end and epilogue-begin notes after instruction scheduling and delayed branch scheduling. */ void -reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) +reposition_prologue_and_epilogue_notes (void) { #if defined (HAVE_prologue) || defined (HAVE_epilogue) rtx insn, last, note; @@ -5273,7 +5327,7 @@ reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED) /* 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. */ - for (insn = f; insn; insn = NEXT_INSN (insn)) + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { if (NOTE_P (insn)) { @@ -5354,6 +5408,13 @@ current_function_name (void) { return lang_hooks.decl_printable_name (cfun->decl, 2); } + +/* Returns the raw (mangled) name of the current function. */ +const char * +current_function_assembler_name (void) +{ + return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)); +} static unsigned int @@ -5411,5 +5472,38 @@ struct tree_opt_pass pass_leaf_regs = 0 /* letter */ }; +static unsigned int +rest_of_handle_thread_prologue_and_epilogue (void) +{ + if (optimize) + cleanup_cfg (CLEANUP_EXPENSIVE); + /* On some machines, the prologue and epilogue code, or parts thereof, + can be represented as RTL. Doing so lets us schedule insns between + it and the rest of the code and also allows delayed branch + scheduling to operate in the epilogue. */ + + thread_prologue_and_epilogue_insns (); + return 0; +} + +struct tree_opt_pass pass_thread_prologue_and_epilogue = +{ + "pro_and_epilogue", /* name */ + NULL, /* gate */ + rest_of_handle_thread_prologue_and_epilogue, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_THREAD_PROLOGUE_AND_EPILOGUE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + TODO_verify_flow, /* todo_flags_start */ + TODO_dump_func | + TODO_df_finish | + TODO_ggc_collect, /* todo_flags_finish */ + 'w' /* letter */ +}; + #include "gt-function.h" |