[PATCH: ARM] PR 45335 Use ldrd and strd to access two consecutive words

Carrot Wei carrot@google.com
Tue Mar 29 10:18:00 GMT 2011


Thank you for the knowledge. I've updated the insn patterns
accordingly. Again tested on arm qemu.

thanks
Carrot

ChangeLog:
2011-03-29  Wei Guozhi  <carrot@google.com>

        PR target/45335
        * gcc/config/arm/ldmstm.md (ldm2_ia, stm2_ia, ldm2_ib, stm2_ib, ldm2_da,
        stm2_da, ldm2_db, stm2_db): Add condition !arm_arch7 to these insns.
        (ldrd, ldrd_reg1, ldrd_reg2 and peephole2): New insn patterns and
        related peephole2.
        (strd, strd_reg1, strd_reg2 and peephole2): New insn patterns and
        related peephole2.
        * gcc/config/arm/arm-protos.h (arm_check_ldrd_operands): New prototype.
        (arm_legitimate_ldrd_p): New prototype.
        (arm_output_ldrd): New prototype.
        * gcc/config/arm/arm.c (arm_check_ldrd_operands): New function.
        (arm_legitimate_ldrd_p): New function.
        (arm_output_ldrd): New function.


2011-03-29  Wei Guozhi  <carrot@google.com>

        PR target/45335
        * gcc.target/arm/pr45335.c: New test.
        * gcc.target/arm/pr45335-2.c: New test.
        * gcc.target/arm/pr45335-3.c: New test.
        * gcc.target/arm/pr40457-1.c: Add another possible output "ldrd".
        * gcc.target/arm/pr40457-2.c: Changed to store 3 words.
        * gcc.target/arm/pr40457-3.c: Changed to store 3 words.


On Thu, Mar 24, 2011 at 8:25 AM, Mike Stump <mikestump@comcast.net> wrote:
> On Jan 18, 2011, at 6:59 AM, Carrot Wei wrote:
>> +(define_insn "*ldrd"
>> +  [(parallel [(set (match_operand:SI 0 "arm_hard_register_operand" "")
>
> parallel is implicit, you can safely remove it from all define_insns.
>
-------------- next part --------------
Index: testsuite/gcc.target/arm/pr40457-3.c
===================================================================
--- testsuite/gcc.target/arm/pr40457-3.c	(revision 171439)
+++ testsuite/gcc.target/arm/pr40457-3.c	(working copy)
@@ -5,6 +5,7 @@ void foo(int* p)
 {
   p[0] = 1;
   p[1] = 0;
+  p[2] = 2;
 }
 
 /* { dg-final { scan-assembler "stm" } } */
Index: testsuite/gcc.target/arm/pr45335-2.c
===================================================================
--- testsuite/gcc.target/arm/pr45335-2.c	(revision 0)
+++ testsuite/gcc.target/arm/pr45335-2.c	(revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-Os -march=armv7-a" }  */
+/* { dg-do compile } */
+
+void foo(int a, int b, int* p)
+{
+  p[2] = a;
+  p[3] = b;
+}
+
+/* { dg-final { scan-assembler "strd" } } */
Index: testsuite/gcc.target/arm/pr45335-3.c
===================================================================
--- testsuite/gcc.target/arm/pr45335-3.c	(revision 0)
+++ testsuite/gcc.target/arm/pr45335-3.c	(revision 0)
@@ -0,0 +1,12 @@
+/* { dg-options "-Os -march=armv7-a" }  */
+/* { dg-do compile } */
+
+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 "ldrd" } } */
Index: testsuite/gcc.target/arm/pr40457-1.c
===================================================================
--- testsuite/gcc.target/arm/pr40457-1.c	(revision 171439)
+++ testsuite/gcc.target/arm/pr40457-1.c	(working copy)
@@ -7,4 +7,4 @@ int bar(int* p)
   return x;
 }
 
-/* { dg-final { scan-assembler "ldm" } } */
+/* { dg-final { scan-assembler "ldm|ldrd" } } */
Index: testsuite/gcc.target/arm/pr40457-2.c
===================================================================
--- testsuite/gcc.target/arm/pr40457-2.c	(revision 171439)
+++ testsuite/gcc.target/arm/pr40457-2.c	(working copy)
@@ -5,6 +5,7 @@ void foo(int* p)
 {
   p[0] = 1;
   p[1] = 0;
+  p[2] = 2;
 }
 
 /* { dg-final { scan-assembler "stm" } } */
Index: testsuite/gcc.target/arm/pr45335.c
===================================================================
--- testsuite/gcc.target/arm/pr45335.c	(revision 0)
+++ testsuite/gcc.target/arm/pr45335.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-final { scan-assembler "ldrd" } } */
+/* { dg-final { scan-assembler "strd" } } */
+
+struct S
+{
+    void* p1;
+    void* p2;
+    void* p3;
+    void* p4;
+};
+
+extern printf(char*, ...);
+
+void foo1(struct S* fp, struct S* otherSaveArea)
+{
+    struct S* saveA = fp - 1;
+    printf("StackSaveArea for fp %p [%p/%p]:\n", fp, saveA, otherSaveArea);
+    printf("prevFrame=%p savedPc=%p meth=%p curPc=%p fp[0]=0x%08x\n",
+        saveA->p1, saveA->p2, saveA->p3, saveA->p4, *(unsigned int*)fp);
+}
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c	(revision 171439)
+++ config/arm/arm.c	(working copy)
@@ -23681,4 +23681,234 @@ arm_preferred_rename_class (reg_class_t 
     return NO_REGS;
 }
 
+/* Check the validity of operands in an ldrd/strd instruction.  */
+bool
+arm_check_ldrd_operands (rtx reg1, rtx reg2, rtx off1, rtx off2)
+{
+  HOST_WIDE_INT offset1 = 0;
+  HOST_WIDE_INT offset2 = 0;
+  int regno1 = REGNO (reg1);
+  int regno2 = REGNO (reg2);
+  HOST_WIDE_INT max_offset = 1020;
+
+  if (TARGET_ARM)
+    max_offset = 255;
+
+  if (off1 != NULL_RTX)
+    offset1 = INTVAL (off1);
+  if (off2 != NULL_RTX)
+    offset2 = INTVAL (off2);
+
+  /* The offset range of LDRD is [-max_offset, max_offset]. Here we check if
+     both offsets lie in the range [-max_offset, max_offset+4]. If one of the
+     offsets is max_offset+4, the following condition
+	((offset1 + 4) == offset2)
+     will ensure offset1 to be max_offset, suitable for instruction LDRD.  */
+  if ((offset1 > (max_offset + 4)) || (offset1 < -max_offset)
+      || ((offset1 & 3) != 0))
+    return false;
+  if ((offset2 > (max_offset + 4)) || (offset2 < -max_offset)
+      || ((offset2 & 3) != 0))
+    return false;
+
+  if ((offset1 + 4) == offset2)
+    {
+      if (TARGET_THUMB2)
+	return true;
+
+      /* TARGET_ARM  */
+      if (((regno1 & 1) == 0) && ((regno1 + 1) == regno2))           /* ldrd  */
+	return true;
+
+      if ((regno1 < regno2) && ((offset1 <= 4) && (offset1 >= -8)))  /* ldm  */
+	return true;
+    }
+  if ((offset2 + 4) == offset1)
+    {
+      if (TARGET_THUMB2)
+	return true;
+
+      /* TARGET_ARM  */
+      if (((regno2 & 1) == 0) && ((regno2 + 1) == regno1))           /* ldrd  */
+	return true;
+
+      if ((regno2 < regno1) && ((offset2 <= 4) && (offset2 >= -8)))  /* ldm  */
+	return true;
+    }
+
+  return false;
+}
+
+/* Check if the two memory accesses can be merged to an ldrd/strd instruction.
+   That is they use the same base register, and the gap between constant
+   offsets should be 4.  */
+bool
+arm_legitimate_ldrd_p (rtx reg1, rtx reg2, rtx mem1, rtx mem2, bool ldrd)
+{
+  rtx base1, base2;
+  rtx offset1 = NULL_RTX;
+  rtx offset2 = NULL_RTX;
+  rtx addr1 = XEXP (mem1, 0);
+  rtx addr2 = XEXP (mem2, 0);
+
+  if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
+    return false;
+
+  if (REG_P (addr1))
+    base1 = addr1;
+  else if (GET_CODE (addr1) == PLUS)
+    {
+      base1 = XEXP (addr1, 0);
+      offset1 = XEXP (addr1, 1);
+      if (!REG_P (base1) || (GET_CODE (offset1) != CONST_INT))
+	return false;
+    }
+  else
+    return false;
+
+  if (REG_P (addr2))
+    base2 = addr2;
+  else if (GET_CODE (addr2) == PLUS)
+    {
+      base2 = XEXP (addr2, 0);
+      offset2 = XEXP (addr2, 1);
+      if (!REG_P (base2) || (GET_CODE (offset2) != CONST_INT))
+	return false;
+    }
+  else
+    return false;
+
+  if (base1 != base2)
+    return false;
+
+  if (ldrd && ((reg1 == reg2) || (reg1 == base1)))
+    return false;
+
+  return arm_check_ldrd_operands (reg1, reg2, offset1, offset2);
+}
+
+/* Output instructions for ldrd and count the number of bytes has been
+   outputted. Do not actually output instructions if EMIT_P is false.  */
+int
+arm_output_ldrd (rtx reg1, rtx reg2, rtx base, rtx off1, rtx off2, bool emit_p)
+{
+  int length = 0;
+  rtx operands[5];
+  HOST_WIDE_INT offset1 = 0;
+  HOST_WIDE_INT offset2 = 0;
+
+  if (off1 != NULL_RTX)
+    offset1 = INTVAL (off1);
+  else
+    off1 = GEN_INT (0);
+  if (off2 != NULL_RTX)
+    offset2 = INTVAL (off2);
+  else
+    off2 = GEN_INT (0);
+  if (offset1 > offset2)
+    {
+      rtx tmp;
+      HOST_WIDE_INT t = offset1;   offset1 = offset2;   offset2 = t;
+      tmp = off1;   off1 = off2;   off2 = tmp;
+      tmp = reg1;   reg1 = reg2;   reg2 = tmp;
+    }
+
+  operands[0] = reg1;
+  operands[1] = reg2;
+  operands[2] = base;
+  operands[3] = off1;
+  operands[4] = off2;
+
+  if (TARGET_THUMB2)
+    {
+      if (fix_cm3_ldrd && (base == reg1))
+	{
+	  if (offset1 <= -256)
+	    {
+	      if (emit_p)
+		output_asm_insn ("sub\t%2, %2, %n3", operands);
+	      length = 4;
+
+	      if (emit_p)
+		output_asm_insn ("ldr\t%1, [%2, #4]", operands);
+	      if (low_register_operand (reg2, SImode)
+		  && low_register_operand (base, SImode))
+		length += 2;
+	      else
+		length += 4;
+
+	      if (emit_p)
+		output_asm_insn ("ldr\t%0, [%2]", operands);
+	      if (low_register_operand (base, SImode))
+		length += 2;
+	      else
+		length += 4;
+	    }
+	  else
+	    {
+	      if (emit_p)
+		output_asm_insn ("ldr\t%1, [%2, %4]", operands);
+	      if (low_register_operand (reg2, SImode) && (offset2 >= 0)
+		  && low_register_operand (base, SImode) && (offset2 < 128))
+		length += 2;
+	      else
+		length += 4;
+
+	      if (emit_p)
+		output_asm_insn ("ldr\t%0, [%2, %3]", operands);
+	      if (low_register_operand (base, SImode)
+		  && (offset1 >= 0) && (offset1 < 128))
+		length += 2;
+	      else
+		length += 4;
+	    }
+	}
+      else
+	{
+	  if (emit_p)
+	    output_asm_insn ("ldrd\t%0, %1, [%2, %3]", operands);
+	  length = 4;
+	}
+    }
+  else    /* TARGET_ARM  */
+    {
+      if ((REGNO (reg2) == (REGNO (reg1) + 1)) && ((REGNO (reg1) & 1) == 0))
+	{
+	  if (emit_p)
+	    output_asm_insn ("ldrd\t%0, %1, [%2, %3]", operands);
+	  length = 4;
+	}
+      else
+	{
+	  if (emit_p)
+	    {
+	      switch (offset1)
+		{
+		case -8:
+		  output_asm_insn ("ldm%(db%)\t%2, {%0, %1}", operands);
+		  break;
+
+		case -4:
+		  output_asm_insn ("ldm%(da%)\t%2, {%0, %1}", operands);
+		  break;
+
+		case 0:
+		  output_asm_insn ("ldm%(ia%)\t%2, {%0, %1}", operands);
+		  break;
+
+		case 4:
+		  output_asm_insn ("ldm%(ib%)\t%2, {%0, %1}", operands);
+		  break;
+
+		default:
+		  gcc_unreachable ();
+		}
+	    }
+	  length = 4;
+	}
+    }
+
+  return length;
+}
+
 #include "gt-arm.h"
Index: config/arm/arm-protos.h
===================================================================
--- config/arm/arm-protos.h	(revision 171439)
+++ config/arm/arm-protos.h	(working copy)
@@ -152,6 +152,9 @@ extern void arm_expand_sync (enum machin
 extern const char *arm_output_memory_barrier (rtx *);
 extern const char *arm_output_sync_insn (rtx, rtx *);
 extern unsigned int arm_sync_loop_insns (rtx , rtx *);
+extern bool arm_check_ldrd_operands (rtx, rtx, rtx, rtx);
+extern bool arm_legitimate_ldrd_p (rtx, rtx, rtx, rtx, bool);
+extern int arm_output_ldrd (rtx, rtx, rtx, rtx, rtx, bool);
 
 #if defined TREE_CODE
 extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
Index: config/arm/ldmstm.md
===================================================================
--- config/arm/ldmstm.md	(revision 171439)
+++ config/arm/ldmstm.md	(working copy)
@@ -852,7 +852,7 @@
      (set (match_operand:SI 2 "arm_hard_register_operand" "")
           (mem:SI (plus:SI (match_dup 3)
                   (const_int 4))))])]
-  "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
+  "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "ldm%(ia%)\t%3, {%1, %2}"
   [(set_attr "type" "load2")
    (set_attr "predicable" "yes")])
@@ -901,7 +901,7 @@
           (match_operand:SI 1 "arm_hard_register_operand" ""))
      (set (mem:SI (plus:SI (match_dup 3) (const_int 4)))
           (match_operand:SI 2 "arm_hard_register_operand" ""))])]
-  "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
+  "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "stm%(ia%)\t%3, {%1, %2}"
   [(set_attr "type" "store2")
    (set_attr "predicable" "yes")])
@@ -939,7 +939,7 @@
      (set (match_operand:SI 2 "arm_hard_register_operand" "")
           (mem:SI (plus:SI (match_dup 3)
                   (const_int 8))))])]
-  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
+  "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "ldm%(ib%)\t%3, {%1, %2}"
   [(set_attr "type" "load2")
    (set_attr "predicable" "yes")])
@@ -965,7 +965,7 @@
           (match_operand:SI 1 "arm_hard_register_operand" ""))
      (set (mem:SI (plus:SI (match_dup 3) (const_int 8)))
           (match_operand:SI 2 "arm_hard_register_operand" ""))])]
-  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
+  "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "stm%(ib%)\t%3, {%1, %2}"
   [(set_attr "type" "store2")
    (set_attr "predicable" "yes")])
@@ -990,7 +990,7 @@
                   (const_int -4))))
      (set (match_operand:SI 2 "arm_hard_register_operand" "")
           (mem:SI (match_dup 3)))])]
-  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
+  "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "ldm%(da%)\t%3, {%1, %2}"
   [(set_attr "type" "load2")
    (set_attr "predicable" "yes")])
@@ -1015,7 +1015,7 @@
           (match_operand:SI 1 "arm_hard_register_operand" ""))
      (set (mem:SI (match_dup 3))
           (match_operand:SI 2 "arm_hard_register_operand" ""))])]
-  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
+  "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "stm%(da%)\t%3, {%1, %2}"
   [(set_attr "type" "store2")
    (set_attr "predicable" "yes")])
@@ -1041,7 +1041,7 @@
      (set (match_operand:SI 2 "arm_hard_register_operand" "")
           (mem:SI (plus:SI (match_dup 3)
                   (const_int -4))))])]
-  "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
+  "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "ldm%(db%)\t%3, {%1, %2}"
   [(set_attr "type" "load2")
    (set_attr "predicable" "yes")])
@@ -1067,7 +1067,7 @@
           (match_operand:SI 1 "arm_hard_register_operand" ""))
      (set (mem:SI (plus:SI (match_dup 3) (const_int -4)))
           (match_operand:SI 2 "arm_hard_register_operand" ""))])]
-  "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
+  "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
   "stm%(db%)\t%3, {%1, %2}"
   [(set_attr "type" "store2")
    (set_attr "predicable" "yes")])
@@ -1189,3 +1189,207 @@
     FAIL;
 })
 
+(define_insn "*ldrd"
+  [(set (match_operand:SI 0 "arm_hard_register_operand" "")
+	(mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
+			 (match_operand:SI 3 "const_int_operand" ""))))
+   (set (match_operand:SI 1 "arm_hard_register_operand" "")
+	(mem:SI (plus:SI (match_dup 2)
+			 (match_operand:SI 4 "const_int_operand" ""))))]
+  "TARGET_32BIT && arm_arch7
+   && arm_check_ldrd_operands (operands[0], operands[1],
+			       operands[3], operands[4])"
+  "*
+  arm_output_ldrd (operands[0], operands[1],
+		   operands[2], operands[3], operands[4], true);
+  return \"\";
+  "
+  [(set (attr "length")
+	(symbol_ref ("arm_output_ldrd (operands[0], operands[1], operands[2],
+				       operands[3], operands[4], false)")))]
+)
+
+(define_insn "*ldrd_reg1"
+  [(set (match_operand:SI 0 "arm_hard_register_operand" "")
+	(mem:SI (match_operand:SI 2 "s_register_operand" "rk")))
+   (set (match_operand:SI 1 "arm_hard_register_operand" "")
+	(mem:SI (plus:SI (match_dup 2)
+			 (match_operand:SI 3 "const_int_operand" ""))))]
+  "TARGET_32BIT && arm_arch7
+   && arm_check_ldrd_operands (operands[0], operands[1], NULL_RTX, operands[3])"
+  "*
+  arm_output_ldrd (operands[0], operands[1],
+		   operands[2], NULL_RTX, operands[3], true);
+  return \"\";
+  "
+  [(set (attr "length")
+	(symbol_ref ("arm_output_ldrd (operands[0], operands[1], operands[2],
+				       NULL_RTX, operands[3], false)")))]
+)
+
+(define_insn "*ldrd_reg2"
+  [(set (match_operand:SI 0 "arm_hard_register_operand" "")
+	(mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
+			 (match_operand:SI 3 "const_int_operand" ""))))
+   (set (match_operand:SI 1 "arm_hard_register_operand" "")
+	(mem:SI (match_dup 2)))]
+  "TARGET_32BIT && arm_arch7
+   && arm_check_ldrd_operands (operands[0], operands[1], operands[3], NULL_RTX)"
+  "*
+  arm_output_ldrd (operands[0], operands[1],
+		   operands[2], operands[3], NULL_RTX, true);
+  return \"\";
+  "
+  [(set (attr "length")
+	(symbol_ref ("arm_output_ldrd (operands[0], operands[1], operands[2],
+				       operands[3], NULL_RTX, false)")))]
+)
+
+(define_peephole2
+  [(set (match_operand:SI 0 "s_register_operand" "")
+	(match_operand:SI 2 "memory_operand" ""))
+   (set (match_operand:SI 1 "s_register_operand" "")
+	(match_operand:SI 3 "memory_operand" ""))]
+  "TARGET_32BIT && arm_arch7
+   && arm_legitimate_ldrd_p (operands[0], operands[1],
+			     operands[2], operands[3], true)"
+  [(parallel [(set (match_operand:SI 0 "s_register_operand" "")
+		   (match_operand:SI 2 "memory_operand" ""))
+	      (set (match_operand:SI 1 "s_register_operand" "")
+		   (match_operand:SI 3 "memory_operand" ""))])]
+  ""
+)
+
+(define_insn "*strd"
+  [(set (mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
+			 (match_operand:SI 3 "const_int_operand" "")))
+	(match_operand:SI 0 "arm_hard_register_operand" ""))
+   (set (mem:SI (plus:SI (match_dup 2)
+			 (match_operand:SI 4 "const_int_operand" "")))
+	(match_operand:SI 1 "arm_hard_register_operand" ""))]
+  "TARGET_32BIT && arm_arch7
+   && arm_check_ldrd_operands (operands[0], operands[1],
+			       operands[3], operands[4])"
+  "*
+  {
+    HOST_WIDE_INT offset1 = INTVAL (operands[3]);
+    HOST_WIDE_INT offset2 = INTVAL (operands[4]);
+    if (offset1 > offset2)
+      {
+	rtx tmp = operands[0];  operands[0] = operands[1];  operands[1] = tmp;
+	tmp = operands[3];  operands[3] = operands[4];  operands[4] = tmp;
+	offset1 = INTVAL (operands[3]);
+	offset2 = INTVAL (operands[4]);
+      }
+    if (TARGET_THUMB2)
+      return \"strd\\t%0, %1, [%2, %3]\";
+    else          /* TARGET_ARM  */
+      {
+	if ((REGNO (operands[1]) == (REGNO (operands[0]) + 1))
+	    && ((REGNO (operands[0]) & 1) == 0))
+	  return \"strd\\t%0, %1, [%2, %3]\";
+	else if (offset1 == -8)
+	  return \"stm%(db%)\\t%2, {%0, %1}\";
+	else      /* offset1 == 4  */
+	  return \"stm%(ib%)\\t%2, {%0, %1}\";
+      }
+  }"
+  [(set_attr "length" "4")]
+)
+
+(define_insn "*strd_reg1"
+  [(set (mem:SI (match_operand:SI 2 "s_register_operand" "rk"))
+	(match_operand:SI 0 "arm_hard_register_operand" ""))
+   (set (mem:SI (plus:SI (match_dup 2)
+			 (match_operand:SI 3 "const_int_operand" "")))
+	(match_operand:SI 1 "arm_hard_register_operand" ""))]
+  "TARGET_32BIT && arm_arch7
+   && arm_check_ldrd_operands (operands[0], operands[1], NULL_RTX, operands[3])"
+  "*
+  {
+    HOST_WIDE_INT offset2 = INTVAL (operands[3]);
+    if (TARGET_THUMB2)
+      {
+	if (offset2 == 4)
+	  return \"strd\\t%0, %1, [%2]\";
+	else
+	  return \"strd\\t%1, %0, [%2, %3]\";
+      }
+    else           /* TARGET_ARM  */
+      {
+	if (offset2 == 4)
+	  {
+	    if ((REGNO (operands[1]) == (REGNO (operands[0]) + 1))
+		&& ((REGNO (operands[0]) & 1) == 0))
+	      return \"strd\\t%0, %1, [%2]\";
+	    else
+	      return \"stm%(ia%)\\t%2, {%0, %1}\";
+	  }
+	else      /* offset2 == -4  */
+	  {
+	    if ((REGNO (operands[0]) == (REGNO (operands[1]) + 1))
+		&& ((REGNO (operands[1]) & 1) == 0))
+	      return \"strd\\t%1, %0, [%2, %3]\";
+	    else
+	      return \"stm%(da%)\\t%2, {%1, %0}\";
+	  }
+      }
+  }"
+  [(set_attr "length" "4")]
+)
+
+(define_insn "*strd_reg2"
+  [(set (mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
+			 (match_operand:SI 3 "const_int_operand" "")))
+	(match_operand:SI 0 "arm_hard_register_operand" ""))
+   (set (mem:SI (match_dup 2))
+	(match_operand:SI 1 "arm_hard_register_operand" ""))]
+  "TARGET_32BIT && arm_arch7
+   && arm_check_ldrd_operands (operands[0], operands[1], operands[3], NULL_RTX)"
+  "*
+  {
+    HOST_WIDE_INT offset1 = INTVAL (operands[3]);
+    if (TARGET_THUMB2)
+      {
+	if (offset1 == -4)
+	  return \"strd\\t%0, %1, [%2, %3]\";
+	else
+	  return \"strd\\t%1, %0, [%2]\";
+      }
+    else           /* TARGET_ARM  */
+      {
+	if (offset1 == -4)
+	  {
+	    if ((REGNO (operands[1]) == (REGNO (operands[0]) + 1))
+		&& ((REGNO (operands[0]) & 1) == 0))
+	      return \"strd\\t%0, %1, [%2, %3]\";
+	    else
+	      return \"stm%(da%)\\t%2, {%0, %1}\";
+	  }
+	else
+	  {
+	    if ((REGNO (operands[0]) == (REGNO (operands[1]) + 1))
+		&& ((REGNO (operands[1]) & 1) == 0))
+	      return \"strd\\t%1, %0, [%2]\";
+	    else
+	      return \"stm%(ia%)\\t%2, {%1, %0}\";
+	  }
+      }
+  }"
+  [(set_attr "length" "4")]
+)
+
+(define_peephole2
+  [(set (match_operand:SI 2 "memory_operand" "")
+	(match_operand:SI 0 "s_register_operand" ""))
+   (set (match_operand:SI 3 "memory_operand" "")
+	(match_operand:SI 1 "s_register_operand" ""))]
+  "TARGET_32BIT && arm_arch7
+   && arm_legitimate_ldrd_p (operands[0], operands[1],
+				operands[2], operands[3], false)"
+  [(parallel [(set (match_operand:SI 2 "memory_operand" "")
+		   (match_operand:SI 0 "s_register_operand" ""))
+	      (set (match_operand:SI 3 "memory_operand" "")
+		   (match_operand:SI 1 "s_register_operand" ""))])]
+  ""
+)


More information about the Gcc-patches mailing list