RA: Implement reuse of equivalent memory for caller saves optimization (2nd version)
authorVladimir N. Makarov <vmakarov@redhat.com>
Thu, 9 Feb 2023 20:18:48 +0000 (15:18 -0500)
committerVladimir N. Makarov <vmakarov@redhat.com>
Thu, 9 Feb 2023 21:48:21 +0000 (16:48 -0500)
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.

gcc/ira.cc
gcc/ira.h
gcc/lra-constraints.cc
gcc/testsuite/g++.target/i386/pr108711.C [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr103541.c [new file with mode: 0644]

index 66df03e..6143db0 100644 (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;
                  }
index 58b50db..3d35025 100644 (file)
--- a/gcc/ira.h
+++ b/gcc/ira.h
@@ -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
index 7bffbc0..dd4f68b 100644 (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)
diff --git a/gcc/testsuite/g++.target/i386/pr108711.C b/gcc/testsuite/g++.target/i386/pr108711.C
new file mode 100644 (file)
index 0000000..0a223e0
--- /dev/null
@@ -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_);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr103541.c b/gcc/testsuite/gcc.target/i386/pr103541.c
new file mode 100644 (file)
index 0000000..72b257d
--- /dev/null
@@ -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\\\)" } } */