From 5a5a3bc5fa14664be26748c11325021b6b6f8e74 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:19:49 +0000 Subject: [PATCH] Add a function for getting the ABI of a call insn target 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 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 --- gcc/ChangeLog | 64 +++++++++++++++++++++ gcc/caller-save.c | 16 ++++-- gcc/cfgcleanup.c | 10 ++-- gcc/cgraph.c | 7 ++- gcc/cgraph.h | 2 +- gcc/config/aarch64/aarch64.c | 23 +++----- gcc/df-scan.c | 8 +-- gcc/doc/tm.texi | 23 ++++---- gcc/doc/tm.texi.in | 4 +- gcc/final.c | 104 +++++++---------------------------- gcc/function-abi.cc | 25 ++++++++- gcc/function-abi.h | 3 + gcc/ira-lives.c | 10 ++-- gcc/lra-lives.c | 9 ++- gcc/postreload.c | 8 ++- gcc/regcprop.c | 8 +-- gcc/regs.h | 4 -- gcc/resource.c | 11 ++-- gcc/rtl.h | 10 ++-- gcc/rtlanal.c | 18 ++++++ gcc/target.def | 27 +++++---- gcc/targhooks.c | 5 -- gcc/targhooks.h | 2 - gcc/var-tracking.c | 7 +-- 24 files changed, 221 insertions(+), 187 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 812dadbc8e9..43c34559df2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,67 @@ +2019-09-30 Richard Sandiford + + * 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 * target.def (fntype_abi): New target hook. diff --git a/gcc/caller-save.c b/gcc/caller-save.c index b63e5683fae..10b67370de5 100644 --- a/gcc/caller-save.c +++ b/gcc/caller-save.c @@ -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++) diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 17fa1de68ef..329fa0cc901 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -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; diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 8615e2eca36..19158f08818 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -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 (); + { + node->rtl = ggc_cleared_alloc (); + node->rtl->function_used_regs = reg_class_contents[ALL_REGS]; + } return node->rtl; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 195e6e9a96e..c35b6b97516 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -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. */ diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 211459c29c4..71cdce3033c 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -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 \ diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 9b08bdca0f6..7ca1050f789 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -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 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 0f79d382379..33997a5c7a0 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -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 diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index ed605c05f4b..55fb5d4175a 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -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 diff --git a/gcc/final.c b/gcc/final.c index ae8ff22894f..7cf9ef1effd 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -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 *); /* 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; } diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index c77989a1b08..e2c35b6a274 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -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; } diff --git a/gcc/function-abi.h b/gcc/function-abi.h index 05e502e1013..c8f3f291a88 100644 --- a/gcc/function-abi.h +++ b/gcc/function-abi.h @@ -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 diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c index 166bd7b9b0c..e24831a207c 100644 --- a/gcc/ira-lives.c +++ b/gcc/ira-lives.c @@ -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 diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index 6f081598cb4..b84d6461c4c 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -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 diff --git a/gcc/postreload.c b/gcc/postreload.c index 73b0afab3a1..467df7bb0b6 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -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)) diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 4dc82a70545..4879063ea69 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -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, - ®s_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)) diff --git a/gcc/regs.h b/gcc/regs.h index 4634abc7ece..821979ec672 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -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 */ diff --git a/gcc/resource.c b/gcc/resource.c index 2d30e08a4d3..c66b6e3ee32 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -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 (x); rtx link; - HARD_REG_SET regs; res->cc = res->memory = 1; - get_call_reg_set_usage (call_insn, ®s, 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, - ®s_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. */ diff --git a/gcc/rtl.h b/gcc/rtl.h index b75b3ed6759..d798562cb31 100644 --- 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, diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 28b399cfc44..9c70eee4ccb 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -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. diff --git a/gcc/target.def b/gcc/target.def index 803c7a35825..adf7a96e419 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -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 diff --git a/gcc/targhooks.c b/gcc/targhooks.c index ed77afb1da5..d2e3ff662b6 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -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" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 5aba67660f8..d4c3563e825 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -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 */ diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 6c26b61dd16..3d069e41323 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -116,6 +116,7 @@ #include "rtl-iter.h" #include "fibonacci_heap.h" #include "print-rtl.h" +#include "function-abi.h" typedef fibonacci_heap bb_heap_t; typedef fibonacci_node 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) -- 2.30.2