diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9eee988e12c..d55f28ea910 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2020-05-21  Felix Yang  <felix.yang@huawei.com>
+
+	PR target/95254
+	* config/aarch64/aarch64.c (aarch64_expand_sve_mem_move):
+	Catch the case when one move operand is a SUBREG doing an
+	equal-size mode conversion from Advanced SIMD mode to SVE mode.
+	Simplify this into an Advanced SIMD mode move.
+
 2020-05-19  Alex Coplan  <alex.coplan@arm.com>
 
 	PR target/94591
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 79c016f4dc3..2d7f1f59676 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -5228,7 +5228,48 @@ aarch64_emit_sve_pred_move (rtx dest, rtx pred, rtx src)
 void
 aarch64_expand_sve_mem_move (rtx dest, rtx src, machine_mode pred_mode)
 {
-  machine_mode mode = GET_MODE (dest);
+  rtx inner = NULL_RTX;
+  unsigned int alignment;
+  machine_mode inner_mode, mode = GET_MODE (dest);
+
+  if (SUBREG_P (src)
+      && REG_P (SUBREG_REG (src))
+      && known_eq (SUBREG_BYTE (src), 0))
+    {
+      inner = SUBREG_REG (src);
+      inner_mode = GET_MODE (inner);
+      alignment = MEM_ALIGN (dest);
+    }
+  else if (SUBREG_P (dest)
+	   && REG_P (SUBREG_REG (dest))
+	   && known_eq (SUBREG_BYTE (dest), 0))
+    {
+      inner = SUBREG_REG (dest);
+      inner_mode = GET_MODE (inner);
+      alignment = MEM_ALIGN (src);
+    }
+  if (inner != NULL_RTX
+      && aarch64_classify_vector_mode (inner_mode) == VEC_ADVSIMD
+      && GET_MODE_INNER (mode) == GET_MODE_INNER (inner_mode)
+      && known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (inner_mode))
+      && GET_MODE_BITSIZE (inner_mode).to_constant () <= alignment)
+    {
+      rtx addr, mem;
+      if (MEM_P (src))
+	{
+	  addr = XEXP (src, 0);
+	  mem = gen_rtx_MEM (inner_mode, addr);
+	  emit_move_insn (inner, mem);
+	}
+      else
+	{
+	  addr = XEXP (dest, 0);
+	  mem = gen_rtx_MEM (inner_mode, addr);
+	  emit_move_insn (mem, inner);
+	}
+      return;
+    }
+
   rtx ptrue = aarch64_ptrue_reg (pred_mode);
   if (!register_operand (src, mode)
       && !register_operand (dest, mode))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 48671f1105a..9450ff7ab7e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-05-21  Felix Yang  <felix.yang@huawei.com>
+
+	PR target/95254
+	* gcc.target/aarch64/pr95254.c: New test.
+
 2020-05-19  Alex Coplan  <alex.coplan@arm.com>
 
 	PR target/94591
diff --git a/gcc/testsuite/gcc.target/aarch64/pr95254.c b/gcc/testsuite/gcc.target/aarch64/pr95254.c
new file mode 100644
index 00000000000..10bfc868197
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr95254.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-slp-vectorize -march=armv8.2-a+sve -msve-vector-bits=256" } */
+
+typedef short __attribute__((vector_size (8))) v4hi;
+
+typedef union U4HI { v4hi v; short a[4]; } u4hi;
+
+short b[4];
+
+void pass_v4hi (v4hi v)
+{
+    int i;
+    u4hi u;
+    u.v = v;
+    for (i = 0; i < 4; i++)
+      b[i] = u.a[i];
+};
+
+/* { dg-final { scan-assembler-not "ptrue" } } */
