From 497b699b93759c7f84527f49a9644c3ea692405d Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:39 +0000 Subject: [PATCH] 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 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 --- gcc/ChangeLog | 27 ++++++++++++++++ gcc/sel-sched-ir.c | 7 +++-- gcc/sel-sched-ir.h | 10 +++--- gcc/sel-sched.c | 78 +++++++++++++++++++++------------------------- 4 files changed, 72 insertions(+), 50 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4c29a6c7f7e..6d2d20f1df9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2019-09-30 Richard Sandiford + + * 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 * sched-deps.c (deps_analyze_insn): Use the ABI of the target diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c index e4f5a454fdb..8a1d41473b9 100644 --- a/gcc/sel-sched-ir.c +++ b/gcc/sel-sched-ir.c @@ -311,9 +311,10 @@ flist_clear (flist_t *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 -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; @@ -321,7 +322,7 @@ def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call) d = DEF_LIST_DEF (*dl); d->orig_insn = original_insn; - d->crosses_call = crosses_call; + d->crossed_call_abis = crossed_call_abis; } diff --git a/gcc/sel-sched-ir.h b/gcc/sel-sched-ir.h index b5824aec369..ddc76a73ede 100644 --- a/gcc/sel-sched-ir.h +++ b/gcc/sel-sched-ir.h @@ -188,12 +188,12 @@ struct _def { 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 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 - to static params. */ - bool crosses_call; + path or whether all paths crosses a call. Thus we should move + CROSSED_CALL_ABIS to static params. */ + unsigned int crossed_call_abis; }; typedef struct _def *def_t; @@ -1510,7 +1510,7 @@ extern void flist_tail_init (flist_tail_t); extern fence_t flist_lookup (flist_t, insn_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. */ extern tc_t create_target_context (bool); diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c index bf370b5a5d8..652784e79ed 100644 --- a/gcc/sel-sched.c +++ b/gcc/sel-sched.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "sel-sched-dump.h" #include "sel-sched.h" #include "dbgcnt.h" +#include "function-abi.h" /* Implementation of selective scheduling approach. The below implementation follows the original approach with the following @@ -302,10 +303,6 @@ struct hard_regs_data that the whole set is not computed yet. */ 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. */ HARD_REG_SET regs_ever_used; @@ -325,8 +322,8 @@ struct reg_rename /* These are *available* for renaming. */ HARD_REG_SET available_for_renaming; - /* Whether this code motion path crosses a call. */ - bool crosses_call; + /* The set of ABIs used by calls that the code motion path crosses. */ + unsigned int crossed_call_abis : NUM_ABI_IDS; }; /* A global structure that contains the needed information about harg @@ -390,8 +387,8 @@ struct fur_static_params /* Pointer to the list of original insns definitions. */ def_list_t *original_insns; - /* True if a code motion path contains a CALL insn. */ - bool crosses_call; + /* The set of ABIs used by calls that the code motion path crosses. */ + unsigned int crossed_call_abis : NUM_ABI_IDS; }; typedef struct fur_static_params *fur_static_params_p; @@ -1067,7 +1064,6 @@ init_regs_for_mode (machine_mode mode) int cur_reg; 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++) { @@ -1102,10 +1098,6 @@ init_regs_for_mode (machine_mode mode) if (i >= 0) 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, then it's ok. */ SET_HARD_REG_BIT (sel_hrd.regs_for_mode[mode], cur_reg); @@ -1123,7 +1115,8 @@ init_hard_regs_data (void) CLEAR_HARD_REG_SET (sel_hrd.regs_ever_used); 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); /* 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, SET_HARD_REG_SET (reg_rename_p->unavailable_hard_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); return; @@ -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; #endif - /* If there's a call on this path, make regs from call_used_or_fixed_regs - unavailable. */ - if (def->crosses_call) - reg_rename_p->unavailable_hard_regs |= call_used_or_fixed_regs; + mode = GET_MODE (orig_dest); + + /* If there's a call on this path, make regs from full_reg_clobbers + unavailable. - /* Stop here before reload: we need FRAME_REGS, STACK_REGS, and crosses_call, - but not register classes. */ + ??? It would be better to track the set of clobbered registers + 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) return; @@ -1238,19 +1238,11 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, register class. */ reg_rename_p->available_for_renaming = reg_class_contents[cl]; - mode = GET_MODE (orig_dest); - /* Leave only registers available for this mode. */ if (!sel_hrd.regs_for_mode_ok[mode]) init_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. */ EXECUTE_IF_SET_IN_HARD_REG_SET (reg_rename_p->available_for_renaming, 0, cur_reg, hrsi) @@ -1481,7 +1473,7 @@ choose_best_pseudo_reg (regset used_regs, /* Don't let register cross a call if it doesn't already cross one. This condition is written in accordance with 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) return gen_rtx_REG (mode, orig_regno); } @@ -1508,7 +1500,8 @@ choose_best_pseudo_reg (regset used_regs, max_regno = max_reg_num (); 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; } @@ -1560,7 +1553,8 @@ verify_target_availability (expr_t expr, regset used_regs, as well. */ gcc_assert (scheduled_something_on_previous_fence || !live_available || !hard_available - || (!reload_completed && reg_rename_p->crosses_call + || (!reload_completed + && reg_rename_p->crossed_call_abis && REG_N_CALLS_CROSSED (regno) == 0)); } @@ -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 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 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, bitmap_clear (code_motion_visited_blocks); /* Init parameters for code_motion_path_driver. */ - sparams.crosses_call = false; + sparams.crossed_call_abis = 0; sparams.original_insns = original_insns; sparams.used_regs = 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); - reg_rename_p->crosses_call |= sparams.crosses_call; + reg_rename_p->crossed_call_abis |= sparams.crossed_call_abis; gcc_assert (res == 1); gcc_assert (original_insns && *original_insns); @@ -6006,7 +6000,7 @@ move_op_orig_expr_found (insn_t insn, expr_t expr, /* The function is called when original expr is 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 fur_orig_expr_found (insn_t insn, expr_t expr 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, regset tmp; 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: (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, least one insn in 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. */ - DEF_LIST_DEF (*sparams->original_insns)->crosses_call - |= sparams->crosses_call; + DEF_LIST_DEF (*sparams->original_insns)->crossed_call_abis + |= sparams->crossed_call_abis; } else 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) fur_static_params_p sparams = (fur_static_params_p) static_params; if (CALL_P (insn)) - sparams->crosses_call = true; + sparams->crossed_call_abis |= 1 << insn_callee_abi (insn).id (); else if (DEBUG_INSN_P (insn)) return true; -- 2.30.2