diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bc1e8cb4fcf..1f9c54e0b7c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2017-10-19 Richard Earnshaw + + PR target/82445 + * config/arm/arm.c (align_ok_ldrd_strd): New function. + (mem_ok_for_ldrd_strd): New parameter align. Extract the alignment of + the mem into it. + (gen_operands_ldrd_strd): Validate the alignment of the accesses. + 2017-10-18 Segher Boessenkool PR rtl-optimization/82602 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 1ded0d2a17d..989957f048e 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -15199,12 +15199,23 @@ operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rn, HOST_WIDE_INT offset, return true; } +/* Return true if a 64-bit access with alignment ALIGN and with a + constant offset OFFSET from the base pointer is permitted on this + architecture. */ +static bool +align_ok_ldrd_strd (HOST_WIDE_INT align, HOST_WIDE_INT offset) +{ + return (unaligned_access + ? (align >= BITS_PER_WORD && (offset & 3) == 0) + : (align >= 2 * BITS_PER_WORD && (offset & 7) == 0)); +} + /* Helper for gen_operands_ldrd_strd. Returns true iff the memory operand MEM's address contains an immediate offset from the base - register and has no side effects, in which case it sets BASE and - OFFSET accordingly. */ + register and has no side effects, in which case it sets BASE, + OFFSET and ALIGN accordingly. */ static bool -mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset) +mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset, HOST_WIDE_INT *align) { rtx addr; @@ -15223,6 +15234,7 @@ mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset) gcc_assert (MEM_P (mem)); *offset = const0_rtx; + *align = MEM_ALIGN (mem); addr = XEXP (mem, 0); @@ -15263,7 +15275,7 @@ gen_operands_ldrd_strd (rtx *operands, bool load, bool const_store, bool commute) { int nops = 2; - HOST_WIDE_INT offsets[2], offset; + HOST_WIDE_INT offsets[2], offset, align[2]; rtx base = NULL_RTX; rtx cur_base, cur_offset, tmp; int i, gap; @@ -15275,7 +15287,8 @@ gen_operands_ldrd_strd (rtx *operands, bool load, registers, and the corresponding memory offsets. */ for (i = 0; i < nops; i++) { - if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset)) + if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset, + &align[i])) return false; if (i == 0) @@ -15389,6 +15402,7 @@ gen_operands_ldrd_strd (rtx *operands, bool load, /* Swap the instructions such that lower memory is accessed first. */ std::swap (operands[0], operands[1]); std::swap (operands[2], operands[3]); + std::swap (align[0], align[1]); if (const_store) std::swap (operands[4], operands[5]); } @@ -15402,6 +15416,9 @@ gen_operands_ldrd_strd (rtx *operands, bool load, if (gap != 4) return false; + if (!align_ok_ldrd_strd (align[0], offset)) + return false; + /* Make sure we generate legal instructions. */ if (operands_ok_ldrd_strd (operands[0], operands[1], base, offset, false, load)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fea70feae8d..cc07f8b0bb2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2017-10-19 Richard Earnshaw + + PR target/82445 + * gcc.target/arm/peep-ldrd-1.c: Tighten test scan pattern. + * gcc.target/arm/peep-strd-1.c: Likewise. + * gcc.target/arm/peep-ldrd-2.c: New test. + * gcc.target/arm/peep-strd-2.c: New test. + 2017-10-18 Vladimir Makarov PR middle-end/82556 diff --git a/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c b/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c index eb2b86ee7b6..d49eff6b87e 100644 --- a/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c +++ b/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c @@ -8,4 +8,4 @@ int foo(int a, int b, int* p, int *q) *p = a; return a; } -/* { dg-final { scan-assembler "ldrd" } } */ +/* { dg-final { scan-assembler "ldrd\\t" } } */ diff --git a/gcc/testsuite/gcc.target/arm/peep-ldrd-2.c b/gcc/testsuite/gcc.target/arm/peep-ldrd-2.c new file mode 100644 index 00000000000..6822c2b1454 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/peep-ldrd-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_prefer_ldrd_strd } */ +/* { dg-options "-O2 -mno-unaligned-access" } */ +int foo(int a, int b, int* p, int *q) +{ + a = p[2] + p[3]; + *q = a; + *p = a; + return a; +} +/* { dg-final { scan-assembler-not "ldrd\\t" } } */ diff --git a/gcc/testsuite/gcc.target/arm/peep-strd-1.c b/gcc/testsuite/gcc.target/arm/peep-strd-1.c index bd330769599..fe1beac7229 100644 --- a/gcc/testsuite/gcc.target/arm/peep-strd-1.c +++ b/gcc/testsuite/gcc.target/arm/peep-strd-1.c @@ -6,4 +6,4 @@ void foo(int a, int b, int* p) p[2] = a; p[3] = b; } -/* { dg-final { scan-assembler "strd" } } */ +/* { dg-final { scan-assembler "strd\\t" } } */ diff --git a/gcc/testsuite/gcc.target/arm/peep-strd-2.c b/gcc/testsuite/gcc.target/arm/peep-strd-2.c new file mode 100644 index 00000000000..bfc5ebe9eec --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/peep-strd-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_prefer_ldrd_strd } */ +/* { dg-options "-O2 -mno-unaligned-access" } */ +void foo(int a, int b, int* p) +{ + p[2] = a; + p[3] = b; +} +/* { dg-final { scan-assembler-not "strd\\t" } } */