diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index e5ae556..c4ea1fa 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -181,9 +181,6 @@ int aarch64_asm_preferred_eh_data_format (int, int);
 int aarch64_hard_regno_mode_ok (unsigned, enum machine_mode);
 int aarch64_hard_regno_nregs (unsigned, enum machine_mode);
 int aarch64_simd_attr_length_move (rtx);
-int aarch64_simd_immediate_valid_for_move (rtx, enum machine_mode, rtx *,
-					   int *, unsigned char *, int *,
-					   int *);
 int aarch64_uxt_size (int, HOST_WIDE_INT);
 rtx aarch64_final_eh_return_addr (void);
 rtx aarch64_legitimize_reload_address (rtx *, enum machine_mode, int, int, int);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 94db053..9fa18b6 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -93,6 +93,7 @@ struct simd_immediate_info
   int shift;
   int element_width;
   bool mvn;
+  bool msl;
 };
 
 /* The current code model.  */
@@ -6319,16 +6320,16 @@ aarch64_simd_valid_immediate (rtx op, enum machine_mode mode, bool inverse,
       CHECK (2, 16, 11, bytes[i] == 0xff && bytes[i + 1] == bytes[1], 8, 1);
 
       CHECK (4, 32, 12, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
-	     && bytes[i + 2] == 0 && bytes[i + 3] == 0, 0, 0);
+	     && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
 
       CHECK (4, 32, 13, bytes[i] == 0 && bytes[i + 1] == bytes[1]
-	     && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 0, 1);
+	     && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
 
       CHECK (4, 32, 14, bytes[i] == 0xff && bytes[i + 1] == 0xff
-	     && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 0, 0);
+	     && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
 
       CHECK (4, 32, 15, bytes[i] == 0 && bytes[i + 1] == 0
-	     && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 0, 1);
+	     && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
 
       CHECK (1, 8, 16, bytes[i] == bytes[0], 0, 0);
 
@@ -6337,12 +6338,7 @@ aarch64_simd_valid_immediate (rtx op, enum machine_mode mode, bool inverse,
     }
   while (0);
 
-  /* TODO: Currently the assembler cannot handle types 12 to 15.
-     And there is no way to specify cmode through the compiler.
-     Disable them till there is support in the assembler.  */
-  if (immtype == -1
-      || (immtype >= 12 && immtype <= 15)
-      || immtype == 18)
+  if (immtype == -1)
     return false;
 
   if (info)
@@ -6353,6 +6349,9 @@ aarch64_simd_valid_immediate (rtx op, enum machine_mode mode, bool inverse,
 
       unsigned HOST_WIDE_INT imm = 0;
 
+      if (immtype >= 12 && immtype <= 15)
+	info->msl = true;
+
       /* Un-invert bytes of recognized vector, if necessary.  */
       if (invmask != 0)
         for (i = 0; i < idx; i++)
@@ -7285,10 +7284,11 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
   bool is_valid;
   static char templ[40];
   const char *mnemonic;
+  const char *shift_op;
   unsigned int lane_count = 0;
   char element_char;
 
-  struct simd_immediate_info info;
+  struct simd_immediate_info info = { NULL_RTX, 0, 0, false, false };
 
   /* This will return true to show const_vector is legal for use as either
      a AdvSIMD MOVI instruction (or, implicitly, MVNI) immediate.  It will
@@ -7324,14 +7324,15 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
     }
 
   mnemonic = info.mvn ? "mvni" : "movi";
+  shift_op = info.msl ? "msl" : "lsl";
 
   if (lane_count == 1)
     snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX,
 	      mnemonic, UINTVAL (info.value));
   else if (info.shift)
     snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX
-	      ", lsl %d", mnemonic, lane_count, element_char,
-	      UINTVAL (info.value), info.shift);
+	      ", %s %d", mnemonic, lane_count, element_char,
+	      UINTVAL (info.value), shift_op, info.shift);
   else
     snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX,
 	      mnemonic, lane_count, element_char, UINTVAL (info.value));
diff --git a/gcc/testsuite/gcc.target/aarch64/vect-movi.c b/gcc/testsuite/gcc.target/aarch64/vect-movi.c
new file mode 100644
index 0000000..59a0bd5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/vect-movi.c
@@ -0,0 +1,74 @@
+/* { dg-do run } */
+/* { dg-options "-O3 --save-temps -fno-inline" } */
+
+extern void abort (void);
+
+#define N 16
+
+static void
+movi_msl8 (int *__restrict a)
+{
+  int i;
+
+  /* { dg-final { scan-assembler "movi\\tv\[0-9\]+\.4s, 0xab, msl 8" } } */
+  for (i = 0; i < N; i++)
+    a[i] = 0xabff;
+}
+
+static void
+movi_msl16 (int *__restrict a)
+{
+  int i;
+
+  /* { dg-final { scan-assembler "movi\\tv\[0-9\]+\.4s, 0xab, msl 16" } } */
+  for (i = 0; i < N; i++)
+    a[i] = 0xabffff;
+}
+
+static void
+mvni_msl8 (int *__restrict a)
+{
+  int i;
+
+  /* { dg-final { scan-assembler "mvni\\tv\[0-9\]+\.4s, 0xab, msl 8" } } */
+  for (i = 0; i < N; i++)
+    a[i] = 0xffff5400;
+}
+
+static void
+mvni_msl16 (int *__restrict a)
+{
+  int i;
+
+  /* { dg-final { scan-assembler "mvni\\tv\[0-9\]+\.4s, 0xab, msl 16" } } */
+  for (i = 0; i < N; i++)
+    a[i] = 0xff540000;
+}
+
+int
+main (void)
+{
+  int a[N] = { 0 };
+  int i;
+
+#define CHECK_ARRAY(a, val)	\
+  for (i = 0; i < N; i++)	\
+    if (a[i] != val)		\
+      abort ();
+
+  movi_msl8 (a);
+  CHECK_ARRAY (a, 0xabff);
+
+  movi_msl16 (a);
+  CHECK_ARRAY (a, 0xabffff);
+
+  mvni_msl8 (a);
+  CHECK_ARRAY (a, 0xffff5400);
+
+  mvni_msl16 (a);
+  CHECK_ARRAY (a, 0xff540000);
+
+  return 0;
+}
+
+/* { dg-final { cleanup-saved-temps } } */
