aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>2018-06-29 13:36:35 +0000
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>2018-06-29 13:36:35 +0000
commit52057dc4ac5295caebf83147f688d769c93cbc8d (patch)
tree95dfcfdded0b4e95879b33b300ba999cb847f437 /gcc
parentb33aa7209ed570864189dba4c070565ea4a1554b (diff)
downloadgcc-52057dc4ac5295caebf83147f688d769c93cbc8d.zip
gcc-52057dc4ac5295caebf83147f688d769c93cbc8d.tar.gz
gcc-52057dc4ac5295caebf83147f688d769c93cbc8d.tar.bz2
[arm] Avoid STRD with odd register for TARGET_ARM in output_move_double
In this testcase the user forces an odd register as the starting reg for a DFmode value. The output_move_double function tries to store that using an STRD instruction. But for TARGET_ARM the starting register of an STRD must be an even one. This is always the case with compiler-allocated registers for DFmode values, but the inline assembly forced our hand here. This patch restricts the STRD-emitting logic in output_move_double to not avoid odd-numbered source registers in STRD. I'm not a fan of the whole function, we should be exposing a lot of the logic in there to RTL rather than at the final output stage, but that would need to be fixed separately. * config/arm/arm.c (output_move_double): Don't allow STRD instructions if starting source register is not even. * gcc.target/arm/arm-soft-strd-even.c: New test. From-SVN: r262250
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/config/arm/arm.c22
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.target/arm/arm-soft-strd-even.c18
4 files changed, 41 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4401245..a76fea9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2018-06-29 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * config/arm/arm.c (output_move_double): Don't allow STRD instructions
+ if starting source register is not even.
+
2018-06-29 Martin Liska <mliska@suse.cz>
PR tree-optimization/86263
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index c70be36..f1a9958 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -18463,12 +18463,18 @@ output_move_double (rtx *operands, bool emit, int *count)
gcc_assert ((REGNO (operands[1]) != IP_REGNUM)
|| (TARGET_ARM && TARGET_LDRD));
+ /* For TARGET_ARM the first source register of an STRD
+ must be even. This is usually the case for double-word
+ values but user assembly constraints can force an odd
+ starting register. */
+ bool allow_strd = TARGET_LDRD
+ && !(TARGET_ARM && (REGNO (operands[1]) & 1) == 1);
switch (GET_CODE (XEXP (operands[0], 0)))
{
case REG:
if (emit)
{
- if (TARGET_LDRD)
+ if (allow_strd)
output_asm_insn ("strd%?\t%1, [%m0]", operands);
else
output_asm_insn ("stm%?\t%m0, %M1", operands);
@@ -18476,7 +18482,7 @@ output_move_double (rtx *operands, bool emit, int *count)
break;
case PRE_INC:
- gcc_assert (TARGET_LDRD);
+ gcc_assert (allow_strd);
if (emit)
output_asm_insn ("strd%?\t%1, [%m0, #8]!", operands);
break;
@@ -18484,7 +18490,7 @@ output_move_double (rtx *operands, bool emit, int *count)
case PRE_DEC:
if (emit)
{
- if (TARGET_LDRD)
+ if (allow_strd)
output_asm_insn ("strd%?\t%1, [%m0, #-8]!", operands);
else
output_asm_insn ("stmdb%?\t%m0!, %M1", operands);
@@ -18494,7 +18500,7 @@ output_move_double (rtx *operands, bool emit, int *count)
case POST_INC:
if (emit)
{
- if (TARGET_LDRD)
+ if (allow_strd)
output_asm_insn ("strd%?\t%1, [%m0], #8", operands);
else
output_asm_insn ("stm%?\t%m0!, %M1", operands);
@@ -18502,7 +18508,7 @@ output_move_double (rtx *operands, bool emit, int *count)
break;
case POST_DEC:
- gcc_assert (TARGET_LDRD);
+ gcc_assert (allow_strd);
if (emit)
output_asm_insn ("strd%?\t%1, [%m0], #-8", operands);
break;
@@ -18513,8 +18519,8 @@ output_move_double (rtx *operands, bool emit, int *count)
otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
- /* IWMMXT allows offsets larger than ldrd can handle,
- fix these up with a pair of ldr. */
+ /* IWMMXT allows offsets larger than strd can handle,
+ fix these up with a pair of str. */
if (!TARGET_THUMB2
&& CONST_INT_P (otherops[2])
&& (INTVAL(otherops[2]) <= -256
@@ -18579,7 +18585,7 @@ output_move_double (rtx *operands, bool emit, int *count)
return "";
}
}
- if (TARGET_LDRD
+ if (allow_strd
&& (REG_P (otherops[2])
|| TARGET_THUMB2
|| (CONST_INT_P (otherops[2])
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c7fef193..9072c6d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2018-06-29 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * gcc.target/arm/arm-soft-strd-even.c: New test.
+
2018-06-29 Tom de Vries <tdevries@suse.de>
* gcc.dg/guality/pr45882.c (foo): Add line number var for breakpoint
diff --git a/gcc/testsuite/gcc.target/arm/arm-soft-strd-even.c b/gcc/testsuite/gcc.target/arm/arm-soft-strd-even.c
new file mode 100644
index 0000000..fb7317c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/arm-soft-strd-even.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-require-effective-target arm_arm_ok } */
+/* { dg-options "-O2 -marm -mfloat-abi=soft" } */
+
+/* Check that we don't try to emit STRD in ARM state with
+ odd starting register. */
+
+struct S {
+ double M0;
+} __attribute((aligned)) __attribute((packed));
+
+void bar(void *);
+
+void foo(int x, struct S y) {
+ asm("" : : : "r1", "r8", "r7", "r4");
+ y.M0 ?: bar(0);
+ bar(__builtin_alloca(8));
+}