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 <richard.sandiford@arm.com> gcc/ * target.def (insn_callee_abi): New hook. (remove_extra_call_preserved_regs): Delete. * doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro. (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete. * doc/tm.texi: Regenerate. * targhooks.h (default_remove_extra_call_preserved_regs): Delete. * targhooks.c (default_remove_extra_call_preserved_regs): Delete. * config/aarch64/aarch64.c (aarch64_simd_call_p): Constify the insn argument. (aarch64_remove_extra_call_preserved_regs): Delete. (aarch64_insn_callee_abi): New function. (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete. (TARGET_INSN_CALLEE_ABI): New macro. * rtl.h (get_call_fndecl): Declare. (cgraph_rtl_info): Fix formatting. Tweak comment for function_used_regs. Remove function_used_regs_valid. * rtlanal.c (get_call_fndecl): Moved from final.c * function-abi.h (insn_callee_abi): Declare. (target_function_abi_info): Mention insn_callee_abi. * function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar way to get_call_reg_set_usage did. (insn_callee_abi): New function. * regs.h (get_call_reg_set_usage): Delete. * final.c: Include function-abi.h. (collect_fn_hard_reg_usage): Add fixed and stack registers to function_used_regs before the main loop rather than afterwards. Use insn_callee_abi instead of get_call_reg_set_usage. Exit early if function_used_regs ends up not being useful. (get_call_fndecl): Move to rtlanal.c (get_call_cgraph_rtl_info, get_call_reg_set_usage): Delete. * caller-save.c: Include function-abi.h. (setup_save_areas, save_call_clobbered_regs): Use insn_callee_abi instead of get_call_reg_set_usage. * cfgcleanup.c: Include function-abi.h. (old_insns_match_p): Use insn_callee_abi instead of get_call_reg_set_usage. * cgraph.h (cgraph_node::rtl_info): Take a const_tree instead of a tree. * cgraph.c (cgraph_node::rtl_info): Likewise. Initialize function_used_regs. * df-scan.c: Include function-abi.h. (df_get_call_refs): Use insn_callee_abi instead of get_call_reg_set_usage. * ira-lives.c: Include function-abi.h. (process_bb_node_lives): Use insn_callee_abi instead of get_call_reg_set_usage. * lra-lives.c: Include function-abi.h. (process_bb_lives): Use insn_callee_abi instead of get_call_reg_set_usage. * postreload.c: Include function-abi.h. (reload_combine): Use insn_callee_abi instead of get_call_reg_set_usage. * regcprop.c: Include function-abi.h. (copyprop_hardreg_forward_1): Use insn_callee_abi instead of get_call_reg_set_usage. * resource.c: Include function-abi.h. (mark_set_resources, mark_target_live_regs): Use insn_callee_abi instead of get_call_reg_set_usage. * var-tracking.c: Include function-abi.h. (dataflow_set_clear_at_call): Use insn_callee_abi instead of get_call_reg_set_usage. From-SVN: r276309
This commit is contained in:
parent
002ffd3caa
commit
5a5a3bc5fa
|
@ -1,3 +1,67 @@
|
|||
2019-09-30 Richard Sandiford <richard.sandiford@arm.com>
|
||||
|
||||
* target.def (insn_callee_abi): New hook.
|
||||
(remove_extra_call_preserved_regs): Delete.
|
||||
* doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro.
|
||||
(TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
|
||||
* doc/tm.texi: Regenerate.
|
||||
* targhooks.h (default_remove_extra_call_preserved_regs): Delete.
|
||||
* targhooks.c (default_remove_extra_call_preserved_regs): Delete.
|
||||
* config/aarch64/aarch64.c (aarch64_simd_call_p): Constify the
|
||||
insn argument.
|
||||
(aarch64_remove_extra_call_preserved_regs): Delete.
|
||||
(aarch64_insn_callee_abi): New function.
|
||||
(TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete.
|
||||
(TARGET_INSN_CALLEE_ABI): New macro.
|
||||
* rtl.h (get_call_fndecl): Declare.
|
||||
(cgraph_rtl_info): Fix formatting. Tweak comment for
|
||||
function_used_regs. Remove function_used_regs_valid.
|
||||
* rtlanal.c (get_call_fndecl): Moved from final.c
|
||||
* function-abi.h (insn_callee_abi): Declare.
|
||||
(target_function_abi_info): Mention insn_callee_abi.
|
||||
* function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar
|
||||
way to get_call_reg_set_usage did.
|
||||
(insn_callee_abi): New function.
|
||||
* regs.h (get_call_reg_set_usage): Delete.
|
||||
* final.c: Include function-abi.h.
|
||||
(collect_fn_hard_reg_usage): Add fixed and stack registers to
|
||||
function_used_regs before the main loop rather than afterwards.
|
||||
Use insn_callee_abi instead of get_call_reg_set_usage. Exit early
|
||||
if function_used_regs ends up not being useful.
|
||||
(get_call_fndecl): Move to rtlanal.c
|
||||
(get_call_cgraph_rtl_info, get_call_reg_set_usage): Delete.
|
||||
* caller-save.c: Include function-abi.h.
|
||||
(setup_save_areas, save_call_clobbered_regs): Use insn_callee_abi
|
||||
instead of get_call_reg_set_usage.
|
||||
* cfgcleanup.c: Include function-abi.h.
|
||||
(old_insns_match_p): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
* cgraph.h (cgraph_node::rtl_info): Take a const_tree instead of
|
||||
a tree.
|
||||
* cgraph.c (cgraph_node::rtl_info): Likewise. Initialize
|
||||
function_used_regs.
|
||||
* df-scan.c: Include function-abi.h.
|
||||
(df_get_call_refs): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
* ira-lives.c: Include function-abi.h.
|
||||
(process_bb_node_lives): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
* lra-lives.c: Include function-abi.h.
|
||||
(process_bb_lives): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
* postreload.c: Include function-abi.h.
|
||||
(reload_combine): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
* regcprop.c: Include function-abi.h.
|
||||
(copyprop_hardreg_forward_1): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
* resource.c: Include function-abi.h.
|
||||
(mark_set_resources, mark_target_live_regs): Use insn_callee_abi
|
||||
instead of get_call_reg_set_usage.
|
||||
* var-tracking.c: Include function-abi.h.
|
||||
(dataflow_set_clear_at_call): Use insn_callee_abi instead of
|
||||
get_call_reg_set_usage.
|
||||
|
||||
2019-09-30 Richard Sandiford <richard.sandiford@arm.com>
|
||||
|
||||
* target.def (fntype_abi): New target hook.
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
104
gcc/final.c
104
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;
|
||||
|
||||
if (hard_reg_set_subset_p (crtl->abi->full_and_partial_reg_clobbers (),
|
||||
function_used_regs))
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "resource.h"
|
||||
#include "insn-attr.h"
|
||||
#include "params.h"
|
||||
#include "function-abi.h"
|
||||
|
||||
/* This structure is used to record liveness information at the targets or
|
||||
fallthrough insns of branches. We will most likely need the information
|
||||
|
@ -662,12 +663,10 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
|
|||
{
|
||||
rtx_call_insn *call_insn = as_a <rtx_call_insn *> (x);
|
||||
rtx link;
|
||||
HARD_REG_SET regs;
|
||||
|
||||
res->cc = res->memory = 1;
|
||||
|
||||
get_call_reg_set_usage (call_insn, ®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. */
|
||||
|
|
10
gcc/rtl.h
10
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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 *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)
|
||||
|
|
Loading…
Reference in New Issue