diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 668c4a6..1c6425f 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -116,6 +116,7 @@ extern rtx arm_gen_store_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *);
 extern bool bad_operands_ldrd_strd (rtx, rtx, rtx, HOST_WIDE_INT, bool, bool);
 extern bool gen_operands_ldrd_strd (rtx *, int, bool, bool);
 extern bool gen_operands_const_strd (rtx *, int);
+extern bool gen_movmem_ldrd_strd (rtx *);
 
 extern int arm_gen_movmemqi (rtx *);
 extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx);
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index a78ba88..7b493ae 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -6695,6 +6695,19 @@
 })
 
 
+(define_expand "movmemdi"
+  [(match_operand:BLK 0 "general_operand" "")
+   (match_operand:BLK 1 "general_operand" "")
+   (match_operand:SI 2 "const_int_operand" "")
+   (match_operand:SI 3 "const_int_operand" "")]
+  "current_tune->prefer_ldrd_strd && !optimize_function_for_size_p (cfun)"
+  {
+   if (gen_movmem_ldrd_strd (operands))
+      DONE;
+   FAIL;
+  } 
+)
+
 ;; Move a block of memory if it is word aligned and MORE than 2 words long.
 ;; We could let this apply for blocks of less than this, but it clobbers so
 ;; many registers that there is then probably a better way.
@@ -6704,8 +6717,16 @@
    (match_operand:BLK 1 "general_operand" "")
    (match_operand:SI 2 "const_int_operand" "")
    (match_operand:SI 3 "const_int_operand" "")]
-  "TARGET_EITHER"
+  ""
   "
+  if (current_tune->prefer_ldrd_strd && !optimize_function_for_size_p (cfun))
+    {
+     if (gen_movmem_ldrd_strd (operands))
+        DONE;
+
+     FAIL;
+    } 
+  else
   if (TARGET_32BIT)
     {
       if (arm_gen_movmemqi (operands))
diff --git a/gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c b/gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c
index 9995708..441751d 100644
--- a/gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c
+++ b/gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c
@@ -1,18 +1,7 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target arm_unaligned } */
-/* { dg-options "-O2" } */
-
-#include <string.h>
-
-char src[16];
-char dest[16];
-
-void aligned_both (void)
-{
-  memcpy (dest, src, 15);
-}
-
+/* { dg-options "-O2 -march=armv4t" } */
+#include "unaligned-memcpy.inc"
 /* We know both src and dest to be aligned: expect multiword loads/stores.  */
-
 /* { dg-final { scan-assembler-times "ldmia" 1 } } */
 /* { dg-final { scan-assembler-times "stmia" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/unaligned-memcpy-5.c b/gcc/testsuite/gcc.target/arm/unaligned-memcpy-5.c
new file mode 100644
index 0000000..7361478
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/unaligned-memcpy-5.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_unaligned } */
+/* { dg-options "-O2 -mcpu=cortex-a15" } */
+#include "unaligned-memcpy.inc"
+/* We know both src and dest to be aligned: expect doubleword loads/stores.  */
+/* { dg-final { scan-assembler-times "ldrd" 1 } } */
+/* { dg-final { scan-assembler-times "strd" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/unaligned-memcpy.inc b/gcc/testsuite/gcc.target/arm/unaligned-memcpy.inc
new file mode 100644
index 0000000..8593951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/unaligned-memcpy.inc
@@ -0,0 +1,9 @@
+#include <string.h>
+
+char src[16];
+char dest[16];
+
+void aligned_both (void)
+{
+  memcpy (dest, src, 15);
+}
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 8f8f67d..dd042b6 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -25360,4 +25360,97 @@ find_free_regs_for_arm_const_strd (int len, rtx *operands, rtx base, HOST_WIDE_I
 
 #undef SWAP_RTX
 
+/* Copy using LDRD/STRD instructions whenever possible.  
+   Returns true upon success. */
+bool
+gen_movmem_ldrd_strd (rtx *operands)
+{  
+  HOST_WIDE_INT len, align, offset;
+  rtx src, dst, base, offset_rtx, res;
+  rtx reg0;
+
+  gcc_assert (CONST_INT_P (operands[2]));
+  gcc_assert (CONST_INT_P (operands[3]));
+  
+  len = INTVAL (operands[2]);
+  if (len > 64) 
+    return false;
+
+  /* Maximum alignment we can assume for both src and dst buffers.  */
+  align = INTVAL (operands[3]);
+
+  if ((align & 3) != 0)    
+    {
+      if (!unaligned_access) 
+        return false;
+      return arm_movmemqi_unaligned (operands);      
+    }
+  
+  /* Both src and dst must be at least word aligned.  */
+  if ((len > 64) || (align & 3))
+    return false;
+
+  /* Copy src and dst to registers and update the corresponding mem rtx.  */
+  dst = operands[0];
+  if (!mem_ok_for_ldrd_strd (dst, &base, &offset_rtx)) 
+    return false;
+  base = gen_reg_rtx (SImode);
+  emit_move_insn (base, XEXP (dst, 0));
+  dst = change_address (dst, VOIDmode, base);
+
+  src = operands[1];
+  if (!mem_ok_for_ldrd_strd (src, &base, &offset_rtx)) 
+    return false;
+  base = gen_reg_rtx (SImode);
+  emit_move_insn (base, XEXP (src, 0));
+  src = change_address (src, VOIDmode, base);
+
+  if (len >= 8)
+    {      
+      src = change_address (src, DImode, NULL);
+      dst = change_address (dst, DImode, NULL);
+      reg0 = gen_reg_rtx (DImode);
+      offset = 8;
+      while (len >= 8)
+        {
+          len -= 8;
+          emit_insn (gen_rtx_SET (VOIDmode, reg0, src));
+          emit_insn (gen_rtx_SET (VOIDmode, dst, reg0));
+          dst = adjust_address (dst, DImode, offset);
+          src = adjust_address (src, DImode, offset);
+        }
+    }
+  
+  if (len >=4)
+    {      
+      len -= 4;
+      offset = 4;
+      reg0 = gen_reg_rtx (SImode);
+      dst = change_address (dst, SImode, NULL);
+      src = change_address (src, SImode, NULL);
+      emit_set_insn (reg0, src);
+      emit_set_insn (dst, reg0);
+      src = adjust_address (src, SImode, offset);
+      dst = adjust_address (dst, SImode, offset);
+    }
+  
+  if (len >= 1)
+    {
+      offset = 1;
+      reg0 = gen_reg_rtx (QImode);
+      dst = change_address (dst, QImode, NULL);
+      src = change_address (src, QImode, NULL);
+      while (len >= 1)
+        {
+          len -= 1;
+          emit_set_insn (reg0, src);
+          emit_set_insn (dst, reg0);
+          src = adjust_address (src, QImode, offset);
+          dst = adjust_address (dst, QImode, offset);
+        }
+    }
+
+  return true;
+}
+
 #include "gt-arm.h"
