summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-12-01 08:27:58 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2018-12-01 08:27:58 +0100
commit6b4f5050a9a5156eb23b9174ff576a77b1149465 (patch)
treeaee5b5dee90397d7a4c1d9984482cdc9fbcfc202 /gcc
parent1072cfdf34f5fda7091282a4780f4974cac306d3 (diff)
re PR target/54589 (struct offset add should be folded into address calculation)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/combine.c49
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/i386/pr54589.c22
4 files changed, 78 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6ce31bf8927..b215a9c6357 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/combine.c b/gcc/combine.c
index ecc83f89bce..7e611399f2c 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -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);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b48e353d05d..c5ca4be86c4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..c1032d71c29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr54589.c
@@ -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;
+}