aboutsummaryrefslogtreecommitdiff
path: root/gcc/function-abi.cc
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2019-09-30 16:39:38 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2019-09-30 16:39:38 +0000
commit6d1e98dfd2bfce30640d71df355bedf114229744 (patch)
tree4fd650f51b146fd95f2345a09063f202a8768f53 /gcc/function-abi.cc
parent7c3958812bd5e2e139c7f0adf8f03b505fda67f2 (diff)
downloadgcc-6d1e98dfd2bfce30640d71df355bedf114229744.zip
gcc-6d1e98dfd2bfce30640d71df355bedf114229744.tar.gz
gcc-6d1e98dfd2bfce30640d71df355bedf114229744.tar.bz2
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
Diffstat (limited to 'gcc/function-abi.cc')
-rw-r--r--gcc/function-abi.cc36
1 files changed, 36 insertions, 0 deletions
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: