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);
break;
case PRE_INC:
- gcc_assert (TARGET_LDRD);
+ gcc_assert (allow_strd);
if (emit)
output_asm_insn ("strd%?\t%1, [%m0, #8]!", operands);
break;
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);
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);
break;
case POST_DEC:
- gcc_assert (TARGET_LDRD);
+ gcc_assert (allow_strd);
if (emit)
output_asm_insn ("strd%?\t%1, [%m0], #-8", operands);
break;
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
return "";
}
}
- if (TARGET_LDRD
+ if (allow_strd
&& (REG_P (otherops[2])
|| TARGET_THUMB2
|| (CONST_INT_P (otherops[2])
--- /dev/null
+/* { 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));
+}