Add a function for getting the ABI of a call insn target
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 30 Sep 2019 16:19:49 +0000 (16:19 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 30 Sep 2019 16:19:49 +0000 (16:19 +0000)
This patch replaces get_call_reg_set_usage with insn_callee_abi,
which returns the ABI of the target of a call insn.  The ABI's
full_reg_clobbers corresponds to regs_invalidated_by_call,
whereas many callers instead passed call_used_or_fixed_regs, i.e.:

  (regs_invalidated_by_call | fixed_reg_set)

The patch slavishly preserves the "| fixed_reg_set" for these callers;
later patches will clean this up.

2019-09-30  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* target.def (insn_callee_abi): New hook.
(remove_extra_call_preserved_regs): Delete.
* doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro.
(TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
* doc/tm.texi: Regenerate.
* targhooks.h (default_remove_extra_call_preserved_regs): Delete.
* targhooks.c (default_remove_extra_call_preserved_regs): Delete.
* config/aarch64/aarch64.c (aarch64_simd_call_p): Constify the
insn argument.
(aarch64_remove_extra_call_preserved_regs): Delete.
(aarch64_insn_callee_abi): New function.
(TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
(TARGET_INSN_CALLEE_ABI): New macro.
* rtl.h (get_call_fndecl): Declare.
(cgraph_rtl_info): Fix formatting.  Tweak comment for
function_used_regs.  Remove function_used_regs_valid.
* rtlanal.c (get_call_fndecl): Moved from final.c
* function-abi.h (insn_callee_abi): Declare.
(target_function_abi_info): Mention insn_callee_abi.
* function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar
way to get_call_reg_set_usage did.
(insn_callee_abi): New function.
* regs.h (get_call_reg_set_usage): Delete.
* final.c: Include function-abi.h.
(collect_fn_hard_reg_usage): Add fixed and stack registers to
function_used_regs before the main loop rather than afterwards.
Use insn_callee_abi instead of get_call_reg_set_usage.  Exit early
if function_used_regs ends up not being useful.
(get_call_fndecl): Move to rtlanal.c
(get_call_cgraph_rtl_info, get_call_reg_set_usage): Delete.
* caller-save.c: Include function-abi.h.
(setup_save_areas, save_call_clobbered_regs): Use insn_callee_abi
instead of get_call_reg_set_usage.
* cfgcleanup.c: Include function-abi.h.
(old_insns_match_p): Use insn_callee_abi instead of
get_call_reg_set_usage.
* cgraph.h (cgraph_node::rtl_info): Take a const_tree instead of
a tree.
* cgraph.c (cgraph_node::rtl_info): Likewise.  Initialize
function_used_regs.
* df-scan.c: Include function-abi.h.
(df_get_call_refs): Use insn_callee_abi instead of
get_call_reg_set_usage.
* ira-lives.c: Include function-abi.h.
(process_bb_node_lives): Use insn_callee_abi instead of
get_call_reg_set_usage.
* lra-lives.c: Include function-abi.h.
(process_bb_lives): Use insn_callee_abi instead of
get_call_reg_set_usage.
* postreload.c: Include function-abi.h.
(reload_combine): Use insn_callee_abi instead of
get_call_reg_set_usage.
* regcprop.c: Include function-abi.h.
(copyprop_hardreg_forward_1): Use insn_callee_abi instead of
get_call_reg_set_usage.
* resource.c: Include function-abi.h.
(mark_set_resources, mark_target_live_regs): Use insn_callee_abi
instead of get_call_reg_set_usage.
* var-tracking.c: Include function-abi.h.
(dataflow_set_clear_at_call): Use insn_callee_abi instead of
get_call_reg_set_usage.

From-SVN: r276309

24 files changed:
gcc/ChangeLog
gcc/caller-save.c
gcc/cfgcleanup.c
gcc/cgraph.c
gcc/cgraph.h
gcc/config/aarch64/aarch64.c
gcc/df-scan.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/final.c
gcc/function-abi.cc
gcc/function-abi.h
gcc/ira-lives.c
gcc/lra-lives.c
gcc/postreload.c
gcc/regcprop.c
gcc/regs.h
gcc/resource.c
gcc/rtl.h
gcc/rtlanal.c
gcc/target.def
gcc/targhooks.c
gcc/targhooks.h
gcc/var-tracking.c

index 812dadbc8e948ddc455a4b976bf7a8748c98702e..43c34559df22bfd89b455cdf8311e5d13082b147 100644 (file)
@@ -1,3 +1,67 @@
+2019-09-30  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * target.def (insn_callee_abi): New hook.
+       (remove_extra_call_preserved_regs): Delete.
+       * doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro.
+       (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
+       * doc/tm.texi: Regenerate.
+       * targhooks.h (default_remove_extra_call_preserved_regs): Delete.
+       * targhooks.c (default_remove_extra_call_preserved_regs): Delete.
+       * config/aarch64/aarch64.c (aarch64_simd_call_p): Constify the
+       insn argument.
+       (aarch64_remove_extra_call_preserved_regs): Delete.
+       (aarch64_insn_callee_abi): New function.
+       (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
+       (TARGET_INSN_CALLEE_ABI): New macro.
+       * rtl.h (get_call_fndecl): Declare.
+       (cgraph_rtl_info): Fix formatting.  Tweak comment for
+       function_used_regs.  Remove function_used_regs_valid.
+       * rtlanal.c (get_call_fndecl): Moved from final.c
+       * function-abi.h (insn_callee_abi): Declare.
+       (target_function_abi_info): Mention insn_callee_abi.
+       * function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar
+       way to get_call_reg_set_usage did.
+       (insn_callee_abi): New function.
+       * regs.h (get_call_reg_set_usage): Delete.
+       * final.c: Include function-abi.h.
+       (collect_fn_hard_reg_usage): Add fixed and stack registers to
+       function_used_regs before the main loop rather than afterwards.
+       Use insn_callee_abi instead of get_call_reg_set_usage.  Exit early
+       if function_used_regs ends up not being useful.
+       (get_call_fndecl): Move to rtlanal.c
+       (get_call_cgraph_rtl_info, get_call_reg_set_usage): Delete.
+       * caller-save.c: Include function-abi.h.
+       (setup_save_areas, save_call_clobbered_regs): Use insn_callee_abi
+       instead of get_call_reg_set_usage.
+       * cfgcleanup.c: Include function-abi.h.
+       (old_insns_match_p): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+       * cgraph.h (cgraph_node::rtl_info): Take a const_tree instead of
+       a tree.
+       * cgraph.c (cgraph_node::rtl_info): Likewise.  Initialize
+       function_used_regs.
+       * df-scan.c: Include function-abi.h.
+       (df_get_call_refs): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+       * ira-lives.c: Include function-abi.h.
+       (process_bb_node_lives): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+       * lra-lives.c: Include function-abi.h.
+       (process_bb_lives): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+       * postreload.c: Include function-abi.h.
+       (reload_combine): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+       * regcprop.c: Include function-abi.h.
+       (copyprop_hardreg_forward_1): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+       * resource.c: Include function-abi.h.
+       (mark_set_resources, mark_target_live_regs): Use insn_callee_abi
+       instead of get_call_reg_set_usage.
+       * var-tracking.c: Include function-abi.h.
+       (dataflow_set_clear_at_call): Use insn_callee_abi instead of
+       get_call_reg_set_usage.
+
 2019-09-30  Richard Sandiford  <richard.sandiford@arm.com>
 
        * target.def (fntype_abi): New target hook.
index b63e5683faeb3dc40075b293b0ff5e79896341fe..10b67370de53e828b8fda52a495ca1b34261db31 100644 (file)
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "rtl-iter.h"
 #include "target.h"
+#include "function-abi.h"
 
 #define MOVE_MAX_WORDS (MOVE_MAX / UNITS_PER_WORD)
 
@@ -426,7 +427,9 @@ setup_save_areas (void)
       freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
       REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
                               &chain->live_throughout);
-      get_call_reg_set_usage (insn, &used_regs, call_used_or_fixed_regs);
+      used_regs = insn_callee_abi (insn).full_reg_clobbers ();
+      /* ??? This preserves traditional behavior; it might not be needed.  */
+      used_regs |= fixed_reg_set;
 
       /* Record all registers set in this call insn.  These don't
         need to be saved.  N.B. the call insn might set a subreg
@@ -509,7 +512,10 @@ setup_save_areas (void)
 
          REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
                                   &chain->live_throughout);
-         get_call_reg_set_usage (insn, &used_regs, call_used_or_fixed_regs);
+         used_regs = insn_callee_abi (insn).full_reg_clobbers ();
+         /* ??? This preserves traditional behavior; it might not
+            be needed.  */
+         used_regs |= fixed_reg_set;
 
          /* Record all registers set in this call insn.  These don't
             need to be saved.  N.B. the call insn might set a subreg
@@ -838,8 +844,10 @@ save_call_clobbered_regs (void)
                                     | this_insn_sets
                                     | hard_regs_saved);
              hard_regs_to_save &= savable_regs;
-             get_call_reg_set_usage (insn, &call_def_reg_set,
-                                     call_used_or_fixed_regs);
+             call_def_reg_set = insn_callee_abi (insn).full_reg_clobbers ();
+             /* ??? This preserves traditional behavior; it might not
+                be needed.  */
+             call_def_reg_set |= fixed_reg_set;
              hard_regs_to_save &= call_def_reg_set;
 
              for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
index 17fa1de68efae8c662007f1b06c4928e42311f26..329fa0cc901412e74d64807dac5776985f585738 100644 (file)
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "rtl-iter.h"
 #include "regs.h"
+#include "function-abi.h"
 
 #define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK)
 
@@ -1226,10 +1227,11 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx_insn *i1, rtx_insn *i2)
            }
        }
 
-      HARD_REG_SET i1_used, i2_used;
-
-      get_call_reg_set_usage (i1, &i1_used, call_used_or_fixed_regs);
-      get_call_reg_set_usage (i2, &i2_used, call_used_or_fixed_regs);
+      HARD_REG_SET i1_used = insn_callee_abi (i1).full_reg_clobbers ();
+      HARD_REG_SET i2_used = insn_callee_abi (i2).full_reg_clobbers ();
+      /* ??? This preserves traditional behavior; it might not be needed.  */
+      i1_used |= fixed_reg_set;
+      i2_used |= fixed_reg_set;
 
       if (i1_used != i2_used)
         return dir_none;
index 8615e2eca36d3a5201fd65665b6eeacfb6f6c3ee..19158f08818e319a1377f376e062f43495ef3cd2 100644 (file)
@@ -1839,7 +1839,7 @@ cgraph_node::local_info (tree decl)
 /* Return local info for the compiled function.  */
 
 cgraph_rtl_info *
-cgraph_node::rtl_info (tree decl)
+cgraph_node::rtl_info (const_tree decl)
 {
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
   cgraph_node *node = get (decl);
@@ -1854,7 +1854,10 @@ cgraph_node::rtl_info (tree decl)
     return NULL;
   /* Allocate if it doesn't exist.  */
   if (node->rtl == NULL)
-    node->rtl = ggc_cleared_alloc<cgraph_rtl_info> ();
+    {
+      node->rtl = ggc_cleared_alloc<cgraph_rtl_info> ();
+      node->rtl->function_used_regs = reg_class_contents[ALL_REGS];
+    }
   return node->rtl;
 }
 
index 195e6e9a96e9da1ee1c6cd0d0dfa2796def1bb63..c35b6b975169d06b60f82674ec409b149d697261 100644 (file)
@@ -1379,7 +1379,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
   static cgraph_local_info *local_info (tree decl);
 
   /* Return local info for the compiled function.  */
-  static struct cgraph_rtl_info *rtl_info (tree);
+  static struct cgraph_rtl_info *rtl_info (const_tree);
 
   /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
      Return NULL if there's no such node.  */
index 211459c29c477870d4877639a2f89618e833e127..71cdce3033c33e86df6ec12b1ea1b2e9542ab8de 100644 (file)
@@ -1877,7 +1877,7 @@ aarch64_reg_save_mode (tree fndecl, unsigned regno)
    the function.  */
 
 static bool
-aarch64_simd_call_p (rtx_insn *insn)
+aarch64_simd_call_p (const rtx_insn *insn)
 {
   rtx symbol;
   rtx call;
@@ -1895,20 +1895,14 @@ aarch64_simd_call_p (rtx_insn *insn)
   return aarch64_simd_decl_p (fndecl);
 }
 
-/* Implement TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS.  If INSN calls
-   a function that uses the SIMD ABI, take advantage of the extra
-   call-preserved registers that the ABI provides.  */
+/* Implement TARGET_INSN_CALLEE_ABI.  */
 
-void
-aarch64_remove_extra_call_preserved_regs (rtx_insn *insn,
-                                         HARD_REG_SET *return_set)
+const predefined_function_abi &
+aarch64_insn_callee_abi (const rtx_insn *insn)
 {
   if (aarch64_simd_call_p (insn))
-    {
-      for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-       if (FP_SIMD_SAVED_REGNUM_P (regno))
-         CLEAR_HARD_REG_BIT (*return_set, regno);
-    }
+    return aarch64_simd_abi ();
+  return default_function_abi;
 }
 
 /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED.  The callee only saves
@@ -21004,9 +20998,8 @@ aarch64_libgcc_floating_mode_supported_p
 #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \
   aarch64_hard_regno_call_part_clobbered
 
-#undef TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS
-#define TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS \
-  aarch64_remove_extra_call_preserved_regs
+#undef TARGET_INSN_CALLEE_ABI
+#define TARGET_INSN_CALLEE_ABI aarch64_insn_callee_abi
 
 #undef TARGET_RETURN_CALL_WITH_MAX_CLOBBERS
 #define TARGET_RETURN_CALL_WITH_MAX_CLOBBERS \
index 9b08bdca0f68c4806f26c49a8d4aeebc0a3da468..7ca1050f789fb7c558e9a45e84866d9d5c49ba89 100644 (file)
@@ -35,7 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.h.  */
 #include "dumpfile.h"
 #include "calls.h"
-
+#include "function-abi.h"
 
 /* The set of hard registers in eliminables[i].from. */
 
@@ -3088,13 +3088,11 @@ df_get_call_refs (class df_collection_rec *collection_rec,
   bool is_sibling_call;
   unsigned int i;
   HARD_REG_SET defs_generated;
-  HARD_REG_SET fn_reg_set_usage;
 
   CLEAR_HARD_REG_SET (defs_generated);
   df_find_hard_reg_defs (PATTERN (insn_info->insn), &defs_generated);
   is_sibling_call = SIBLING_CALL_P (insn_info->insn);
-  get_call_reg_set_usage (insn_info->insn, &fn_reg_set_usage,
-                         regs_invalidated_by_call);
+  function_abi callee_abi = insn_callee_abi (insn_info->insn);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -3118,7 +3116,7 @@ df_get_call_refs (class df_collection_rec *collection_rec,
                               NULL, bb, insn_info, DF_REF_REG_DEF, flags);
            }
        }
-      else if (TEST_HARD_REG_BIT (fn_reg_set_usage, i)
+      else if (callee_abi.clobbers_full_reg_p (i)
               /* no clobbers for regs that are the result of the call */
               && !TEST_HARD_REG_BIT (defs_generated, i)
               && (!is_sibling_call
index 0f79d382379f0f10fbe17198d34bb16628cbedea..33997a5c7a0823d9215067b089a4f2cfb9577c59 100644 (file)
@@ -1905,6 +1905,17 @@ descriptor.  Targets only need to define this hook if they support
 interoperability between several ABIs in the same translation unit.
 @end deftypefn
 
+@deftypefn {Target Hook} {const predefined_function_abi &} TARGET_INSN_CALLEE_ABI (const rtx_insn *@var{insn})
+This hook returns a description of the ABI used by the target of
+call instruction @var{insn}; see the definition of
+@code{predefined_function_abi} for details of the ABI descriptor.
+Only the global function @code{insn_callee_abi} should call this hook
+directly.
+
+Targets only need to define this hook if they support
+interoperability between several ABIs in the same translation unit.
+@end deftypefn
+
 @cindex call-used register
 @cindex call-clobbered register
 @cindex call-saved register
@@ -1921,18 +1932,6 @@ The default implementation returns false, which is correct
 for targets that don't have partly call-clobbered registers.
 @end deftypefn
 
-@deftypefn {Target Hook} void TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS (rtx_insn *@var{insn}, HARD_REG_SET *@var{used_regs})
-This hook removes registers from the set of call-clobbered registers
- in @var{used_regs} if, contrary to the default rules, something guarantees
- that @samp{insn} preserves those registers.  For example, some targets
- support variant ABIs in which functions preserve more registers than
- normal functions would.  Removing those extra registers from @var{used_regs}
- can lead to better register allocation.
- The default implementation does nothing, which is always safe.
- Defining the hook is purely an optimization.
-@end deftypefn
-
 @deftypefn {Target Hook} {rtx_insn *} TARGET_RETURN_CALL_WITH_MAX_CLOBBERS (rtx_insn *@var{call_1}, rtx_insn *@var{call_2})
 This hook returns a pointer to the call that partially clobbers the
 most registers.  If a platform supports multiple ABIs where the registers
index ed605c05f4be64f096d1b88c2def1313ff99ab45..55fb5d4175a5921d48aa3d4e22edfffb0ea46dc9 100644 (file)
@@ -1711,13 +1711,13 @@ must be defined.  Modern ports should define @code{CALL_REALLY_USED_REGISTERS}.
 @cindex call-saved register
 @hook TARGET_FNTYPE_ABI
 
+@hook TARGET_INSN_CALLEE_ABI
+
 @cindex call-used register
 @cindex call-clobbered register
 @cindex call-saved register
 @hook TARGET_HARD_REGNO_CALL_PART_CLOBBERED
 
-@hook TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS
-
 @hook TARGET_RETURN_CALL_WITH_MAX_CLOBBERS
 
 @hook TARGET_GET_MULTILIB_ABI_NAME
index ae8ff22894fb239800f1b12b10a0e95155ee4ef3..7cf9ef1effda2870b67e26c5b9e2e2a3a7e5289b 100644 (file)
@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
+#include "function-abi.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data declarations.  */
@@ -230,7 +231,6 @@ static int alter_cond (rtx);
 #endif
 static int align_fuzz (rtx, rtx, int, unsigned);
 static void collect_fn_hard_reg_usage (void);
-static tree get_call_fndecl (rtx_insn *);
 \f
 /* Initialize data in final at the beginning of a compilation.  */
 
@@ -4994,7 +4994,16 @@ collect_fn_hard_reg_usage (void)
   if (!targetm.call_fusage_contains_non_callee_clobbers)
     return;
 
-  CLEAR_HARD_REG_SET (function_used_regs);
+  /* Be conservative - mark fixed and global registers as used.  */
+  function_used_regs = fixed_reg_set;
+
+#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 (function_used_regs, i);
+#endif
 
   for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
     {
@@ -5005,96 +5014,23 @@ collect_fn_hard_reg_usage (void)
 
       if (CALL_P (insn)
          && !self_recursive_call_p (insn))
-       {
-         if (!get_call_reg_set_usage (insn, &insn_used_regs,
-                                      call_used_or_fixed_regs))
-           return;
-
-         function_used_regs |= insn_used_regs;
-       }
+       function_used_regs
+         |= insn_callee_abi (insn).full_and_partial_reg_clobbers ();
 
       find_all_hard_reg_sets (insn, &insn_used_regs, false);
       function_used_regs |= insn_used_regs;
-    }
 
-  /* Be conservative - mark fixed and global registers as used.  */
-  function_used_regs |= fixed_reg_set;
-
-#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 (function_used_regs, i);
-#endif
+      if (hard_reg_set_subset_p (crtl->abi->full_and_partial_reg_clobbers (),
+                                function_used_regs))
+       return;
+    }
 
-  /* The information we have gathered is only interesting if it exposes a
-     register from the call_used_regs that is not used in this function.  */
-  if (hard_reg_set_subset_p (call_used_or_fixed_regs, function_used_regs))
-    return;
+  /* Mask out fully-saved registers, so that they don't affect equality
+     comparisons between function_abis.  */
+  function_used_regs &= crtl->abi->full_and_partial_reg_clobbers ();
 
   node = cgraph_node::rtl_info (current_function_decl);
   gcc_assert (node != NULL);
 
   node->function_used_regs = function_used_regs;
-  node->function_used_regs_valid = 1;
-}
-
-/* Get the declaration of the function called by INSN.  */
-
-static tree
-get_call_fndecl (rtx_insn *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 *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_node::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 *insn, HARD_REG_SET *reg_set,
-                       HARD_REG_SET default_set)
-{
-  if (flag_ipa_ra)
-    {
-      struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn);
-      if (node != NULL
-         && node->function_used_regs_valid)
-       {
-         *reg_set = node->function_used_regs & default_set;
-         return true;
-       }
-    }
-  *reg_set = default_set;
-  targetm.remove_extra_call_preserved_regs (insn, reg_set);
-  return false;
 }
index c77989a1b08d6ab4ed2193f6d460722e6e0d8fee..e2c35b6a274cb87c4560779c4350c5585595622e 100644 (file)
@@ -143,5 +143,28 @@ function_abi
 fndecl_abi (const_tree fndecl)
 {
   gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
-  return fntype_abi (TREE_TYPE (fndecl));
+  const predefined_function_abi &base_abi = fntype_abi (TREE_TYPE (fndecl));
+
+  if (flag_ipa_ra && decl_binds_to_current_def_p (fndecl))
+    if (cgraph_rtl_info *info = cgraph_node::rtl_info (fndecl))
+      return function_abi (base_abi, info->function_used_regs);
+
+  return base_abi;
+}
+
+/* Return the ABI of the function called by INSN.  */
+
+function_abi
+insn_callee_abi (const rtx_insn *insn)
+{
+  gcc_assert (insn && CALL_P (insn));
+
+  if (flag_ipa_ra)
+    if (tree fndecl = get_call_fndecl (insn))
+      return fndecl_abi (fndecl);
+
+  if (targetm.calls.insn_callee_abi)
+    return targetm.calls.insn_callee_abi (insn);
+
+  return default_function_abi;
 }
index 05e502e1013d31246b5f4b17c76cfda92f4e53c3..c8f3f291a888cd9b926a0b5dccd65916c61eaddc 100644 (file)
@@ -224,6 +224,8 @@ struct target_function_abi_info
      * crtl->abi is the ABI of the function that we are currently
        compiling to rtl.
 
+     * insn_callee_abi (INSN) is the ABI used by the target of call insn INSN.
+
      * eh_edge_abi is the "ABI" used when taking an EH edge from an
        exception-throwing statement to an exception handler.  Catching
        exceptions from calls can be treated as an abnormal return from
@@ -265,5 +267,6 @@ extern target_function_abi_info *this_target_function_abi_info;
 
 extern const predefined_function_abi &fntype_abi (const_tree);
 extern function_abi fndecl_abi (const_tree);
+extern function_abi insn_callee_abi (const rtx_insn *);
 
 #endif
index 166bd7b9b0c26dd33976f01eaaba4d8b1dfa6d89..e24831a207cedfcc42256103c293e3d79ce0ba37 100644 (file)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ira.h"
 #include "ira-int.h"
 #include "sparseset.h"
+#include "function-abi.h"
 
 /* The code in this file is similar to one in global but the code
    works on the allocno basis and creates live ranges instead of
@@ -1254,10 +1255,11 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
                  ira_object_t obj = ira_object_id_map[i];
                  a = OBJECT_ALLOCNO (obj);
                  int num = ALLOCNO_NUM (a);
-                 HARD_REG_SET this_call_used_reg_set;
-
-                 get_call_reg_set_usage (insn, &this_call_used_reg_set,
-                                         call_used_or_fixed_regs);
+                 HARD_REG_SET this_call_used_reg_set
+                   = insn_callee_abi (insn).full_reg_clobbers ();
+                 /* ??? This preserves traditional behavior; it might not be
+                    needed.  */
+                 this_call_used_reg_set |= fixed_reg_set;
 
                  /* Don't allocate allocnos that cross setjmps or any
                     call, if this function receives a nonlocal
index 6f081598cb4bb6ddf40e06b2815760299cc58850..b84d6461c4cc8ecf5270f56848403f4a768d621a 100644 (file)
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.        If not see
 #include "sparseset.h"
 #include "lra-int.h"
 #include "target.h"
+#include "function-abi.h"
 
 /* Program points are enumerated by numbers from range
    0..LRA_LIVE_MAX_POINT-1.  There are approximately two times more
@@ -931,9 +932,11 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
            last_call_used_reg_set = call_used_or_fixed_regs;
          else
            {
-             HARD_REG_SET this_call_used_reg_set;
-             get_call_reg_set_usage (curr_insn, &this_call_used_reg_set,
-                                     call_used_or_fixed_regs);
+             HARD_REG_SET this_call_used_reg_set
+               = insn_callee_abi (curr_insn).full_reg_clobbers ();
+             /* ??? This preserves traditional behavior; it might not
+                be needed.  */
+             this_call_used_reg_set |= fixed_reg_set;
 
              bool flush = (! hard_reg_set_empty_p (last_call_used_reg_set)
                            && (last_call_used_reg_set
index 73b0afab3a1cdecd45d7f19cd8f65d76371f3ef8..467df7bb0b642930dc1e4f6b6a5359503bea0747 100644 (file)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cselib.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
+#include "function-abi.h"
 
 static int reload_cse_noop_set_p (rtx);
 static bool reload_cse_simplify (rtx_insn *, rtx);
@@ -1330,9 +1331,10 @@ reload_combine (void)
       if (CALL_P (insn))
        {
          rtx link;
-         HARD_REG_SET used_regs;
-
-         get_call_reg_set_usage (insn, &used_regs, call_used_or_fixed_regs);
+         HARD_REG_SET used_regs = insn_callee_abi (insn).full_reg_clobbers ();
+         /* ??? This preserves traditional behavior; it might not be
+            needed.  */
+         used_regs |= fixed_reg_set;
 
          for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
            if (TEST_HARD_REG_BIT (used_regs, r))
index 4dc82a70545b3f15d784464a918803aa2ac6dec0..4879063ea69e63d195cce3959a51ed76d4b41f24 100644 (file)
@@ -35,6 +35,7 @@
 #include "rtl-iter.h"
 #include "cfgrtl.h"
 #include "target.h"
+#include "function-abi.h"
 
 /* The following code does forward propagation of hard register copies.
    The object is to eliminate as many dependencies as possible, so that
@@ -1035,7 +1036,6 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
          unsigned int set_nregs = 0;
          unsigned int regno;
          rtx exp;
-         HARD_REG_SET regs_invalidated_by_this_call;
 
          for (exp = CALL_INSN_FUNCTION_USAGE (insn); exp; exp = XEXP (exp, 1))
            {
@@ -1053,11 +1053,9 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
                }
            }
 
-         get_call_reg_set_usage (insn,
-                                 &regs_invalidated_by_this_call,
-                                 regs_invalidated_by_call);
+         function_abi callee_abi = insn_callee_abi (insn);
          for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-           if ((TEST_HARD_REG_BIT (regs_invalidated_by_this_call, regno)
+           if ((callee_abi.clobbers_full_reg_p (regno)
                 || (targetm.hard_regno_call_part_clobbered
                     (insn, regno, vd->e[regno].mode)))
                && (regno < set_regno || regno >= set_regno + set_nregs))
index 4634abc7ece12706b9991eda0c257adeda839b56..821979ec67251fa78ce1209e89f641b7dcac0c23 100644 (file)
@@ -383,8 +383,4 @@ 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 *insn, HARD_REG_SET *reg_set,
-                                   HARD_REG_SET default_set);
-
 #endif /* GCC_REGS_H */
index 2d30e08a4d3c160ce0a48a92a0218419ce3f4224..c66b6e3ee3260b51866d895b8eb0dd2ef18c256e 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "resource.h"
 #include "insn-attr.h"
 #include "params.h"
+#include "function-abi.h"
 
 /* This structure is used to record liveness information at the targets or
    fallthrough insns of branches.  We will most likely need the information
@@ -662,12 +663,10 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
        {
          rtx_call_insn *call_insn = as_a <rtx_call_insn *> (x);
          rtx link;
-         HARD_REG_SET regs;
 
          res->cc = res->memory = 1;
 
-         get_call_reg_set_usage (call_insn, &regs, regs_invalidated_by_call);
-         res->regs |= regs;
+         res->regs |= insn_callee_abi (call_insn).full_reg_clobbers ();
 
          for (link = CALL_INSN_FUNCTION_USAGE (call_insn);
               link; link = XEXP (link, 1))
@@ -1038,10 +1037,8 @@ mark_target_live_regs (rtx_insn *insns, rtx target_maybe_return, struct resource
                 predicated instruction, or if the CALL is NORETURN.  */
              if (GET_CODE (PATTERN (real_insn)) != COND_EXEC)
                {
-                 HARD_REG_SET regs_invalidated_by_this_call;
-                 get_call_reg_set_usage (real_insn,
-                                         &regs_invalidated_by_this_call,
-                                         regs_invalidated_by_call);
+                 HARD_REG_SET regs_invalidated_by_this_call
+                   = insn_callee_abi (real_insn).full_reg_clobbers ();
                  /* CALL clobbers all call-used regs that aren't fixed except
                     sp, ap, and fp.  Do this before setting the result of the
                     call live.  */
index b75b3ed6759d96531b76d61ddbbefdd0595e4a37..d798562cb31c5b94ad62a25b2b2dce8d74cc84e0 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3447,6 +3447,7 @@ extern int rtx_unstable_p (const_rtx);
 extern bool rtx_varies_p (const_rtx, bool);
 extern bool rtx_addr_varies_p (const_rtx, bool);
 extern rtx get_call_rtx_from (const rtx_insn *);
+extern tree get_call_fndecl (const rtx_insn *);
 extern HOST_WIDE_INT get_integer_term (const_rtx);
 extern rtx get_related_value (const_rtx);
 extern bool offset_within_block_p (const_rtx, HOST_WIDE_INT);
@@ -4401,14 +4402,11 @@ extern tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER];
    Available only for functions that has been already assembled.  */
 
 struct GTY(()) cgraph_rtl_info {
-   unsigned int preferred_incoming_stack_boundary;
+  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).  */
+  /* Which registers the function clobbers, either directly or by
+     calling another function.  */
   HARD_REG_SET function_used_regs;
-  /* Set if function_used_regs is valid.  */
-  unsigned function_used_regs_valid: 1;
 };
 
 /* If loads from memories of mode MODE always sign or zero extend,
index 28b399cfc44c390f270ca6763b3b7240e2b0e77c..9c70eee4ccb1b1da765f2f80a0c90c23fb457a19 100644 (file)
@@ -822,6 +822,24 @@ get_call_rtx_from (const rtx_insn *insn)
     return x;
   return NULL_RTX;
 }
+
+/* Get the declaration of the function called by INSN.  */
+
+tree
+get_call_fndecl (const rtx_insn *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;
+}
 \f
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
index 803c7a358251859634e791d851ca64186b1b90ec..adf7a96e419ef0c52fc4c98423a218b72a8efa3f 100644 (file)
@@ -4952,6 +4952,19 @@ interoperability between several ABIs in the same translation unit.",
  const predefined_function_abi &, (const_tree type),
  NULL)
 
+DEFHOOK
+(insn_callee_abi,
+ "This hook returns a description of the ABI used by the target of\n\
+call instruction @var{insn}; see the definition of\n\
+@code{predefined_function_abi} for details of the ABI descriptor.\n\
+Only the global function @code{insn_callee_abi} should call this hook\n\
+directly.\n\
+\n\
+Targets only need to define this hook if they support\n\
+interoperability between several ABIs in the same translation unit.",
+ const predefined_function_abi &, (const rtx_insn *insn),
+ NULL)
+
 /* ??? Documenting this hook requires a GFDL license grant.  */
 DEFHOOK_UNDOC
 (internal_arg_pointer,
@@ -5834,20 +5847,6 @@ DEFHOOK
  const char *, (void),
  hook_constcharptr_void_null)
 
-DEFHOOK
-(remove_extra_call_preserved_regs,
- "This hook removes registers from the set of call-clobbered registers\n\
- in @var{used_regs} if, contrary to the default rules, something guarantees\n\
- that @samp{insn} preserves those registers.  For example, some targets\n\
- support variant ABIs in which functions preserve more registers than\n\
- normal functions would.  Removing those extra registers from @var{used_regs}\n\
- can lead to better register allocation.\n\
- \n\
- The default implementation does nothing, which is always safe.\n\
- Defining the hook is purely an optimization.",
- void, (rtx_insn *insn, HARD_REG_SET *used_regs),
- default_remove_extra_call_preserved_regs)
-
 /* Return the smallest number of different values for which it is best to
    use a jump-table instead of a tree of conditional branches.  */
 DEFHOOK
index ed77afb1da57e59bc0725dc0d6fac477391bae03..d2e3ff662b67ae4a0c2c281ec26c312c52f12847 100644 (file)
@@ -2363,9 +2363,4 @@ default_speculation_safe_value (machine_mode mode ATTRIBUTE_UNUSED,
   return result;
 }
 
-void
-default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
-{
-}
-
 #include "gt-targhooks.h"
index 5aba67660f85406b9fd475e75a3cc65b0d1952f5..d4c3563e82587feea9523a15c2dcc490dad9919e 100644 (file)
@@ -281,7 +281,5 @@ extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);
 extern bool default_have_speculation_safe_value (bool);
 extern bool speculation_safe_value_not_needed (bool);
 extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
-extern void default_remove_extra_call_preserved_regs (rtx_insn *,
-                                                     HARD_REG_SET *);
 
 #endif /* GCC_TARGHOOKS_H */
index 6c26b61dd1644990185fbf96ccb4e6cfc45f51af..3d069e41323c03fb8aaf33672eb49c9f9c3cd15b 100644 (file)
 #include "rtl-iter.h"
 #include "fibonacci_heap.h"
 #include "print-rtl.h"
+#include "function-abi.h"
 
 typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
 typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
@@ -4900,12 +4901,10 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
 {
   unsigned int r;
   hard_reg_set_iterator hrsi;
-  HARD_REG_SET invalidated_regs;
 
-  get_call_reg_set_usage (call_insn, &invalidated_regs,
-                         regs_invalidated_by_call);
+  function_abi callee_abi = insn_callee_abi (call_insn);
 
-  EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
+  EXECUTE_IF_SET_IN_HARD_REG_SET (callee_abi.full_reg_clobbers (), 0, r, hrsi)
     var_regno_delete (set, r);
 
   if (MAY_HAVE_DEBUG_BIND_INSNS)