[pushed,PR114991,IRA] : Improve reg equiv invariant calculation

Message ID 462c19a6-d679-4696-bbee-f63936e185ef@redhat.com
State New
Headers
Series [pushed,PR114991,IRA] : Improve reg equiv invariant calculation |

Commit Message

Vladimir Makarov March 10, 2025, 8:30 p.m. UTC
  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.
  

Patch

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.

diff --git a/gcc/ira-costs.cc b/gcc/ira-costs.cc
index a404e9f2690..b568c7d0326 100644
--- a/gcc/ira-costs.cc
+++ b/gcc/ira-costs.cc
@@ -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;
diff --git a/gcc/testsuite/gcc.target/aarch64/pr114991.c b/gcc/testsuite/gcc.target/aarch64/pr114991.c
new file mode 100644
index 00000000000..d3c7bd131dd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr114991.c
@@ -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" } } */