From 27c07cc5d06c0f74d147c14c6a4b0b071266e774 Mon Sep 17 00:00:00 2001 From: Radovan Obradovic Date: Wed, 28 May 2014 09:43:11 +0000 Subject: [PATCH] -fuse-caller-save - Collect register usage information 2014-05-28 Radovan Obradovic Tom de Vries * cgraph.h (struct cgraph_rtl_info): Add function_used_regs and function_used_regs_valid fields. * final.c: Move include of hard-reg-set.h to before rtl.h to declare find_all_hard_reg_sets. (collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_rtl_info) (get_call_reg_set_usage): New function. (rest_of_handle_final): Use collect_fn_hard_reg_usage. * regs.h (get_call_reg_set_usage): Declare. Co-Authored-By: Tom de Vries From-SVN: r211006 --- gcc/ChangeLog | 12 ++++++ gcc/cgraph.h | 7 +++ gcc/final.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++- gcc/regs.h | 4 ++ 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7ec8e447ed3..5264478cf6a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2014-05-28 Radovan Obradovic + Tom de Vries + + * cgraph.h (struct cgraph_rtl_info): Add function_used_regs + and function_used_regs_valid fields. + * final.c: Move include of hard-reg-set.h to before rtl.h to declare + find_all_hard_reg_sets. + (collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_rtl_info) + (get_call_reg_set_usage): New function. + (rest_of_handle_final): Use collect_fn_hard_reg_usage. + * regs.h (get_call_reg_set_usage): Declare. + 2014-05-28 Georg-Johann Lay PR libgcc/61152 diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 8556e2d1774..94a8f252c47 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -249,6 +249,13 @@ struct GTY(()) cgraph_global_info { struct GTY(()) cgraph_rtl_info { unsigned int preferred_incoming_stack_boundary; + + /* Call unsaved hard registers really used by the corresponding + function (including ones used by functions called by the + function). */ + HARD_REG_SET function_used_regs; + /* Set if function_used_regs is valid. */ + unsigned function_used_regs_valid: 1; }; /* Represent which DECL tree (or reference to such tree) diff --git a/gcc/final.c b/gcc/final.c index 54386a69ee7..f75edd5b330 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "varasm.h" +#include "hard-reg-set.h" #include "rtl.h" #include "tm_p.h" #include "regs.h" @@ -57,7 +58,6 @@ along with GCC; see the file COPYING3. If not see #include "recog.h" #include "conditions.h" #include "flags.h" -#include "hard-reg-set.h" #include "output.h" #include "except.h" #include "function.h" @@ -224,6 +224,7 @@ static int alter_cond (rtx); static int final_addr_vec_align (rtx); #endif static int align_fuzz (rtx, rtx, int, unsigned); +static void collect_fn_hard_reg_usage (void); /* Initialize data in final at the beginning of a compilation. */ @@ -4442,6 +4443,8 @@ rest_of_handle_final (void) assemble_start_function (current_function_decl, fnname); final_start_function (get_insns (), asm_out_file, optimize); final (get_insns (), asm_out_file, optimize); + if (flag_use_caller_save) + collect_fn_hard_reg_usage (); final_end_function (); /* The IA-64 ".handlerdata" directive must be issued before the ".endp" @@ -4740,3 +4743,115 @@ make_pass_clean_state (gcc::context *ctxt) { return new pass_clean_state (ctxt); } + +/* Collect hard register usage for the current function. */ + +static void +collect_fn_hard_reg_usage (void) +{ + rtx insn; + int i; + struct cgraph_rtl_info *node; + + /* ??? To be removed when all the ports have been fixed. */ + if (!targetm.call_fusage_contains_non_callee_clobbers) + return; + + node = cgraph_rtl_info (current_function_decl); + gcc_assert (node != NULL); + + for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn)) + { + HARD_REG_SET insn_used_regs; + + if (!NONDEBUG_INSN_P (insn)) + continue; + + find_all_hard_reg_sets (insn, &insn_used_regs, false); + + if (CALL_P (insn) + && !get_call_reg_set_usage (insn, &insn_used_regs, call_used_reg_set)) + { + CLEAR_HARD_REG_SET (node->function_used_regs); + return; + } + + IOR_HARD_REG_SET (node->function_used_regs, insn_used_regs); + } + + /* Be conservative - mark fixed and global registers as used. */ + IOR_HARD_REG_SET (node->function_used_regs, fixed_reg_set); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (global_regs[i]) + SET_HARD_REG_BIT (node->function_used_regs, i); + +#ifdef STACK_REGS + /* Handle STACK_REGS conservatively, since the df-framework does not + provide accurate information for them. */ + + for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) + SET_HARD_REG_BIT (node->function_used_regs, i); +#endif + + node->function_used_regs_valid = 1; +} + +/* Get the declaration of the function called by INSN. */ + +static tree +get_call_fndecl (rtx insn) +{ + rtx note, datum; + + note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX); + if (note == NULL_RTX) + return NULL_TREE; + + datum = XEXP (note, 0); + if (datum != NULL_RTX) + return SYMBOL_REF_DECL (datum); + + return NULL_TREE; +} + +/* Return the cgraph_rtl_info of the function called by INSN. Returns NULL for + call targets that can be overwritten. */ + +static struct cgraph_rtl_info * +get_call_cgraph_rtl_info (rtx insn) +{ + tree fndecl; + + if (insn == NULL_RTX) + return NULL; + + fndecl = get_call_fndecl (insn); + if (fndecl == NULL_TREE + || !decl_binds_to_current_def_p (fndecl)) + return NULL; + + return cgraph_rtl_info (fndecl); +} + +/* Find hard registers used by function call instruction INSN, and return them + in REG_SET. Return DEFAULT_SET in REG_SET if not found. */ + +bool +get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set, + HARD_REG_SET default_set) +{ + if (flag_use_caller_save) + { + struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn); + if (node != NULL + && node->function_used_regs_valid) + { + COPY_HARD_REG_SET (*reg_set, node->function_used_regs); + AND_HARD_REG_SET (*reg_set, default_set); + return true; + } + } + + COPY_HARD_REG_SET (*reg_set, default_set); + return false; +} diff --git a/gcc/regs.h b/gcc/regs.h index c8c978b24de..be81db46a7e 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -419,4 +419,8 @@ range_in_hard_reg_set_p (const HARD_REG_SET set, unsigned regno, int nregs) return true; } +/* Get registers used by given function call instruction. */ +extern bool get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set, + HARD_REG_SET default_set); + #endif /* GCC_REGS_H */ -- 2.30.2