Commit 497b699b by Richard Sandiford Committed by Richard Sandiford

Remove global call sets: sel-sched.c

The main change here is to replace a crosses_call boolean with
a bitmask of the ABIs used by the crossed calls.  For space reasons,
I didn't also add a HARD_REG_SET that tracks the set of registers
that are actually clobbered, which means that this is the one part
of the series that doesn't benefit from -fipa-ra.  The existing
FIXME suggests that the current structures aren't the preferred
way of representing this anyhow, and the pass already makes
conservative assumptions about call-crossing registers.

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

gcc/
	* sel-sched-ir.h (_def::crosses_call): Replace with...
	(_def::crossed_call_abis): ..this new field.
	(def_list_add): Take a mask of ABIs instead of a crosses_call
	boolean.
	* sel-sched-ir.c (def_list_add): Likewise.  Update initialization
	of _def accordingly.
	* sel-sched.c: Include function-abi.h.
	(hard_regs_data::regs_for_call_clobbered): Delete.
	(reg_rename::crosses_call): Replace with...
	(reg_rename::crossed_call_abis): ...this new field.
	(fur_static_params::crosses_call): Replace with...
	(fur_static_params::crossed_call_abis): ...this new field.
	(init_regs_for_mode): Don't initialize sel_hrd.regs_for_call_clobbered.
	(init_hard_regs_data): Use crtl->abi to test which registers the
	current function would need to save before it uses them.
	(mark_unavailable_hard_regs): Update handling of call-clobbered
	registers, using call_clobbers_in_region to find out which registers
	might be call-clobbered (but without taking -fipa-ra into account
	for now).  Remove separate handling of partially call-clobbered
	registers.
	(verify_target_availability): Use crossed_call_abis instead of
	crosses_call.
	(get_spec_check_type_for_insn, find_used_regs): Likewise.
	(fur_orig_expr_found, fur_on_enter, fur_orig_expr_not_found): Likewise.

From-SVN: r276336
parent 2e2c6df3
2019-09-30 Richard Sandiford <richard.sandiford@arm.com> 2019-09-30 Richard Sandiford <richard.sandiford@arm.com>
* sel-sched-ir.h (_def::crosses_call): Replace with...
(_def::crossed_call_abis): ..this new field.
(def_list_add): Take a mask of ABIs instead of a crosses_call
boolean.
* sel-sched-ir.c (def_list_add): Likewise. Update initialization
of _def accordingly.
* sel-sched.c: Include function-abi.h.
(hard_regs_data::regs_for_call_clobbered): Delete.
(reg_rename::crosses_call): Replace with...
(reg_rename::crossed_call_abis): ...this new field.
(fur_static_params::crosses_call): Replace with...
(fur_static_params::crossed_call_abis): ...this new field.
(init_regs_for_mode): Don't initialize sel_hrd.regs_for_call_clobbered.
(init_hard_regs_data): Use crtl->abi to test which registers the
current function would need to save before it uses them.
(mark_unavailable_hard_regs): Update handling of call-clobbered
registers, using call_clobbers_in_region to find out which registers
might be call-clobbered (but without taking -fipa-ra into account
for now). Remove separate handling of partially call-clobbered
registers.
(verify_target_availability): Use crossed_call_abis instead of
crosses_call.
(get_spec_check_type_for_insn, find_used_regs): Likewise.
(fur_orig_expr_found, fur_on_enter, fur_orig_expr_not_found): Likewise.
2019-09-30 Richard Sandiford <richard.sandiford@arm.com>
* sched-deps.c (deps_analyze_insn): Use the ABI of the target * sched-deps.c (deps_analyze_insn): Use the ABI of the target
function to test whether a register is fully or partly clobbered. function to test whether a register is fully or partly clobbered.
......
...@@ -311,9 +311,10 @@ flist_clear (flist_t *lp) ...@@ -311,9 +311,10 @@ flist_clear (flist_t *lp)
flist_remove (lp); flist_remove (lp);
} }
/* Add ORIGINAL_INSN the def list DL honoring CROSSES_CALL. */ /* Add ORIGINAL_INSN the def list DL honoring CROSSED_CALL_ABIS. */
void void
def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call) def_list_add (def_list_t *dl, insn_t original_insn,
unsigned int crossed_call_abis)
{ {
def_t d; def_t d;
...@@ -321,7 +322,7 @@ def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call) ...@@ -321,7 +322,7 @@ def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call)
d = DEF_LIST_DEF (*dl); d = DEF_LIST_DEF (*dl);
d->orig_insn = original_insn; d->orig_insn = original_insn;
d->crosses_call = crosses_call; d->crossed_call_abis = crossed_call_abis;
} }
......
...@@ -188,12 +188,12 @@ struct _def ...@@ -188,12 +188,12 @@ struct _def
{ {
insn_t orig_insn; insn_t orig_insn;
/* FIXME: Get rid of CROSSES_CALL in each def, since if we're moving up /* FIXME: Get rid of CROSSED_CALL_ABIS in each def, since if we're moving up
rhs from two different places, but only one of the code motion paths rhs from two different places, but only one of the code motion paths
crosses a call, we can't use any of the call_used_regs, no matter which crosses a call, we can't use any of the call_used_regs, no matter which
path or whether all paths crosses a call. Thus we should move CROSSES_CALL path or whether all paths crosses a call. Thus we should move
to static params. */ CROSSED_CALL_ABIS to static params. */
bool crosses_call; unsigned int crossed_call_abis;
}; };
typedef struct _def *def_t; typedef struct _def *def_t;
...@@ -1510,7 +1510,7 @@ extern void flist_tail_init (flist_tail_t); ...@@ -1510,7 +1510,7 @@ extern void flist_tail_init (flist_tail_t);
extern fence_t flist_lookup (flist_t, insn_t); extern fence_t flist_lookup (flist_t, insn_t);
extern void flist_clear (flist_t *); extern void flist_clear (flist_t *);
extern void def_list_add (def_list_t *, insn_t, bool); extern void def_list_add (def_list_t *, insn_t, unsigned int);
/* Target context functions. */ /* Target context functions. */
extern tc_t create_target_context (bool); extern tc_t create_target_context (bool);
......
...@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "sel-sched-dump.h" #include "sel-sched-dump.h"
#include "sel-sched.h" #include "sel-sched.h"
#include "dbgcnt.h" #include "dbgcnt.h"
#include "function-abi.h"
/* Implementation of selective scheduling approach. /* Implementation of selective scheduling approach.
The below implementation follows the original approach with the following The below implementation follows the original approach with the following
...@@ -302,10 +303,6 @@ struct hard_regs_data ...@@ -302,10 +303,6 @@ struct hard_regs_data
that the whole set is not computed yet. */ that the whole set is not computed yet. */
HARD_REG_SET regs_for_rename[FIRST_PSEUDO_REGISTER]; HARD_REG_SET regs_for_rename[FIRST_PSEUDO_REGISTER];
/* For every mode, this stores registers not available due to
call clobbering. */
HARD_REG_SET regs_for_call_clobbered[NUM_MACHINE_MODES];
/* All registers that are used or call used. */ /* All registers that are used or call used. */
HARD_REG_SET regs_ever_used; HARD_REG_SET regs_ever_used;
...@@ -325,8 +322,8 @@ struct reg_rename ...@@ -325,8 +322,8 @@ struct reg_rename
/* These are *available* for renaming. */ /* These are *available* for renaming. */
HARD_REG_SET available_for_renaming; HARD_REG_SET available_for_renaming;
/* Whether this code motion path crosses a call. */ /* The set of ABIs used by calls that the code motion path crosses. */
bool crosses_call; unsigned int crossed_call_abis : NUM_ABI_IDS;
}; };
/* A global structure that contains the needed information about harg /* A global structure that contains the needed information about harg
...@@ -390,8 +387,8 @@ struct fur_static_params ...@@ -390,8 +387,8 @@ struct fur_static_params
/* Pointer to the list of original insns definitions. */ /* Pointer to the list of original insns definitions. */
def_list_t *original_insns; def_list_t *original_insns;
/* True if a code motion path contains a CALL insn. */ /* The set of ABIs used by calls that the code motion path crosses. */
bool crosses_call; unsigned int crossed_call_abis : NUM_ABI_IDS;
}; };
typedef struct fur_static_params *fur_static_params_p; typedef struct fur_static_params *fur_static_params_p;
...@@ -1067,7 +1064,6 @@ init_regs_for_mode (machine_mode mode) ...@@ -1067,7 +1064,6 @@ init_regs_for_mode (machine_mode mode)
int cur_reg; int cur_reg;
CLEAR_HARD_REG_SET (sel_hrd.regs_for_mode[mode]); CLEAR_HARD_REG_SET (sel_hrd.regs_for_mode[mode]);
CLEAR_HARD_REG_SET (sel_hrd.regs_for_call_clobbered[mode]);
for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++) for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++)
{ {
...@@ -1102,10 +1098,6 @@ init_regs_for_mode (machine_mode mode) ...@@ -1102,10 +1098,6 @@ init_regs_for_mode (machine_mode mode)
if (i >= 0) if (i >= 0)
continue; continue;
if (targetm.hard_regno_call_part_clobbered (0, cur_reg, mode))
SET_HARD_REG_BIT (sel_hrd.regs_for_call_clobbered[mode],
cur_reg);
/* If the CUR_REG passed all the checks above, /* If the CUR_REG passed all the checks above,
then it's ok. */ then it's ok. */
SET_HARD_REG_BIT (sel_hrd.regs_for_mode[mode], cur_reg); SET_HARD_REG_BIT (sel_hrd.regs_for_mode[mode], cur_reg);
...@@ -1123,7 +1115,8 @@ init_hard_regs_data (void) ...@@ -1123,7 +1115,8 @@ init_hard_regs_data (void)
CLEAR_HARD_REG_SET (sel_hrd.regs_ever_used); CLEAR_HARD_REG_SET (sel_hrd.regs_ever_used);
for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++) for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++)
if (df_regs_ever_live_p (cur_reg) || call_used_or_fixed_reg_p (cur_reg)) if (df_regs_ever_live_p (cur_reg)
|| crtl->abi->clobbers_full_reg_p (cur_reg))
SET_HARD_REG_BIT (sel_hrd.regs_ever_used, cur_reg); SET_HARD_REG_BIT (sel_hrd.regs_ever_used, cur_reg);
/* Initialize registers that are valid based on mode when this is /* Initialize registers that are valid based on mode when this is
...@@ -1193,7 +1186,7 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, ...@@ -1193,7 +1186,7 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
SET_HARD_REG_SET (reg_rename_p->unavailable_hard_regs); SET_HARD_REG_SET (reg_rename_p->unavailable_hard_regs);
/* Give a chance for original register, if it isn't in used_regs. */ /* Give a chance for original register, if it isn't in used_regs. */
if (!def->crosses_call) if (!def->crossed_call_abis)
CLEAR_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs, regno); CLEAR_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs, regno);
return; return;
...@@ -1224,13 +1217,20 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, ...@@ -1224,13 +1217,20 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
reg_rename_p->unavailable_hard_regs |= sel_hrd.stack_regs; reg_rename_p->unavailable_hard_regs |= sel_hrd.stack_regs;
#endif #endif
/* If there's a call on this path, make regs from call_used_or_fixed_regs mode = GET_MODE (orig_dest);
unavailable. */
if (def->crosses_call) /* If there's a call on this path, make regs from full_reg_clobbers
reg_rename_p->unavailable_hard_regs |= call_used_or_fixed_regs; unavailable.
/* Stop here before reload: we need FRAME_REGS, STACK_REGS, and crosses_call, ??? It would be better to track the set of clobbered registers
but not register classes. */ directly, but that would be quite expensive in a def_t. */
if (def->crossed_call_abis)
reg_rename_p->unavailable_hard_regs
|= call_clobbers_in_region (def->crossed_call_abis,
reg_class_contents[ALL_REGS], mode);
/* Stop here before reload: we need FRAME_REGS, STACK_REGS, and
crossed_call_abis, but not register classes. */
if (!reload_completed) if (!reload_completed)
return; return;
...@@ -1238,19 +1238,11 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, ...@@ -1238,19 +1238,11 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
register class. */ register class. */
reg_rename_p->available_for_renaming = reg_class_contents[cl]; reg_rename_p->available_for_renaming = reg_class_contents[cl];
mode = GET_MODE (orig_dest);
/* Leave only registers available for this mode. */ /* Leave only registers available for this mode. */
if (!sel_hrd.regs_for_mode_ok[mode]) if (!sel_hrd.regs_for_mode_ok[mode])
init_regs_for_mode (mode); init_regs_for_mode (mode);
reg_rename_p->available_for_renaming &= sel_hrd.regs_for_mode[mode]; reg_rename_p->available_for_renaming &= sel_hrd.regs_for_mode[mode];
/* Exclude registers that are partially call clobbered. */
if (def->crosses_call
&& !targetm.hard_regno_call_part_clobbered (0, regno, mode))
reg_rename_p->available_for_renaming
&= ~sel_hrd.regs_for_call_clobbered[mode];
/* Leave only those that are ok to rename. */ /* Leave only those that are ok to rename. */
EXECUTE_IF_SET_IN_HARD_REG_SET (reg_rename_p->available_for_renaming, EXECUTE_IF_SET_IN_HARD_REG_SET (reg_rename_p->available_for_renaming,
0, cur_reg, hrsi) 0, cur_reg, hrsi)
...@@ -1481,7 +1473,7 @@ choose_best_pseudo_reg (regset used_regs, ...@@ -1481,7 +1473,7 @@ choose_best_pseudo_reg (regset used_regs,
/* Don't let register cross a call if it doesn't already /* Don't let register cross a call if it doesn't already
cross one. This condition is written in accordance with cross one. This condition is written in accordance with
that in sched-deps.c sched_analyze_reg(). */ that in sched-deps.c sched_analyze_reg(). */
if (!reg_rename_p->crosses_call if (!reg_rename_p->crossed_call_abis
|| REG_N_CALLS_CROSSED (orig_regno) > 0) || REG_N_CALLS_CROSSED (orig_regno) > 0)
return gen_rtx_REG (mode, orig_regno); return gen_rtx_REG (mode, orig_regno);
} }
...@@ -1508,7 +1500,8 @@ choose_best_pseudo_reg (regset used_regs, ...@@ -1508,7 +1500,8 @@ choose_best_pseudo_reg (regset used_regs,
max_regno = max_reg_num (); max_regno = max_reg_num ();
maybe_extend_reg_info_p (); maybe_extend_reg_info_p ();
REG_N_CALLS_CROSSED (REGNO (new_reg)) = reg_rename_p->crosses_call ? 1 : 0; REG_N_CALLS_CROSSED (REGNO (new_reg))
= reg_rename_p->crossed_call_abis ? 1 : 0;
return new_reg; return new_reg;
} }
...@@ -1560,7 +1553,8 @@ verify_target_availability (expr_t expr, regset used_regs, ...@@ -1560,7 +1553,8 @@ verify_target_availability (expr_t expr, regset used_regs,
as well. */ as well. */
gcc_assert (scheduled_something_on_previous_fence || !live_available gcc_assert (scheduled_something_on_previous_fence || !live_available
|| !hard_available || !hard_available
|| (!reload_completed && reg_rename_p->crosses_call || (!reload_completed
&& reg_rename_p->crossed_call_abis
&& REG_N_CALLS_CROSSED (regno) == 0)); && REG_N_CALLS_CROSSED (regno) == 0));
} }
...@@ -3248,7 +3242,7 @@ get_spec_check_type_for_insn (insn_t insn, expr_t expr) ...@@ -3248,7 +3242,7 @@ get_spec_check_type_for_insn (insn_t insn, expr_t expr)
All the original operations found during the traversal are saved in the All the original operations found during the traversal are saved in the
ORIGINAL_INSNS list. ORIGINAL_INSNS list.
REG_RENAME_P->CROSSES_CALL is true, if there is a call insn on the path REG_RENAME_P->CROSSED_CALL_ABIS is true, if there is a call insn on the path
from INSN to original insn. In this case CALL_USED_REG_SET will be added from INSN to original insn. In this case CALL_USED_REG_SET will be added
to unavailable hard regs at the point original operation is found. */ to unavailable hard regs at the point original operation is found. */
...@@ -3269,7 +3263,7 @@ find_used_regs (insn_t insn, av_set_t orig_ops, regset used_regs, ...@@ -3269,7 +3263,7 @@ find_used_regs (insn_t insn, av_set_t orig_ops, regset used_regs,
bitmap_clear (code_motion_visited_blocks); bitmap_clear (code_motion_visited_blocks);
/* Init parameters for code_motion_path_driver. */ /* Init parameters for code_motion_path_driver. */
sparams.crosses_call = false; sparams.crossed_call_abis = 0;
sparams.original_insns = original_insns; sparams.original_insns = original_insns;
sparams.used_regs = used_regs; sparams.used_regs = used_regs;
...@@ -3278,7 +3272,7 @@ find_used_regs (insn_t insn, av_set_t orig_ops, regset used_regs, ...@@ -3278,7 +3272,7 @@ find_used_regs (insn_t insn, av_set_t orig_ops, regset used_regs,
res = code_motion_path_driver (insn, orig_ops, NULL, &lparams, &sparams); res = code_motion_path_driver (insn, orig_ops, NULL, &lparams, &sparams);
reg_rename_p->crosses_call |= sparams.crosses_call; reg_rename_p->crossed_call_abis |= sparams.crossed_call_abis;
gcc_assert (res == 1); gcc_assert (res == 1);
gcc_assert (original_insns && *original_insns); gcc_assert (original_insns && *original_insns);
...@@ -6006,7 +6000,7 @@ move_op_orig_expr_found (insn_t insn, expr_t expr, ...@@ -6006,7 +6000,7 @@ move_op_orig_expr_found (insn_t insn, expr_t expr,
/* The function is called when original expr is found. /* The function is called when original expr is found.
INSN - current insn traversed, EXPR - the corresponding expr found, INSN - current insn traversed, EXPR - the corresponding expr found,
crosses_call and original_insns in STATIC_PARAMS are updated. */ crossed_call_abis and original_insns in STATIC_PARAMS are updated. */
static void static void
fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED, fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED,
cmpd_local_params_p lparams ATTRIBUTE_UNUSED, cmpd_local_params_p lparams ATTRIBUTE_UNUSED,
...@@ -6016,9 +6010,9 @@ fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED, ...@@ -6016,9 +6010,9 @@ fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED,
regset tmp; regset tmp;
if (CALL_P (insn)) if (CALL_P (insn))
params->crosses_call = true; params->crossed_call_abis |= 1 << insn_callee_abi (insn).id ();
def_list_add (params->original_insns, insn, params->crosses_call); def_list_add (params->original_insns, insn, params->crossed_call_abis);
/* Mark the registers that do not meet the following condition: /* Mark the registers that do not meet the following condition:
(2) not among the live registers of the point (2) not among the live registers of the point
...@@ -6176,10 +6170,10 @@ fur_on_enter (insn_t insn ATTRIBUTE_UNUSED, cmpd_local_params_p local_params, ...@@ -6176,10 +6170,10 @@ fur_on_enter (insn_t insn ATTRIBUTE_UNUSED, cmpd_local_params_p local_params,
least one insn in ORIGINAL_INSNS. */ least one insn in ORIGINAL_INSNS. */
gcc_assert (*sparams->original_insns); gcc_assert (*sparams->original_insns);
/* Adjust CROSSES_CALL, since we may have come to this block along /* Adjust CROSSED_CALL_ABIS, since we may have come to this block along
different path. */ different path. */
DEF_LIST_DEF (*sparams->original_insns)->crosses_call DEF_LIST_DEF (*sparams->original_insns)->crossed_call_abis
|= sparams->crosses_call; |= sparams->crossed_call_abis;
} }
else else
local_params->old_original_insns = *sparams->original_insns; local_params->old_original_insns = *sparams->original_insns;
...@@ -6233,7 +6227,7 @@ fur_orig_expr_not_found (insn_t insn, av_set_t orig_ops, void *static_params) ...@@ -6233,7 +6227,7 @@ fur_orig_expr_not_found (insn_t insn, av_set_t orig_ops, void *static_params)
fur_static_params_p sparams = (fur_static_params_p) static_params; fur_static_params_p sparams = (fur_static_params_p) static_params;
if (CALL_P (insn)) if (CALL_P (insn))
sparams->crosses_call = true; sparams->crossed_call_abis |= 1 << insn_callee_abi (insn).id ();
else if (DEBUG_INSN_P (insn)) else if (DEBUG_INSN_P (insn))
return true; return true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment