[03/32] Add a function for getting the ABI of a call insn target

Message ID mpt5zlyzmbs.fsf@arm.com
State New
Headers show
Series
  • Support multiple ABIs in the same translation unit
Related show

Commit Message

Richard Sandiford Sept. 11, 2019, 7:04 p.m.
This patch replaces get_call_reg_set_usage with call_insn_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-11  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* target.def (call_insn_abi): New hook.
	(remove_extra_call_preserved_regs): Delete.
	* doc/tm.texi.in (TARGET_CALL_INSN_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_call_insn_abi): New function.
	(TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
	(TARGET_CALL_INSN_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 (call_insn_abi): Declare.
	(target_function_abi_info): Mention call_insn_abi.
	* function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar
	way to get_call_reg_set_usage did.
	(call_insn_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 call_insn_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 call_insn_abi
	instead of get_call_reg_set_usage.
	* cfgcleanup.c: Include function-abi.h.
	(old_insns_match_p): Use call_insn_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 call_insn_abi instead of
	get_call_reg_set_usage.
	* ira-lives.c: Include function-abi.h.
	(process_bb_node_lives): Use call_insn_abi instead of
	get_call_reg_set_usage.
	* lra-lives.c: Include function-abi.h.
	(process_bb_lives): Use call_insn_abi instead of
	get_call_reg_set_usage.
	* postreload.c: Include function-abi.h.
	(reload_combine): Use call_insn_abi instead of get_call_reg_set_usage.
	* regcprop.c: Include function-abi.h.
	(copyprop_hardreg_forward_1): Use call_insn_abi instead of
	get_call_reg_set_usage.
	* resource.c: Include function-abi.h.
	(mark_set_resources, mark_target_live_regs): Use call_insn_abi
	instead of get_call_reg_set_usage.
	* var-tracking.c: Include function-abi.h.
	(dataflow_set_clear_at_call): Use call_insn_abi
	instead of get_call_reg_set_usage.

Comments

Richard Sandiford Sept. 25, 2019, 3:38 p.m. | #1
Richard Sandiford <richard.sandiford@arm.com> writes:
> This patch replaces get_call_reg_set_usage with call_insn_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.


On reflection, I think insn_callee_abi would be a better name for the
function than call_insn_abi, since it should make it clearer that the
function returns the ABI of the target function.  In future we could
have expr_callee_abi for CALL_EXPRs.

Also, after Segher's comments for 10/32, I've used "callee_abi" as
the name of temporary variables, instead of just "abi".

I've made the same change for later patches (except where I've posted
new versions instead), but it didn't seem worth spamming the lists
with that.

Tested as before.

Richard

PS. Ping for the series :-)


2019-09-25  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.

Index: gcc/target.def
===================================================================
--- gcc/target.def	2019-09-25 16:23:04.000000000 +0100
+++ gcc/target.def	2019-09-25 16:23:05.092580444 +0100
@@ -4952,6 +4952,19 @@ interoperability between several ABIs in
  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: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	2019-09-25 16:23:04.000000000 +0100
+++ gcc/doc/tm.texi.in	2019-09-25 16:23:05.088580476 +0100
@@ -1711,13 +1711,13 @@ must be defined.  Modern ports should de
 @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: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	2019-09-25 16:23:04.000000000 +0100
+++ gcc/doc/tm.texi	2019-09-25 16:23:05.084580502 +0100
@@ -1905,6 +1905,17 @@ descriptor.  Targets only need to define
 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
 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: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	2019-09-25 16:23:04.000000000 +0100
+++ gcc/targhooks.h	2019-09-25 16:23:05.092580444 +0100
@@ -281,7 +281,5 @@ extern tree default_preferred_else_value
 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: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/targhooks.c	2019-09-25 16:23:05.092580444 +0100
@@ -2363,9 +2363,4 @@ default_speculation_safe_value (machine_
   return result;
 }
 
-void
-default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
-{
-}
-
 #include "gt-targhooks.h"
Index: gcc/config/aarch64/aarch64.c
===================================================================
--- gcc/config/aarch64/aarch64.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/config/aarch64/aarch64.c	2019-09-25 16:23:05.080580530 +0100
@@ -1877,7 +1877,7 @@ aarch64_reg_save_mode (tree fndecl, unsi
    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
@@ -20924,9 +20918,8 @@ #define TARGET_MODES_TIEABLE_P aarch64_m
 #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: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2019-09-25 16:23:04.000000000 +0100
+++ gcc/rtl.h	2019-09-25 16:23:05.092580444 +0100
@@ -3438,6 +3438,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);
@@ -4389,14 +4390,11 @@ extern tree GTY(()) global_regs_decl[FIR
    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: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/rtlanal.c	2019-09-25 16:23:05.092580444 +0100
@@ -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;
+}
 
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
Index: gcc/function-abi.h
===================================================================
--- gcc/function-abi.h	2019-09-25 16:23:04.000000000 +0100
+++ gcc/function-abi.h	2019-09-25 16:23:05.088580476 +0100
@@ -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 @@ #define eh_edge_abi default_function_abi
 
 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: gcc/function-abi.cc
===================================================================
--- gcc/function-abi.cc	2019-09-25 16:23:04.000000000 +0100
+++ gcc/function-abi.cc	2019-09-25 16:23:05.088580476 +0100
@@ -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: gcc/regs.h
===================================================================
--- gcc/regs.h	2019-09-25 16:23:04.000000000 +0100
+++ gcc/regs.h	2019-09-25 16:23:05.088580476 +0100
@@ -383,8 +383,4 @@ range_in_hard_reg_set_p (const_hard_reg_
   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: gcc/final.c
===================================================================
--- gcc/final.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/final.c	2019-09-25 16:23:05.088580476 +0100
@@ -81,6 +81,7 @@ #define INCLUDE_ALGORITHM /* reverse */
 #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 *);
 
 /* 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: gcc/caller-save.c
===================================================================
--- gcc/caller-save.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/caller-save.c	2019-09-25 16:23:05.072580590 +0100
@@ -37,6 +37,7 @@ Software Foundation; either version 3, o
 #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: gcc/cfgcleanup.c
===================================================================
--- gcc/cfgcleanup.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/cfgcleanup.c	2019-09-25 16:23:05.076580558 +0100
@@ -54,6 +54,7 @@ Software Foundation; either version 3, o
 #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_UN
 	    }
 	}
 
-      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: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h	2019-09-25 16:23:04.000000000 +0100
+++ gcc/cgraph.h	2019-09-25 16:23:05.076580558 +0100
@@ -1379,7 +1379,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cg
   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: gcc/cgraph.c
===================================================================
--- gcc/cgraph.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/cgraph.c	2019-09-25 16:23:05.076580558 +0100
@@ -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: gcc/df-scan.c
===================================================================
--- gcc/df-scan.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/df-scan.c	2019-09-25 16:23:05.080580530 +0100
@@ -35,7 +35,7 @@ Software Foundation; either version 3, o
 #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_re
   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_re
 			       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: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/ira-lives.c	2019-09-25 16:23:05.088580476 +0100
@@ -33,6 +33,7 @@ Software Foundation; either version 3, o
 #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_nod
 		  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: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/lra-lives.c	2019-09-25 16:23:05.088580476 +0100
@@ -43,6 +43,7 @@ Software Foundation; either version 3, o
 #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 &c
 	    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: gcc/postreload.c
===================================================================
--- gcc/postreload.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/postreload.c	2019-09-25 16:23:05.088580476 +0100
@@ -40,6 +40,7 @@ Software Foundation; either version 3, o
 #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: gcc/regcprop.c
===================================================================
--- gcc/regcprop.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/regcprop.c	2019-09-25 16:23:05.088580476 +0100
@@ -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
 	  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
 		}
 	    }
 
-	  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: gcc/resource.c
===================================================================
--- gcc/resource.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/resource.c	2019-09-25 16:23:05.088580476 +0100
@@ -30,6 +30,7 @@ Software Foundation; either version 3, o
 #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 resour
 	{
 	  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,
 		 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: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	2019-09-25 16:23:04.000000000 +0100
+++ gcc/var-tracking.c	2019-09-25 16:23:05.092580444 +0100
@@ -116,6 +116,7 @@
 #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
 {
   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)
Jeff Law Sept. 30, 2019, 3:52 p.m. | #2
On 9/25/19 9:38 AM, Richard Sandiford wrote:
> Richard Sandiford <richard.sandiford@arm.com> writes:

>> This patch replaces get_call_reg_set_usage with call_insn_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.

> 

> On reflection, I think insn_callee_abi would be a better name for the

> function than call_insn_abi, since it should make it clearer that the

> function returns the ABI of the target function.  In future we could

> have expr_callee_abi for CALL_EXPRs.

> 

> Also, after Segher's comments for 10/32, I've used "callee_abi" as

> the name of temporary variables, instead of just "abi".

> 

> I've made the same change for later patches (except where I've posted

> new versions instead), but it didn't seem worth spamming the lists

> with that.

> 

> Tested as before.

> 

> Richard

> 

> PS. Ping for the series :-)

> 

> 

> 2019-09-25  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.

> 

OK.  I think that's the whole set, right?

There were a ton of guality issues over the last couple weeks in the
tester, but those were somewhat expected due to a prior patchkit.  The
affected targets have new baseline results in my tester, so if anything
goes nuts as a result of your patches it should be fairly obvious.

Jeff
Richard Sandiford Sept. 30, 2019, 4:32 p.m. | #3
Jeff Law <law@redhat.com> writes:
> On 9/25/19 9:38 AM, Richard Sandiford wrote:

>> Richard Sandiford <richard.sandiford@arm.com> writes:

>>> This patch replaces get_call_reg_set_usage with call_insn_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.

>> 

>> On reflection, I think insn_callee_abi would be a better name for the

>> function than call_insn_abi, since it should make it clearer that the

>> function returns the ABI of the target function.  In future we could

>> have expr_callee_abi for CALL_EXPRs.

>> 

>> Also, after Segher's comments for 10/32, I've used "callee_abi" as

>> the name of temporary variables, instead of just "abi".

>> 

>> I've made the same change for later patches (except where I've posted

>> new versions instead), but it didn't seem worth spamming the lists

>> with that.

>> 

>> Tested as before.

>> 

>> Richard

>> 

>> PS. Ping for the series :-)

>> 

>> 

>> 2019-09-25  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.

>> 

> OK.  I think that's the whole set, right?


Yep, all committed now :-)  Thanks again for the reviews.

> There were a ton of guality issues over the last couple weeks in the

> tester, but those were somewhat expected due to a prior patchkit.  The

> affected targets have new baseline results in my tester, so if anything

> goes nuts as a result of your patches it should be fairly obvious.


There was certainly an extra guality failure on aarch64-linux-gnu with
this series, think it was:

gcc.dg/guality/pr41616-1.c   -O2 -flto -fuse-linker-plugin -fno-fat-lto-object

Will be interesting to see what effect it has on other targets.

Richard
Jeff Law Sept. 30, 2019, 4:46 p.m. | #4
On 9/30/19 10:32 AM, Richard Sandiford wrote:
> Jeff Law <law@redhat.com> writes:

>> On 9/25/19 9:38 AM, Richard Sandiford wrote:

>>> Richard Sandiford <richard.sandiford@arm.com> writes:

>>>> This patch replaces get_call_reg_set_usage with call_insn_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.

>>>

>>> On reflection, I think insn_callee_abi would be a better name for the

>>> function than call_insn_abi, since it should make it clearer that the

>>> function returns the ABI of the target function.  In future we could

>>> have expr_callee_abi for CALL_EXPRs.

>>>

>>> Also, after Segher's comments for 10/32, I've used "callee_abi" as

>>> the name of temporary variables, instead of just "abi".

>>>

>>> I've made the same change for later patches (except where I've posted

>>> new versions instead), but it didn't seem worth spamming the lists

>>> with that.

>>>

>>> Tested as before.

>>>

>>> Richard

>>>

>>> PS. Ping for the series :-)

>>>

>>>

>>> 2019-09-25  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.

>>>

>> OK.  I think that's the whole set, right?

> 

> Yep, all committed now :-)  Thanks again for the reviews.

> 

>> There were a ton of guality issues over the last couple weeks in the

>> tester, but those were somewhat expected due to a prior patchkit.  The

>> affected targets have new baseline results in my tester, so if anything

>> goes nuts as a result of your patches it should be fairly obvious.

> 

> There was certainly an extra guality failure on aarch64-linux-gnu with

> this series, think it was:

> 

> gcc.dg/guality/pr41616-1.c   -O2 -flto -fuse-linker-plugin -fno-fat-lto-object

> 

> Will be interesting to see what effect it has on other targets.

Noted.  I'll pass them along rather than ignoring and forcing new baselines.

jeff

Patch

Index: gcc/target.def
===================================================================
--- gcc/target.def	2019-09-11 19:47:20.406290945 +0100
+++ gcc/target.def	2019-09-11 19:47:24.422262645 +0100
@@ -4901,6 +4901,19 @@  interoperability between several ABIs in
  const predefined_function_abi &, (const_tree type),
  NULL)
 
+DEFHOOK
+(call_insn_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{call_insn_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,
@@ -5783,20 +5796,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: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	2019-09-11 19:47:20.402290974 +0100
+++ gcc/doc/tm.texi.in	2019-09-11 19:47:24.414262702 +0100
@@ -1711,13 +1711,13 @@  must be defined.  Modern ports should de
 @cindex call-saved register
 @hook TARGET_FNTYPE_ABI
 
+@hook TARGET_CALL_INSN_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: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	2019-09-11 19:47:20.402290974 +0100
+++ gcc/doc/tm.texi	2019-09-11 19:47:24.414262702 +0100
@@ -1905,6 +1905,17 @@  descriptor.  Targets only need to define
 interoperability between several ABIs in the same translation unit.
 @end deftypefn
 
+@deftypefn {Target Hook} {const predefined_function_abi &} TARGET_CALL_INSN_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{call_insn_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
 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: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	2019-09-09 17:51:55.848574716 +0100
+++ gcc/targhooks.h	2019-09-11 19:47:24.422262645 +0100
@@ -281,7 +281,5 @@  extern tree default_preferred_else_value
 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: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	2019-09-09 17:51:55.848574716 +0100
+++ gcc/targhooks.c	2019-09-11 19:47:24.422262645 +0100
@@ -2363,9 +2363,4 @@  default_speculation_safe_value (machine_
   return result;
 }
 
-void
-default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
-{
-}
-
 #include "gt-targhooks.h"
Index: gcc/config/aarch64/aarch64.c
===================================================================
--- gcc/config/aarch64/aarch64.c	2019-09-11 19:47:20.398291002 +0100
+++ gcc/config/aarch64/aarch64.c	2019-09-11 19:47:24.410262730 +0100
@@ -1877,7 +1877,7 @@  aarch64_reg_save_mode (tree fndecl, unsi
    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_CALL_INSN_ABI.  */
 
-void
-aarch64_remove_extra_call_preserved_regs (rtx_insn *insn,
-					  HARD_REG_SET *return_set)
+const predefined_function_abi &
+aarch64_call_insn_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
@@ -20806,9 +20800,8 @@  #define TARGET_MODES_TIEABLE_P aarch64_m
 #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_CALL_INSN_ABI
+#define TARGET_CALL_INSN_ABI aarch64_call_insn_abi
 
 #undef TARGET_RETURN_CALL_WITH_MAX_CLOBBERS
 #define TARGET_RETURN_CALL_WITH_MAX_CLOBBERS \
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2019-09-10 17:18:59.955982709 +0100
+++ gcc/rtl.h	2019-09-11 19:47:24.418262673 +0100
@@ -3420,6 +3420,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);
@@ -4371,14 +4372,11 @@  extern tree GTY(()) global_regs_decl[FIR
    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: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	2019-09-10 19:56:32.577268091 +0100
+++ gcc/rtlanal.c	2019-09-11 19:47:24.418262673 +0100
@@ -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;
+}
 
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
Index: gcc/function-abi.h
===================================================================
--- gcc/function-abi.h	2019-09-11 19:47:07.490381964 +0100
+++ gcc/function-abi.h	2019-09-11 19:47:24.418262673 +0100
@@ -224,6 +224,8 @@  struct target_function_abi_info
      * crtl->abi is the ABI of the function that we are currently
        compiling to rtl.
 
+     * call_insn_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 @@  #define eh_edge_abi default_function_abi
 
 extern const predefined_function_abi &fntype_abi (const_tree);
 extern function_abi fndecl_abi (const_tree);
+extern function_abi call_insn_abi (const rtx_insn *);
 
 #endif
Index: gcc/function-abi.cc
===================================================================
--- gcc/function-abi.cc	2019-09-11 19:47:20.402290974 +0100
+++ gcc/function-abi.cc	2019-09-11 19:47:24.414262702 +0100
@@ -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
+call_insn_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.call_insn_abi)
+    return targetm.calls.call_insn_abi (insn);
+
+  return default_function_abi;
 }
Index: gcc/regs.h
===================================================================
--- gcc/regs.h	2019-09-09 18:58:28.864430335 +0100
+++ gcc/regs.h	2019-09-11 19:47:24.418262673 +0100
@@ -383,8 +383,4 @@  range_in_hard_reg_set_p (const_hard_reg_
   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: gcc/final.c
===================================================================
--- gcc/final.c	2019-09-10 19:56:32.569268148 +0100
+++ gcc/final.c	2019-09-11 19:47:24.414262702 +0100
@@ -81,6 +81,7 @@  #define INCLUDE_ALGORITHM /* reverse */
 #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 *);
 
 /* 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
+	  |= call_insn_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: gcc/caller-save.c
===================================================================
--- gcc/caller-save.c	2019-09-10 19:56:32.557268232 +0100
+++ gcc/caller-save.c	2019-09-11 19:47:24.402262786 +0100
@@ -37,6 +37,7 @@  Software Foundation; either version 3, o
 #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 = call_insn_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 = call_insn_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 = call_insn_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: gcc/cfgcleanup.c
===================================================================
--- gcc/cfgcleanup.c	2019-09-10 19:56:32.561268204 +0100
+++ gcc/cfgcleanup.c	2019-09-11 19:47:24.402262786 +0100
@@ -54,6 +54,7 @@  Software Foundation; either version 3, o
 #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_UN
 	    }
 	}
 
-      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 = call_insn_abi (i1).full_reg_clobbers ();
+      HARD_REG_SET i2_used = call_insn_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: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h	2019-08-05 17:46:19.305733957 +0100
+++ gcc/cgraph.h	2019-09-11 19:47:24.406262758 +0100
@@ -1368,7 +1368,7 @@  struct GTY((tag ("SYMTAB_FUNCTION"))) cg
   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: gcc/cgraph.c
===================================================================
--- gcc/cgraph.c	2019-09-05 08:49:26.265772215 +0100
+++ gcc/cgraph.c	2019-09-11 19:47:24.406262758 +0100
@@ -1908,7 +1908,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);
@@ -1923,7 +1923,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: gcc/df-scan.c
===================================================================
--- gcc/df-scan.c	2019-09-10 19:56:45.353177919 +0100
+++ gcc/df-scan.c	2019-09-11 19:47:24.410262730 +0100
@@ -35,7 +35,7 @@  Software Foundation; either version 3, o
 #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_re
   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 abi = call_insn_abi (insn_info->insn);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -3118,7 +3116,7 @@  df_get_call_refs (class df_collection_re
 			       NULL, bb, insn_info, DF_REF_REG_DEF, flags);
 	    }
 	}
-      else if (TEST_HARD_REG_BIT (fn_reg_set_usage, i)
+      else if (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: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	2019-09-10 19:56:45.357177891 +0100
+++ gcc/ira-lives.c	2019-09-11 19:47:24.418262673 +0100
@@ -33,6 +33,7 @@  Software Foundation; either version 3, o
 #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_nod
 		  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
+		    = call_insn_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: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c	2019-09-10 19:56:45.357177891 +0100
+++ gcc/lra-lives.c	2019-09-11 19:47:24.418262673 +0100
@@ -43,6 +43,7 @@  Software Foundation; either version 3, o
 #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 &c
 	    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
+		= call_insn_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: gcc/postreload.c
===================================================================
--- gcc/postreload.c	2019-09-10 19:56:45.357177891 +0100
+++ gcc/postreload.c	2019-09-11 19:47:24.418262673 +0100
@@ -40,6 +40,7 @@  Software Foundation; either version 3, o
 #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 = call_insn_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: gcc/regcprop.c
===================================================================
--- gcc/regcprop.c	2019-09-09 18:58:51.472270712 +0100
+++ gcc/regcprop.c	2019-09-11 19:47:24.418262673 +0100
@@ -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
 	  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
 		}
 	    }
 
-	  get_call_reg_set_usage (insn,
-				  &regs_invalidated_by_this_call,
-				  regs_invalidated_by_call);
+	  function_abi abi = call_insn_abi (insn);
 	  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-	    if ((TEST_HARD_REG_BIT (regs_invalidated_by_this_call, regno)
+	    if ((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: gcc/resource.c
===================================================================
--- gcc/resource.c	2019-09-09 18:59:20.864063196 +0100
+++ gcc/resource.c	2019-09-11 19:47:24.418262673 +0100
@@ -30,6 +30,7 @@  Software Foundation; either version 3, o
 #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 resour
 	{
 	  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 |= call_insn_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,
 		 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
+		    = call_insn_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: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	2019-09-09 18:58:51.476270683 +0100
+++ gcc/var-tracking.c	2019-09-11 19:47:24.422262645 +0100
@@ -116,6 +116,7 @@ 
 #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
 {
   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 abi = call_insn_abi (call_insn);
 
-  EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
+  EXECUTE_IF_SET_IN_HARD_REG_SET (abi.full_reg_clobbers (), 0, r, hrsi)
     var_regno_delete (set, r);
 
   if (MAY_HAVE_DEBUG_BIND_INSNS)