aboutsummaryrefslogtreecommitdiff
path: root/gcc/final.c
diff options
context:
space:
mode:
authorRadovan Obradovic <robradovic@mips.com>2014-05-28 09:43:11 +0000
committerTom de Vries <vries@gcc.gnu.org>2014-05-28 09:43:11 +0000
commit27c07cc5d06c0f74d147c14c6a4b0b071266e774 (patch)
treeadc9457c04ab6c4cb81a5e67f444ea92a7ebf3e8 /gcc/final.c
parentca48e5efaee333309fcc62c9afbc65b7d5952d3d (diff)
downloadgcc-27c07cc5d06c0f74d147c14c6a4b0b071266e774.zip
gcc-27c07cc5d06c0f74d147c14c6a4b0b071266e774.tar.gz
gcc-27c07cc5d06c0f74d147c14c6a4b0b071266e774.tar.bz2
-fuse-caller-save - Collect register usage information
2014-05-28 Radovan Obradovic <robradovic@mips.com> Tom de Vries <tom@codesourcery.com> * 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 <tom@codesourcery.com> From-SVN: r211006
Diffstat (limited to 'gcc/final.c')
-rw-r--r--gcc/final.c117
1 files changed, 116 insertions, 1 deletions
diff --git a/gcc/final.c b/gcc/final.c
index 54386a6..f75edd5 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;
+}