/* Information about fuunction binary interfaces.
- Copyright (C) 2019 Free Software Foundation, Inc.
+ Copyright (C) 2019-2021 Free Software Foundation, Inc.
This file is part of GCC
If the ABI specifies that part of a hard register R is call-clobbered,
we should be able to find a single-register mode M for which
- targetm.hard_regno_call_part_clobbered (NULL, R, M) is true.
+ targetm.hard_regno_call_part_clobbered (m_id, R, M) is true.
In other words, it shouldn't be the case that R can hold all
single-register modes across a call, but can't hold part of
a multi-register mode.
for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
if (targetm.hard_regno_mode_ok (regno, mode)
&& hard_regno_nregs (regno, mode) == 1
- && targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
+ && targetm.hard_regno_call_part_clobbered (m_id, regno, mode))
SET_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno);
}
for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
if (targetm.hard_regno_mode_ok (regno, mode)
&& !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno)
- && !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
+ && !targetm.hard_regno_call_part_clobbered (m_id, regno, mode))
remove_from_hard_reg_set (&m_mode_clobbers[i], mode, regno);
}
for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
if (targetm.hard_regno_mode_ok (regno, mode)
&& !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno)
- && targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
+ && targetm.hard_regno_call_part_clobbered (m_id, regno, mode))
gcc_assert (overlaps_hard_reg_set_p (all_clobbers, mode, regno)
&& overlaps_hard_reg_set_p (m_mode_clobbers[i],
mode, 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:
+
+ * Bit ID of ABIS is set if the region contains a call with
+ function_abi identifier ID.
+
+ * MASK contains all the registers that are fully or partially
+ clobbered by calls in the region.
+
+ This is not quite as accurate as testing each individual call,
+ but it's a close and conservatively-correct approximation.
+ It's much better for some targets than just using MASK. */
+
+HARD_REG_SET
+call_clobbers_in_region (unsigned int abis, const_hard_reg_set mask,
+ machine_mode mode)
+{
+ HARD_REG_SET result;
+ CLEAR_HARD_REG_SET (result);
+ for (unsigned int id = 0; abis; abis >>= 1, ++id)
+ if (abis & 1)
+ result |= function_abis[id].mode_clobbers (mode);
+ return result & mask;
+}
+
/* Return the predefined ABI used by functions with type TYPE. */
const predefined_function_abi &
return default_function_abi;
}
+
+/* Return the ABI of the function called by CALL_EXPR EXP. Return the
+ default ABI for erroneous calls. */
+
+function_abi
+expr_callee_abi (const_tree exp)
+{
+ gcc_assert (TREE_CODE (exp) == CALL_EXPR);
+
+ if (tree fndecl = get_callee_fndecl (exp))
+ return fndecl_abi (fndecl);
+
+ tree callee = CALL_EXPR_FN (exp);
+ if (callee == error_mark_node)
+ return default_function_abi;
+
+ tree type = TREE_TYPE (callee);
+ if (type == error_mark_node)
+ return default_function_abi;
+
+ gcc_assert (POINTER_TYPE_P (type));
+ return fntype_abi (TREE_TYPE (type));
+}