The commit 2c0fa3ecf70d199af18785702e9e0548fd3ab793 reuses VALUEs on sp
adjustments.  We can generalize the idea and reuse VALUEs on other
registers.  This can help the postreload pass find more opportunities to
simplify insns.

The following assembly code is generated from the testcase using the current
trunk compiler:

.L5:
        movq    %rbp, %rsi
        movq    %rbx, %rdi
        call    l
        movq    %rbx, %rsi
        addq    $4, %rbx
        testl   %eax, %eax
        je      .L6
        leaq    -4(%rbx), %rax
        cmpq    %rax, %rbp
        je      .L6
        movq    %rbx, %rdi
        call    as

The lea instruction is actually redundant here, as rsi contains the same
value as rbx-4 and can be used in the cmp instruction instead of rax.
With this patch, the lea instruction can be eliminated in the postreload
pass.

Bootstrapped and regtested on x86_64-pc-linux-gnu, no regressions.
---
 gcc/cselib.cc                            | 29 ++++++++++++++----------
 gcc/rtl.h                                |  1 +
 gcc/testsuite/gcc.target/i386/cselib-1.c | 22 ++++++++++++++++++
 3 files changed, 40 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/cselib-1.c

diff --git a/gcc/cselib.cc b/gcc/cselib.cc
index e6a36e892bb..43ab266c4de 100644
--- a/gcc/cselib.cc
+++ b/gcc/cselib.cc
@@ -70,6 +70,9 @@ static rtx autoinc_split (rtx, rtx *, machine_mode);
 #define SP_DERIVED_VALUE_P(RTX) \
   (RTL_FLAG_CHECK1 ("SP_DERIVED_VALUE_P", (RTX), VALUE)->call)
 
+#define REG_DERIVED_VALUE_P(RTX) \
+  (RTL_FLAG_CHECK1 ("REG_DERIVED_VALUE_P", (RTX), VALUE)->volatil)
+
 struct expand_value_data
 {
   bitmap regs_active;
@@ -137,7 +140,7 @@ cselib_hasher::equal (const cselib_val *v, const key *x_arg)
   if (GET_CODE (x) == VALUE)
     return x == v->val_rtx;
 
-  if (SP_DERIVED_VALUE_P (v->val_rtx) && GET_MODE (x) == Pmode)
+  if (REG_DERIVED_VALUE_P (v->val_rtx) && GET_MODE (x) == Pmode)
     {
       rtx xoff = NULL;
       if (autoinc_split (x, &xoff, memmode) == v->val_rtx && xoff == NULL_RTX)
@@ -905,7 +908,7 @@ autoinc_split (rtx x, rtx *off, machine_mode memmode)
        e = cselib_lookup (x, GET_MODE (x), 0, memmode);
       if (e)
        {
-         if (SP_DERIVED_VALUE_P (e->val_rtx)
+         if (REG_DERIVED_VALUE_P (e->val_rtx)
              && (*off == NULL_RTX || *off == const0_rtx))
            {
              *off = NULL_RTX;
@@ -914,7 +917,7 @@ autoinc_split (rtx x, rtx *off, machine_mode memmode)
          for (struct elt_loc_list *l = e->locs; l; l = l->next)
            if (GET_CODE (l->loc) == PLUS
                && GET_CODE (XEXP (l->loc, 0)) == VALUE
-               && SP_DERIVED_VALUE_P (XEXP (l->loc, 0))
+               && REG_DERIVED_VALUE_P (XEXP (l->loc, 0))
                && CONST_INT_P (XEXP (l->loc, 1)))
              {
                if (*off == NULL_RTX)
@@ -971,8 +974,8 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, machine_mode memmode, 
int depth)
       if (GET_CODE (y) == VALUE)
        return e == canonical_cselib_val (CSELIB_VAL_PTR (y));
 
-      if ((SP_DERIVED_VALUE_P (x)
-          || SP_DERIVED_VALUE_P (e->val_rtx))
+      if ((REG_DERIVED_VALUE_P (x)
+          || REG_DERIVED_VALUE_P (e->val_rtx))
          && GET_MODE (y) == Pmode)
        {
          rtx yoff = NULL;
@@ -1004,8 +1007,8 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, machine_mode 
memmode, int depth)
       cselib_val *e = canonical_cselib_val (CSELIB_VAL_PTR (y));
       struct elt_loc_list *l;
 
-      if ((SP_DERIVED_VALUE_P (y)
-          || SP_DERIVED_VALUE_P (e->val_rtx))
+      if ((REG_DERIVED_VALUE_P (y)
+          || REG_DERIVED_VALUE_P (e->val_rtx))
          && GET_MODE (x) == Pmode)
        {
          rtx xoff = NULL;
@@ -1257,11 +1260,11 @@ cselib_hash_plus_const_int (rtx x, HOST_WIDE_INT c, int 
create,
   if (! e)
     return 0;
 
-  if (! SP_DERIVED_VALUE_P (e->val_rtx))
+  if (! REG_DERIVED_VALUE_P (e->val_rtx))
     for (struct elt_loc_list *l = e->locs; l; l = l->next)
       if (GET_CODE (l->loc) == PLUS
          && GET_CODE (XEXP (l->loc, 0)) == VALUE
-         && SP_DERIVED_VALUE_P (XEXP (l->loc, 0))
+         && REG_DERIVED_VALUE_P (XEXP (l->loc, 0))
          && CONST_INT_P (XEXP (l->loc, 1)))
        {
          e = CSELIB_VAL_PTR (XEXP (l->loc, 0));
@@ -2233,13 +2236,13 @@ cselib_subst_to_values (rtx x, machine_mode memmode)
          rtx t = cselib_subst_to_values (XEXP (x, 0), memmode);
          if (GET_CODE (t) == VALUE)
            {
-             if (SP_DERIVED_VALUE_P (t) && XEXP (x, 1) == const0_rtx)
+             if (REG_DERIVED_VALUE_P (t) && XEXP (x, 1) == const0_rtx)
                return t;
              for (struct elt_loc_list *l = CSELIB_VAL_PTR (t)->locs;
                   l; l = l->next)
                if (GET_CODE (l->loc) == PLUS
                    && GET_CODE (XEXP (l->loc, 0)) == VALUE
-                   && SP_DERIVED_VALUE_P (XEXP (l->loc, 0))
+                   && REG_DERIVED_VALUE_P (XEXP (l->loc, 0))
                    && CONST_INT_P (XEXP (l->loc, 1)))
                  return plus_constant (Pmode, l->loc, INTVAL (XEXP (x, 1)));
            }
@@ -2355,6 +2358,8 @@ cselib_lookup_1 (rtx x, machine_mode mode,
       e = new_cselib_val (next_uid, GET_MODE (x), x);
       if (GET_MODE (x) == Pmode && x == stack_pointer_rtx)
        SP_DERIVED_VALUE_P (e->val_rtx) = 1;
+      if (GET_MODE (x) == Pmode && REG_P (x))
+       REG_DERIVED_VALUE_P (e->val_rtx) = 1;
       new_elt_loc_list (e, x);
 
       scalar_int_mode int_mode;
@@ -2436,7 +2441,7 @@ cselib_lookup_1 (rtx x, machine_mode mode,
 
   /* If cselib_preserve_constants, we might get a SP_DERIVED_VALUE_P
      VALUE that isn't in the hash tables anymore.  */
-  if (GET_CODE (v) == VALUE && SP_DERIVED_VALUE_P (v) && PRESERVED_VALUE_P (v))
+  if (GET_CODE (v) == VALUE && REG_DERIVED_VALUE_P (v) && PRESERVED_VALUE_P 
(v))
     PRESERVED_VALUE_P (e->val_rtx) = 1;
 
   new_elt_loc_list (e, v);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index f298096a5a6..6ea206af04f 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -360,6 +360,7 @@ struct GTY((desc("0"), tag("0"),
      In a PREFETCH, this flag indicates that it should be considered a
      scheduling barrier.
      1 in a CONCAT is VAL_NEEDS_RESOLUTION in var-tracking.cc.
+     1 in a VALUE that is REG_DERIVED_VALUE_P in cselib.cc.
      Dumped as "/v" in RTL dumps.  */
   unsigned int volatil : 1;
   /* 1 in a REG if the register is used only in exit code a loop.
diff --git a/gcc/testsuite/gcc.target/i386/cselib-1.c 
b/gcc/testsuite/gcc.target/i386/cselib-1.c
new file mode 100644
index 00000000000..248193add8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cselib-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target { x86_64-*-* } } } */
+/* { dg-options "-O3" } */
+/* { dg-final { scan-assembler-not "leaq" } } */
+
+extern int l(int *, int *);
+extern void as(int *, int *);
+extern int *q();
+
+void m(int *k, int *al, int *aw) {
+  if (k != al)
+    as(aw, al);
+}
+
+void d() {
+  int *p = q(), *e = q();
+  int *c;
+  for (int *b = p; b != e; ++b)
+    if (l(b, p)) {
+      c = b + 1;
+      m(p, b, c);
+    }
+}
-- 
2.46.0

Reply via email to