info->equiv_mem_modified = true;
}
+static int equiv_init_varies_p (rtx x);
+
enum valid_equiv { valid_none, valid_combine, valid_reload };
/* Verify that no store between START and the death of REG invalidates
been changed and all hell breaks loose. */
ret = valid_combine;
if (!MEM_READONLY_P (memref)
- && !RTL_CONST_OR_PURE_CALL_P (insn))
+ && (!RTL_CONST_OR_PURE_CALL_P (insn)
+ || equiv_init_varies_p (XEXP (memref, 0))))
return valid_none;
}
if (reg_equiv[regno].is_arg_equivalence)
return;
ira_reg_equiv[regno].defined_p = false;
+ ira_reg_equiv[regno].caller_save_p = false;
ira_reg_equiv[regno].init_insns = NULL;
for (; list; list = list->next ())
{
{
replacement = copy_rtx (SET_SRC (set));
if (validity == valid_reload)
- note = set_unique_reg_note (insn, REG_EQUIV, replacement);
+ {
+ note = set_unique_reg_note (insn, REG_EQUIV, replacement);
+ }
+ else
+ {
+ /* We still can use this equivalence for caller save
+ optimization in LRA. Mark this. */
+ ira_reg_equiv[regno].caller_save_p = true;
+ ira_reg_equiv[regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, insn,
+ ira_reg_equiv[regno].init_insns);
+ }
}
}
legitimate, we ignore such REG_EQUIV notes. */
if (memory_operand (x, VOIDmode))
{
- ira_reg_equiv[i].defined_p = true;
+ ira_reg_equiv[i].defined_p = !ira_reg_equiv[i].caller_save_p;
ira_reg_equiv[i].memory = x;
continue;
}
/* Major structure describing equivalence info for a pseudo. */
struct ira_reg_equiv_s
{
- /* True if we can use this equivalence. */
+ /* True if we can use this as a general equivalence. */
bool defined_p;
+ /* True if we can use this equivalence only for caller save/restore
+ location. */
+ bool caller_save_p;
/* True if the usage of the equivalence is profitable. */
bool profitable_p;
/* Equiv. memory, constant, invariant, and initializing insns of
return best_cl;
}
-/* Copy any equivalence information from ORIGINAL_REGNO to NEW_REGNO.
- It only makes sense to call this function if NEW_REGNO is always
- equal to ORIGINAL_REGNO. */
+/* Copy any equivalence information from ORIGINAL_REGNO to NEW_REGNO. It only
+ makes sense to call this function if NEW_REGNO is always equal to
+ ORIGINAL_REGNO. Set up defined_p flag when caller_save_p flag is set up and
+ CALL_SAVE_P is true. */
static void
-lra_copy_reg_equiv (unsigned int new_regno, unsigned int original_regno)
+lra_copy_reg_equiv (unsigned int new_regno, unsigned int original_regno,
+ bool call_save_p)
{
- if (!ira_reg_equiv[original_regno].defined_p)
+ if (!ira_reg_equiv[original_regno].defined_p
+ && !(call_save_p && ira_reg_equiv[original_regno].caller_save_p))
return;
ira_expand_reg_equiv ();
rematerializing the original value instead of spilling to the stack. */
if (!HARD_REGISTER_NUM_P (original_regno)
&& mode == PSEUDO_REGNO_MODE (original_regno))
- lra_copy_reg_equiv (new_regno, original_regno);
+ lra_copy_reg_equiv (new_regno, original_regno, call_save_p);
lra_reg_info[new_regno].restore_rtx = regno_reg_rtx[original_regno];
bitmap_set_bit (&lra_split_regs, new_regno);
if (to != NULL)
--- /dev/null
+/* PR target/108711.C */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-exceptions" } */
+struct Expression_list {
+ Expression_list *copy();
+} vals_;
+struct Parser_expression {
+ Parser_expression();
+};
+struct Composite_literal_expression : Parser_expression {
+ Composite_literal_expression(bool has_keys, Expression_list *,
+ bool all_are_names)
+ : has_keys_(has_keys), all_are_names_(all_are_names) {}
+ void do_copy();
+ bool has_keys_;
+ bool all_are_names_;
+};
+void Composite_literal_expression::do_copy() {
+ new Composite_literal_expression(has_keys_, vals_.copy(), all_are_names_);
+}
--- /dev/null
+/* PR rtl-optimization/103541 */
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+float a;
+__attribute__((const)) float foo (float);
+
+float
+test()
+{
+ return a + foo(a) + a;
+}
+
+/* { dg-final { scan-assembler-not "\\\(%rsp\\\)" } } */