[pushed,PR114991,IRA] : Improve reg equiv invariant calculation
Commit Message
The following patch solves performance issue mentioned in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114991
The patch was successfully bootstrapped and tested on x86_64, aarch64,
ppc64le.
commit e355fe414aa3aaf215c7dd9dd789ce217a1b458c
Author: Vladimir N. Makarov <vmakarov@redhat.com>
Date: Mon Mar 10 16:26:59 2025 -0400
[PR114991][IRA]: Improve reg equiv invariant calculation
In PR test case IRA preferred to allocate hard reg to a pseudo instead
of its equivalence. This resulted in allocating caller-saved hard reg
and generating save/restore insns in the function prologue/epilogue.
The equivalence is an invariant (stack pointer plus offset) and the
pseudo is used mostly as memory address. This happened as there was
no simplification of insn after the invariant substitution. The patch
adds the necessary code.
gcc/ChangeLog:
PR target/114991
* ira-costs.cc (equiv_can_be_consumed_p): Add new argument invariant_p.
Add code for dealing with the invariant.
(calculate_equiv_gains): Don't consider init insns. Pass the new
argument to equiv_can_be_consumed_p. Don't treat invariant as
memory.
gcc/testsuite/ChangeLog:
PR target/114991
* gcc.target/aarch64/pr114991.c: New test.
@@ -1788,11 +1788,27 @@ validate_autoinc_and_mem_addr_p (rtx x)
MEM_ADDR_SPACE (x)));
}
-/* Check that reg REGNO can be changed by TO in INSN. Return true in case the
- result insn would be valid one. */
+/* Check that reg REGNO in INSN can be changed by TO (which is an invariant
+ equiv when INVARIANT_P is true). Return true in case the result insn would
+ be valid one. */
static bool
-equiv_can_be_consumed_p (int regno, rtx to, rtx_insn *insn)
+equiv_can_be_consumed_p (int regno, rtx to, rtx_insn *insn, bool invariant_p)
{
+ if (invariant_p)
+ {
+ /* We use more expensive code for the invariant because we need to
+ simplify the result insn as the invariant can be arithmetic rtx
+ inserted into another arithmetic rtx. */
+ rtx pat = PATTERN (insn);
+ int code = INSN_CODE (insn);
+ PATTERN (insn) = copy_rtx (pat);
+ PATTERN (insn)
+ = simplify_replace_rtx (PATTERN (insn), regno_reg_rtx[regno], to);
+ bool res = !insn_invalid_p (insn, false);
+ PATTERN (insn) = pat;
+ INSN_CODE (insn) = code;
+ return res;
+ }
validate_replace_src_group (regno_reg_rtx[regno], to, insn);
/* We can change register to equivalent memory in autoinc rtl. Some code
including verify_changes assumes that autoinc contains only a register.
@@ -1910,6 +1926,14 @@ calculate_equiv_gains (void)
|| !get_equiv_regno (PATTERN (insn), regno, subreg)
|| !bitmap_bit_p (&equiv_pseudos, regno))
continue;
+
+ rtx_insn_list *x;
+ for (x = ira_reg_equiv[regno].init_insns; x != NULL; x = x->next ())
+ if (insn == x->insn ())
+ break;
+ if (x != NULL)
+ continue; /* skip equiv init insn */
+
rtx subst = ira_reg_equiv[regno].memory;
if (subst == NULL)
@@ -1919,13 +1943,17 @@ calculate_equiv_gains (void)
ira_assert (subst != NULL);
mode = PSEUDO_REGNO_MODE (regno);
ira_init_register_move_cost_if_necessary (mode);
- bool consumed_p = equiv_can_be_consumed_p (regno, subst, insn);
+ bool consumed_p
+ = equiv_can_be_consumed_p (regno, subst, insn,
+ subst == ira_reg_equiv[regno].invariant);
rclass = pref[COST_INDEX (regno)];
if (MEM_P (subst)
/* If it is a change of constant into double for example, the
result constant probably will be placed in memory. */
- || (subreg != NULL_RTX && !INTEGRAL_MODE_P (GET_MODE (subreg))))
+ || (ira_reg_equiv[regno].invariant == NULL
+ && subreg != NULL_RTX
+ && !INTEGRAL_MODE_P (GET_MODE (subreg))))
cost = ira_memory_move_cost[mode][rclass][1] + (consumed_p ? 0 : 1);
else if (consumed_p)
continue;
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-shrink-wrap" } */
+
+typedef struct { int arr[16]; } S;
+
+void g (S *);
+void h (S);
+void f(int x)
+{
+ S s;
+ g (&s);
+ h (s);
+}
+
+/* { dg-final { scan-assembler-not "\[ \t\]?str\[ \t\]x" } } */