Commit 52057dc4 by Kyrylo Tkachov Committed by Kyrylo Tkachov

[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
parent b33aa720
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> 2018-06-29 Martin Liska <mliska@suse.cz>
PR tree-optimization/86263 PR tree-optimization/86263
......
...@@ -18463,12 +18463,18 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18463,12 +18463,18 @@ output_move_double (rtx *operands, bool emit, int *count)
gcc_assert ((REGNO (operands[1]) != IP_REGNUM) gcc_assert ((REGNO (operands[1]) != IP_REGNUM)
|| (TARGET_ARM && TARGET_LDRD)); || (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))) switch (GET_CODE (XEXP (operands[0], 0)))
{ {
case REG: case REG:
if (emit) if (emit)
{ {
if (TARGET_LDRD) if (allow_strd)
output_asm_insn ("strd%?\t%1, [%m0]", operands); output_asm_insn ("strd%?\t%1, [%m0]", operands);
else else
output_asm_insn ("stm%?\t%m0, %M1", operands); output_asm_insn ("stm%?\t%m0, %M1", operands);
...@@ -18476,7 +18482,7 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18476,7 +18482,7 @@ output_move_double (rtx *operands, bool emit, int *count)
break; break;
case PRE_INC: case PRE_INC:
gcc_assert (TARGET_LDRD); gcc_assert (allow_strd);
if (emit) if (emit)
output_asm_insn ("strd%?\t%1, [%m0, #8]!", operands); output_asm_insn ("strd%?\t%1, [%m0, #8]!", operands);
break; break;
...@@ -18484,7 +18490,7 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18484,7 +18490,7 @@ output_move_double (rtx *operands, bool emit, int *count)
case PRE_DEC: case PRE_DEC:
if (emit) if (emit)
{ {
if (TARGET_LDRD) if (allow_strd)
output_asm_insn ("strd%?\t%1, [%m0, #-8]!", operands); output_asm_insn ("strd%?\t%1, [%m0, #-8]!", operands);
else else
output_asm_insn ("stmdb%?\t%m0!, %M1", operands); output_asm_insn ("stmdb%?\t%m0!, %M1", operands);
...@@ -18494,7 +18500,7 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18494,7 +18500,7 @@ output_move_double (rtx *operands, bool emit, int *count)
case POST_INC: case POST_INC:
if (emit) if (emit)
{ {
if (TARGET_LDRD) if (allow_strd)
output_asm_insn ("strd%?\t%1, [%m0], #8", operands); output_asm_insn ("strd%?\t%1, [%m0], #8", operands);
else else
output_asm_insn ("stm%?\t%m0!, %M1", operands); output_asm_insn ("stm%?\t%m0!, %M1", operands);
...@@ -18502,7 +18508,7 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18502,7 +18508,7 @@ output_move_double (rtx *operands, bool emit, int *count)
break; break;
case POST_DEC: case POST_DEC:
gcc_assert (TARGET_LDRD); gcc_assert (allow_strd);
if (emit) if (emit)
output_asm_insn ("strd%?\t%1, [%m0], #-8", operands); output_asm_insn ("strd%?\t%1, [%m0], #-8", operands);
break; break;
...@@ -18513,8 +18519,8 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18513,8 +18519,8 @@ output_move_double (rtx *operands, bool emit, int *count)
otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0); otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1); otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
/* IWMMXT allows offsets larger than ldrd can handle, /* IWMMXT allows offsets larger than strd can handle,
fix these up with a pair of ldr. */ fix these up with a pair of str. */
if (!TARGET_THUMB2 if (!TARGET_THUMB2
&& CONST_INT_P (otherops[2]) && CONST_INT_P (otherops[2])
&& (INTVAL(otherops[2]) <= -256 && (INTVAL(otherops[2]) <= -256
...@@ -18579,7 +18585,7 @@ output_move_double (rtx *operands, bool emit, int *count) ...@@ -18579,7 +18585,7 @@ output_move_double (rtx *operands, bool emit, int *count)
return ""; return "";
} }
} }
if (TARGET_LDRD if (allow_strd
&& (REG_P (otherops[2]) && (REG_P (otherops[2])
|| TARGET_THUMB2 || TARGET_THUMB2
|| (CONST_INT_P (otherops[2]) || (CONST_INT_P (otherops[2])
......
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> 2018-06-29 Tom de Vries <tdevries@suse.de>
* gcc.dg/guality/pr45882.c (foo): Add line number var for breakpoint * gcc.dg/guality/pr45882.c (foo): Add line number var for breakpoint
......
/* { 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));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment