RA: Implement reuse of equivalent memory for caller saves optimization (2nd version)

The test pr103541.c shows opportunity to reuse memory with constant address for
caller saves optimization for constant or pure function call.  The patch
implements the memory reuse.

        PR rtl-optimization/103541
        PR rtl-optimization/108711

gcc/ChangeLog:

	* ira.h (struct ira_reg_equiv_s): Add new field caller_save_p.
	* ira.cc (validate_equiv_mem): Check memref address variance.
	(no_equiv): Clear caller_save_p flag.
	(update_equiv_regs): Define caller save equivalence for
	valid_combine.
	(setup_reg_equiv): Clear defined_p flag for caller save equivalence.
	* lra-constraints.cc (lra_copy_reg_equiv): Add new arg
	call_save_p.  Use caller save equivalence depending on the arg.
	(split_reg): Adjust the call.

gcc/testsuite/ChangeLog:

	* gcc.target/i386/pr103541.c: New.
	* g++.target/i386/pr108711.C: New.
This commit is contained in:
Vladimir N. Makarov 2023-02-09 15:18:48 -05:00
parent a618b45ac4
commit 10827a92f1
5 changed files with 65 additions and 10 deletions

View file

@ -3070,6 +3070,8 @@ validate_equiv_mem_from_store (rtx dest, const_rtx set ATTRIBUTE_UNUSED,
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
@ -3113,7 +3115,8 @@ validate_equiv_mem (rtx_insn *start, rtx reg, rtx memref)
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;
}
@ -3414,6 +3417,7 @@ no_equiv (rtx reg, const_rtx store ATTRIBUTE_UNUSED,
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 ())
{
@ -3766,7 +3770,18 @@ update_equiv_regs (void)
{
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);
}
}
}
@ -4156,7 +4171,7 @@ setup_reg_equiv (void)
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;
}

View file

@ -175,8 +175,11 @@ extern struct target_ira *this_target_ira;
/* 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

View file

@ -5771,14 +5771,17 @@ choose_split_class (enum reg_class allocno_class,
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 ();
@ -5958,7 +5961,7 @@ split_reg (bool before_p, int original_regno, rtx_insn *insn,
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)

View file

@ -0,0 +1,20 @@
/* 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_);
}

View file

@ -0,0 +1,14 @@
/* 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\\\)" } } */