+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.
#include "dumpfile.h"
#include "rtl-iter.h"
#include "target.h"
+#include "function-abi.h"
#define MOVE_MAX_WORDS (MOVE_MAX / UNITS_PER_WORD)
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
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
| 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++)
#include "dbgcnt.h"
#include "rtl-iter.h"
#include "regs.h"
+#include "function-abi.h"
#define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK)
}
}
- 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;
/* 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);
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;
}
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. */
the function. */
static bool
-aarch64_simd_call_p (rtx_insn *insn)
+aarch64_simd_call_p (const rtx_insn *insn)
{
rtx symbol;
rtx call;
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
#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 \
#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. */
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++)
{
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
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
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
@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
#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. */
#endif
static int align_fuzz (rtx, rtx, int, unsigned);
static void collect_fn_hard_reg_usage (void);
-static tree get_call_fndecl (rtx_insn *);
\f
/* Initialize data in final at the beginning of a compilation. */
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))
{
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;
}
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;
}
* 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
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
#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
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
#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
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
#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);
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))
#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
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))
{
}
}
- 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))
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 */
#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
{
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))
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. */
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);
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,
return x;
return NULL_RTX;
}
+
+/* Get the declaration of the function called by INSN. */
+
+tree
+get_call_fndecl (const rtx_insn *insn)
+{
+ rtx note, datum;
+
+ note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
+ if (note == NULL_RTX)
+ return NULL_TREE;
+
+ datum = XEXP (note, 0);
+ if (datum != NULL_RTX)
+ return SYMBOL_REF_DECL (datum);
+
+ return NULL_TREE;
+}
\f
/* Return the value of the integer term in X, if one is apparent;
otherwise return 0.
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,
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
return result;
}
-void
-default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
-{
-}
-
#include "gt-targhooks.h"
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 */
#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;
{
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)