From 6d1e98dfd2bfce30640d71df355bedf114229744 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:39:38 +0000 Subject: [PATCH] Make ira call df_set_regs_ever_live for extra call-clobbered regs If we support multiple ABIs in the same translation unit, it can sometimes be the case that a callee clobbers more registers than its caller is allowed to. We need to call df_set_regs_ever_live on these extra registers so that the prologue and epilogue code can handle them appropriately. This patch does that in IRA. I wanted to avoid another full instruction walk just for this, so I combined it with the existing set_paradoxical_subreg walk. This happens before the first calculation of elimination offsets. 2019-09-30 Richard Sandiford gcc/ * function-abi.h (function_abi_aggregator): New class. * function-abi.cc (function_abi_aggregator::caller_save_regs): New function. * ira.c (update_equiv_regs_prescan): New function. Call set_paradoxical_subreg here rather than... (update_equiv_regs): ...here. (ira): Call update_equiv_regs_prescan. From-SVN: r276339 --- gcc/ChangeLog | 10 ++++++++++ gcc/function-abi.cc | 36 ++++++++++++++++++++++++++++++++++++ gcc/function-abi.h | 21 +++++++++++++++++++++ gcc/ira.c | 41 ++++++++++++++++++++++++++++++++--------- 4 files changed, 99 insertions(+), 9 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 00a1731..28e411c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2019-09-30 Richard Sandiford + * function-abi.h (function_abi_aggregator): New class. + * function-abi.cc (function_abi_aggregator::caller_save_regs): New + function. + * ira.c (update_equiv_regs_prescan): New function. Call + set_paradoxical_subreg here rather than... + (update_equiv_regs): ...here. + (ira): Call update_equiv_regs_prescan. + +2019-09-30 Richard Sandiford + * hard-reg-set.h (regs_invalidated_by_call): Only define if IN_TARGET_CODE. (call_used_or_fixed_regs): Likewise. diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index 4bace9e..eee789a 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -126,6 +126,42 @@ predefined_function_abi::add_full_reg_clobber (unsigned int regno) SET_HARD_REG_BIT (m_mode_clobbers[i], regno); } +/* Return the set of registers that the caller of the recorded functions must + save in order to honor the requirements of CALLER_ABI. */ + +HARD_REG_SET +function_abi_aggregator:: +caller_save_regs (const function_abi &caller_abi) const +{ + HARD_REG_SET result; + CLEAR_HARD_REG_SET (result); + for (unsigned int abi_id = 0; abi_id < NUM_ABI_IDS; ++abi_id) + { + const predefined_function_abi &callee_abi = function_abis[abi_id]; + + /* Skip cases that clearly aren't problematic. */ + if (abi_id == caller_abi.id () + || hard_reg_set_empty_p (m_abi_clobbers[abi_id])) + continue; + + /* Collect the set of registers that can be "more clobbered" by + CALLEE_ABI than by CALLER_ABI. */ + HARD_REG_SET extra_clobbers; + CLEAR_HARD_REG_SET (extra_clobbers); + for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i) + { + machine_mode mode = (machine_mode) i; + extra_clobbers |= (callee_abi.mode_clobbers (mode) + & ~caller_abi.mode_clobbers (mode)); + } + + /* Restrict it to the set of registers that we actually saw + clobbers for (e.g. taking -fipa-ra into account). */ + result |= (extra_clobbers & m_abi_clobbers[abi_id]); + } + return result; +} + /* Return the set of registers that cannot be used to hold a value of mode MODE across the calls in a region described by ABIS and MASK, where: diff --git a/gcc/function-abi.h b/gcc/function-abi.h index 8dd139e..9bb4d17 100644 --- a/gcc/function-abi.h +++ b/gcc/function-abi.h @@ -208,6 +208,27 @@ protected: HARD_REG_SET m_mask; }; +/* This class collects information about the ABIs of functions that are + called in a particular region of code. It is mostly intended to be + used as a local variable during an IR walk. */ +class function_abi_aggregator +{ +public: + function_abi_aggregator () : m_abi_clobbers () {} + + /* Record that the code region calls a function with the given ABI. */ + void + note_callee_abi (const function_abi &abi) + { + m_abi_clobbers[abi.id ()] |= abi.full_and_partial_reg_clobbers (); + } + + HARD_REG_SET caller_save_regs (const function_abi &) const; + +private: + HARD_REG_SET m_abi_clobbers[NUM_ABI_IDS]; +}; + struct target_function_abi_info { /* An array of all the target ABIs that are available in this diff --git a/gcc/ira.c b/gcc/ira.c index 925ea26..3b4f9a8 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -3362,6 +3362,37 @@ def_dominates_uses (int regno) return true; } +/* Scan the instructions before update_equiv_regs. Record which registers + are referenced as paradoxical subregs. Also check for cases in which + the current function needs to save a register that one of its call + instructions clobbers. + + These things are logically unrelated, but it's more efficient to do + them together. */ + +static void +update_equiv_regs_prescan (void) +{ + basic_block bb; + rtx_insn *insn; + function_abi_aggregator callee_abis; + + FOR_EACH_BB_FN (bb, cfun) + FOR_BB_INSNS (bb, insn) + if (NONDEBUG_INSN_P (insn)) + { + set_paradoxical_subreg (insn); + if (CALL_P (insn)) + callee_abis.note_callee_abi (insn_callee_abi (insn)); + } + + HARD_REG_SET extra_caller_saves = callee_abis.caller_save_regs (*crtl->abi); + if (!hard_reg_set_empty_p (extra_caller_saves)) + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (TEST_HARD_REG_BIT (extra_caller_saves, regno)) + df_set_regs_ever_live (regno, true); +} + /* Find registers that are equivalent to a single value throughout the compilation (either because they can be referenced in memory or are set once from a single constant). Lower their priority for a @@ -3378,15 +3409,6 @@ update_equiv_regs (void) rtx_insn *insn; basic_block bb; - /* Scan insns and set pdx_subregs if the reg is used in a - paradoxical subreg. Don't set such reg equivalent to a mem, - because lra will not substitute such equiv memory in order to - prevent access beyond allocated memory for paradoxical memory subreg. */ - FOR_EACH_BB_FN (bb, cfun) - FOR_BB_INSNS (bb, insn) - if (NONDEBUG_INSN_P (insn)) - set_paradoxical_subreg (insn); - /* Scan the insns and find which registers have equivalences. Do this in a separate scan of the insns because (due to -fcse-follow-jumps) a register can be set below its use. */ @@ -5276,6 +5298,7 @@ ira (FILE *f) init_alias_analysis (); loop_optimizer_init (AVOID_CFG_MODIFICATIONS); reg_equiv = XCNEWVEC (struct equivalence, max_reg_num ()); + update_equiv_regs_prescan (); update_equiv_regs (); /* Don't move insns if live range shrinkage or register -- 2.7.4