This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][06/10] -fuse-caller-save - Collect register usage information
- From: Tom de Vries <tom at codesourcery dot com>
- To: Vladimir Makarov <vmakarov at redhat dot com>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Sat, 30 Mar 2013 10:11:35 -0700
- Subject: [PATCH][06/10] -fuse-caller-save - Collect register usage information
Vladimir,
This patch adds analysis in pass_final to track which hard registers are set or
clobbered by the function body, and stores that information in a
struct cgraph_node.
Thanks,
-Tom
2013-03-30 Radovan Obradovic <robradovic@mips.com>
Tom de Vries <tom@codesourcery.com>
* cgraph.h (struct cgraph_node): Add function_used_regs,
function_used_regs_initialized 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_node)
(get_call_reg_set_usage): New function.
(rest_of_handle_final): Use collect_fn_hard_reg_usage.
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 8ab7ae1..2132d91 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -251,6 +251,15 @@ struct GTY(()) cgraph_node {
/* Unique id of the node. */
int uid;
+ /* 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 initialized. */
+ unsigned function_used_regs_initialized: 1;
+ /* Set if function_used_regs is valid. */
+ unsigned function_used_regs_valid: 1;
+
/* Set when decl is an abstract function pointed to by the
ABSTRACT_DECL_ORIGIN of a reachable function. */
unsigned abstract_and_needed : 1;
diff --git a/gcc/final.c b/gcc/final.c
index d25b8e0..4e0fd01 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "tree.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "tm_p.h"
#include "regs.h"
@@ -56,7 +57,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"
@@ -222,6 +222,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. */
@@ -4328,6 +4329,8 @@ rest_of_handle_final (void)
rtx x;
const char *fnname;
+ collect_fn_hard_reg_usage ();
+
/* Get the function's name, as described by its RTL. This may be
different from the DECL_NAME name used in the source file. */
@@ -4584,3 +4587,121 @@ struct rtl_opt_pass pass_clean_state =
0 /* todo_flags_finish */
}
};
+
+/* Collect hard register usage for the current function. */
+
+static void
+collect_fn_hard_reg_usage (void)
+{
+ rtx insn;
+ int i;
+ struct cgraph_node *node;
+ struct hard_reg_set_container other_usage;
+
+ if (!flag_use_caller_save)
+ return;
+
+ node = cgraph_get_node (current_function_decl);
+ gcc_assert (node != NULL);
+
+ gcc_assert (!node->function_used_regs_initialized);
+ node->function_used_regs_initialized = 1;
+
+ 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
+
+ CLEAR_HARD_REG_SET (other_usage.set);
+ targetm.fn_other_hard_reg_usage (&other_usage);
+ IOR_HARD_REG_SET (node->function_used_regs, other_usage.set);
+
+ 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;
+
+ if (!flag_use_caller_save)
+ return NULL_TREE;
+
+ 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;
+}
+
+static struct cgraph_node *
+get_call_cgraph_node (rtx insn)
+{
+ tree fndecl;
+
+ if (insn == NULL_RTX)
+ return NULL;
+
+ fndecl = get_call_fndecl (insn);
+ if (fndecl == NULL_TREE
+ || !targetm.binds_local_p (fndecl))
+ return NULL;
+
+ return cgraph_get_node (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)
+{
+ struct cgraph_node *node = get_call_cgraph_node (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;
+ }
+ else
+ {
+ COPY_HARD_REG_SET (*reg_set, default_set);
+ return false;
+ }
+}
diff --git a/gcc/regs.h b/gcc/regs.h
index 090d6b6..ec71ad4 100644
--- a/gcc/regs.h
+++ b/gcc/regs.h
@@ -421,4 +421,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 */