re PR target/54589 (struct offset add should be folded into address calculation)
authorJakub Jelinek <jakub@redhat.com>
Sat, 1 Dec 2018 07:27:58 +0000 (08:27 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sat, 1 Dec 2018 07:27:58 +0000 (08:27 +0100)
PR target/54589
* combine.c (find_split_point): For invalid memory address
nonobj + obj + const, if reg + obj + const is valid addressing
mode, split at nonobj.  Use if rather than else if for the
fallback.  Comment fixes.

* gcc.target/i386/pr54589.c: New test.

From-SVN: r266707

gcc/ChangeLog
gcc/combine.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr54589.c [new file with mode: 0644]

index 6ce31bf..b215a9c 100644 (file)
@@ -1,3 +1,11 @@
+2018-12-01  Jakub Jelinek  <jakub@redhat.com>
+
+       PR target/54589
+       * combine.c (find_split_point): For invalid memory address
+       nonobj + obj + const, if reg + obj + const is valid addressing
+       mode, split at nonobj.  Use if rather than else if for the
+       fallback.  Comment fixes.
+
 2018-11-30  Indu Bhagat  <indu.bhagat@oracle.com>
 
        * coverage.c (get_coverage_counts): Use from_function_decl for precise
index ecc83f8..7e61139 100644 (file)
@@ -4945,7 +4945,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
        }
 
       /* If we have a PLUS whose second operand is a constant and the
-        address is not valid, perhaps will can split it up using
+        address is not valid, perhaps we can split it up using
         the machine-specific way to split large constants.  We use
         the first pseudo-reg (one of the virtual regs) as a placeholder;
         it will not remain in the result.  */
@@ -4960,7 +4960,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
 
          /* This should have produced two insns, each of which sets our
             placeholder.  If the source of the second is a valid address,
-            we can make put both sources together and make a split point
+            we can put both sources together and make a split point
             in the middle.  */
 
          if (seq
@@ -5001,14 +5001,51 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
                }
            }
 
+         /* If that didn't work and we have a nested plus, like:
+            ((REG1 * CONST1) + REG2) + CONST2 and (REG1 + REG2) + CONST2
+            is valid address, try to split (REG1 * CONST1).  */
+         if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+             && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+             && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+             && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SUBREG
+                   && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+                                                        0), 0)))))
+           {
+             rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 0);
+             XEXP (XEXP (XEXP (x, 0), 0), 0) = reg;
+             if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                              MEM_ADDR_SPACE (x)))
+               {
+                 XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+                 return &XEXP (XEXP (XEXP (x, 0), 0), 0);
+               }
+             XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+           }
+         else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+                  && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+                  && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+                  && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == SUBREG
+                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+                                                             0), 1)))))
+           {
+             rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 1);
+             XEXP (XEXP (XEXP (x, 0), 0), 1) = reg;
+             if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                              MEM_ADDR_SPACE (x)))
+               {
+                 XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+                 return &XEXP (XEXP (XEXP (x, 0), 0), 1);
+               }
+             XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+           }
+
          /* If that didn't work, perhaps the first operand is complex and
             needs to be computed separately, so make a split point there.
             This will occur on machines that just support REG + CONST
             and have a constant moved through some previous computation.  */
-
-         else if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
-                  && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
-                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+         if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
+             && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+                   && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
            return &XEXP (XEXP (x, 0), 0);
        }
 
index b48e353..c5ca4be 100644 (file)
@@ -1,3 +1,8 @@
+2018-12-01  Jakub Jelinek  <jakub@redhat.com>
+
+       PR target/54589
+       * gcc.target/i386/pr54589.c: New test.
+
 2018-11-30  Jakub Jelinek  <jakub@redhat.com>
 
        PR testsuite/85368
diff --git a/gcc/testsuite/gcc.target/i386/pr54589.c b/gcc/testsuite/gcc.target/i386/pr54589.c
new file mode 100644 (file)
index 0000000..c1032d7
--- /dev/null
@@ -0,0 +1,22 @@
+/* PR target/54589 */
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler "movl\[ \t]+(?:t\\+336\\(%r..\\)|336\\(%r..,%r..\\)), %eax" } } */
+/* { dg-final { scan-assembler "movl\[ \t]+340\\(%r..,%r..\\), %eax" } } */
+/* { dg-final { scan-assembler-times "salq\[^\n\r]*4, %" 2 } } */
+/* { dg-final { scan-assembler-not "addq\[ \t]" } } */
+
+struct S { int a, b, c, d; };
+struct T { struct S e[16]; struct S f[1024]; } t;
+
+int
+foo (unsigned long x)
+{
+  return t.f[x + 5].a;
+}
+
+int
+bar (struct T *x, unsigned long y)
+{
+  return x->f[y + 5].b;
+}