]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
-fuse-caller-save - Collect register usage information
authorRadovan Obradovic <robradovic@mips.com>
Wed, 28 May 2014 09:43:11 +0000 (09:43 +0000)
committerTom de Vries <vries@gcc.gnu.org>
Wed, 28 May 2014 09:43:11 +0000 (09:43 +0000)
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

gcc/ChangeLog
gcc/cgraph.h
gcc/final.c
gcc/regs.h

index 7ec8e447ed3c0377e95e4922a65d7e796aa3bad8..5264478cf6a43a82728b7a6cf41891f4848275ef 100644 (file)
@@ -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
index 8556e2d1774b54e7f812fad94556969abac06d91..94a8f252c47c41666acf4ad4ad06f8818b87f4f8 100644 (file)
@@ -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)
index 54386a69ee71cfa41a355c376e8be757b6b33f7b..f75edd5b3303f47cadd40a40974fa59ca63eeeb6 100644 (file)
@@ -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);
 \f
 /* 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;
+}
index c8c978b24de74899a5f6a81cdd9753002cb0898d..be81db46a7e46e2c3c40231750cb4af03955dcef 100644 (file)
@@ -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 */