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 <richard.sandiford@arm.com> 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
This commit is contained in:
parent
7c3958812b
commit
6d1e98dfd2
|
@ -1,3 +1,13 @@
|
|||
2019-09-30 Richard Sandiford <richard.sandiford@arm.com>
|
||||
|
||||
* 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 <richard.sandiford@arm.com>
|
||||
|
||||
* hard-reg-set.h (regs_invalidated_by_call): Only define if
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
41
gcc/ira.c
41
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
|
||||
|
|
Loading…
Reference in New Issue