From 6b4f5050a9a5156eb23b9174ff576a77b1149465 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 1 Dec 2018 08:27:58 +0100 Subject: [PATCH] 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 --- gcc/ChangeLog | 8 ++++ gcc/combine.c | 49 ++++++++++++++++++++++--- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.target/i386/pr54589.c | 22 +++++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr54589.c 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 + + 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 * 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 + + PR target/54589 + * gcc.target/i386/pr54589.c: New test. + 2018-11-30 Jakub Jelinek 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; +} -- 2.30.2