Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)	(revision 242318)
+++ gcc/config/rs6000/rs6000.c	(.../gcc/config/rs6000)	(working copy)
@@ -7095,12 +7095,32 @@ rs6000_expand_vector_set (rtx target, rt
   int width = GET_MODE_SIZE (inner_mode);
   int i;
 
-  if (VECTOR_MEM_VSX_P (mode) && (mode == V2DFmode || mode == V2DImode))
+  if (VECTOR_MEM_VSX_P (mode))
     {
-      rtx (*set_func) (rtx, rtx, rtx, rtx)
-	= ((mode == V2DFmode) ? gen_vsx_set_v2df : gen_vsx_set_v2di);
-      emit_insn (set_func (target, target, val, GEN_INT (elt)));
-      return;
+      rtx (*set_func) (rtx, rtx, rtx, rtx) = (rtx (*) (rtx, rtx, rtx, rtx))0;
+
+      if (mode == V2DFmode)
+	set_func = gen_vsx_set_v2df;
+
+      else if (mode == V2DImode)
+	set_func = gen_vsx_set_v2di;
+
+      else if (TARGET_P9_VECTOR && TARGET_VSX_SMALL_INTEGER
+	       && TARGET_UPPER_REGS_DI && TARGET_POWERPC64)
+	{
+	  if (mode == V4SImode)
+	    set_func = gen_vsx_set_v4si_p9;
+	  else if (mode == V8HImode)
+	    set_func = gen_vsx_set_v8hi_p9;
+	  else if (mode == V16QImode)
+	    set_func = gen_vsx_set_v16qi_p9;
+	}
+
+      if (set_func)
+	{
+	  emit_insn (set_func (target, target, val, GEN_INT (elt)));
+	  return;
+	}
     }
 
   /* Simplify setting single element vectors like V1TImode.  */
Index: gcc/config/rs6000/vsx.md
===================================================================
--- gcc/config/rs6000/vsx.md	(svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)	(revision 242318)
+++ gcc/config/rs6000/vsx.md	(.../gcc/config/rs6000)	(working copy)
@@ -2514,9 +2514,9 @@ (define_expand "vec_perm_const<mode>"
     FAIL;
 })
 
-;; Extraction of a single element in a small integer vector.  None of the small
-;; types are currently allowed in a vector register, so we extract to a DImode
-;; and either do a direct move or store.
+;; Extraction of a single element in a small integer vector.  Until ISA 3.0,
+;; none of the small types were allowed in a vector register, so we had to
+;; extract to a DImode and either do a direct move or store.
 (define_expand  "vsx_extract_<mode>"
   [(parallel [(set (match_operand:<VS_scalar> 0 "gpc_reg_operand")
 		   (vec_select:<VS_scalar>
@@ -2839,6 +2839,31 @@ (define_insn_and_split "*vsx_extract_si_
   DONE;
 })
 
+;; V4SI/V8HI/V16QI set operation on ISA 3.0
+(define_insn "vsx_set_<mode>_p9"
+  [(set (match_operand:VSX_EXTRACT_I 0 "gpc_reg_operand" "=<VSX_EX>")
+	(unspec:VSX_EXTRACT_I
+	 [(match_operand:VSX_EXTRACT_I 1 "gpc_reg_operand" "0")
+	  (match_operand:<VS_scalar> 2 "gpc_reg_operand" "<VSX_EX>")
+	  (match_operand:QI 3 "<VSX_EXTRACT_PREDICATE>" "n")]
+	 UNSPEC_VSX_SET))]
+  "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_P9_VECTOR && TARGET_VSX_SMALL_INTEGER
+   && TARGET_UPPER_REGS_DI && TARGET_POWERPC64"
+{
+  int ele = INTVAL (operands[3]);
+  int nunits = GET_MODE_NUNITS (<MODE>mode);
+
+  if (!VECTOR_ELT_ORDER_BIG)
+    ele = nunits - 1 - ele;
+
+  operands[3] = GEN_INT (nunits * ele);
+  if (<MODE>mode == V4SImode)
+    return "xxinsertw %x0,%x2,%3";
+  else
+    return "vinsert<wd> %0,%2,%3";
+}
+  [(set_attr "type" "vecperm")])
+
 ;; Expanders for builtins
 (define_expand "vsx_mergel_<mode>"
   [(use (match_operand:VSX_D 0 "vsx_register_operand" ""))
Index: gcc/testsuite/gcc.target/powerpc/vec-set-char.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/vec-set-char.c	(svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/vec-set-char.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 242346)
@@ -0,0 +1,40 @@
+#include <altivec.h>
+
+/* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -mupper-regs-di -mvsx-small-integer" } */
+
+vector char
+insert_0_0 (vector char v)
+{
+  return vec_insert (0, v, 0);
+}
+
+vector char
+insert_m1_1 (vector char v)
+{
+  return vec_insert (-1, v, 1);
+}
+
+vector char
+insert_5_2 (vector char v)
+{
+  return vec_insert (5, v, 2);
+}
+
+vector char
+insert_mem_15 (vector char v, char *p)
+{
+  return vec_insert (*p, v, 15);
+}
+
+/* { dg-final { scan-assembler     "vinsertb"  } } */
+/* { dg-final { scan-assembler     "xxsplitib" } } */
+/* { dg-final { scan-assembler     "vspltisb"  } } */
+/* { dg-final { scan-assembler-not "mtvsrd"    } } */
+/* { dg-final { scan-assembler-not "mtvsrdd"   } } */
+/* { dg-final { scan-assembler-not "mtvsrwa"   } } */
+/* { dg-final { scan-assembler-not "mtvsrwz"   } } */
+/* { dg-final { scan-assembler-not "mfvsrd"    } } */
+/* { dg-final { scan-assembler-not "mfvsrwz"   } } */
Index: gcc/testsuite/gcc.target/powerpc/vec-set-int.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/vec-set-int.c	(svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/vec-set-int.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 242346)
@@ -0,0 +1,40 @@
+#include <altivec.h>
+
+/* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -mupper-regs-di -mvsx-small-integer" } */
+
+vector int
+insert_0_0 (vector int v)
+{
+  return vec_insert (0, v, 0);
+}
+
+vector int
+insert_m1_1 (vector int v)
+{
+  return vec_insert (-1, v, 1);
+}
+
+vector int
+insert_5_2 (vector int v)
+{
+  return vec_insert (5, v, 2);
+}
+
+vector int
+insert_mem_3 (vector int v, int *p)
+{
+  return vec_insert (*p, v, 3);
+}
+
+/* { dg-final { scan-assembler     "xxinsertw" } } */
+/* { dg-final { scan-assembler     "xxsplitib" } } */
+/* { dg-final { scan-assembler     "vspltisw"  } } */
+/* { dg-final { scan-assembler-not "mtvsrd"    } } */
+/* { dg-final { scan-assembler-not "mtvsrdd"   } } */
+/* { dg-final { scan-assembler-not "mtvsrwa"   } } */
+/* { dg-final { scan-assembler-not "mtvsrwz"   } } */
+/* { dg-final { scan-assembler-not "mfvsrd"    } } */
+/* { dg-final { scan-assembler-not "mfvsrwz"   } } */
Index: gcc/testsuite/gcc.target/powerpc/vec-set-short.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/vec-set-short.c	(svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/testsuite/gcc.target/powerpc)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/vec-set-short.c	(.../gcc/testsuite/gcc.target/powerpc)	(revision 242346)
@@ -0,0 +1,40 @@
+#include <altivec.h>
+
+/* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -mupper-regs-di -mvsx-small-integer" } */
+
+vector short
+insert_0_0 (vector short v)
+{
+  return vec_insert (0, v, 0);
+}
+
+vector short
+insert_m1_1 (vector short v)
+{
+  return vec_insert (-1, v, 1);
+}
+
+vector short
+insert_5_2 (vector short v)
+{
+  return vec_insert (5, v, 2);
+}
+
+vector short
+insert_mem_7 (vector short v, short *p)
+{
+  return vec_insert (*p, v, 7);
+}
+
+/* { dg-final { scan-assembler     "vinserth"  } } */
+/* { dg-final { scan-assembler     "xxsplitib" } } */
+/* { dg-final { scan-assembler     "vspltish"  } } */
+/* { dg-final { scan-assembler-not "mtvsrd"    } } */
+/* { dg-final { scan-assembler-not "mtvsrdd"   } } */
+/* { dg-final { scan-assembler-not "mtvsrwa"   } } */
+/* { dg-final { scan-assembler-not "mtvsrwz"   } } */
+/* { dg-final { scan-assembler-not "mfvsrd"    } } */
+/* { dg-final { scan-assembler-not "mfvsrwz"   } } */
