aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/cgraph.h7
-rw-r--r--gcc/final.c117
-rw-r--r--gcc/regs.h4
4 files changed, 139 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7ec8e44..5264478 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+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.
+
2014-05-28 Georg-Johann Lay <avr@gjlay.de>
PR libgcc/61152
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 8556e2d..94a8f25 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 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;
+}
diff --git a/gcc/regs.h b/gcc/regs.h
index c8c978b..be81db4 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 */