+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
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:
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
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
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. */
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