diff mbox series

[PATCHv2,rs6000] Extract the element in dword0 by mfvsrd and shift/mask [PR110331]

Message ID ff3f47e9-ede7-edfe-c19e-ef5137f760f8@linux.ibm.com
State New
Headers show
Series [PATCHv2,rs6000] Extract the element in dword0 by mfvsrd and shift/mask [PR110331] | expand

Commit Message

HAO CHEN GUI Aug. 22, 2023, 6:28 a.m. UTC
Hi,
  This patch implements the vector element extraction by mfvsrd and
shift/mask when the element is in dword0 of the vector. Originally,
it generates vsplat/mfvsrd on P8 and li/vextract on P9. Since mfvsrd
has lower latency than vextract and rldicl has lower latency than
vsplat, the new sequence has the benefit. Specially, the shift/mask
is no need when the element is the first element of dword0. So it saves
another rldicl when it returns a sign extend value.

  Bootstrapped and tested on powerpc64-linux BE and LE with no regressions.

Thanks
Gui Haochen

ChangeLog
rs6000: Extract the element in dword0 by mfvsrd and shift/mask

gcc/
	PR target/110331
	* config/rs6000/rs6000-protos.h (rs6000_vsx_element_in_dword0_p):
	Declare.
	(rs6000_vsx_extract_element_from_dword0): Declare.
	* config/rs6000/rs6000.cc (rs6000_vsx_element_in_dword0_p): New
	function to judge if an element is in dword0 of a vector.
	(rs6000_vsx_extract_element_from_dword0): Extract an element from
	dword0 by mfvsrd and lshiftrt and mask.
	* config/rs6000/rs6000.md (*rotl<mode>3_mask): Rename to...
	(rotl<mode>3_mask): ...this
	* config/rs6000/vsx.md (split pattern for p9 vector extract): Call
	rs6000_vsx_extract_element_from_dword0 if the element is in dword0.
	(*vsx_extract_<mode>_di_p9): Assert the extracted elements isn't in
	dword0.
	(*vsx_extract_v4si_w023): Call
	rs6000_vsx_extract_element_from_dword0 if the element is in dword0.
	(*vsx_extract_<mode>_zero_extend): Zero extend pattern for vector
	extract on the element in dword0.
	(*vsx_extract_<mode>_p8): Call rs6000_vsx_extract_element_from_dword0
	when the extracted element is in dword0.  Refined the pattern and
	remove reload_completed from split condition.

gcc/testsuite/
	PR target/110331
	* gcc.target/powerpc/fold-vec-extract-char.p8.c: Set the extracted
	elements in dword1.
	* gcc.target/powerpc/fold-vec-extract-char.p9.c: Likewise.
	* gcc.target/powerpc/fold-vec-extract-int.p8.c: Likewise.
	* gcc.target/powerpc/fold-vec-extract-int.p9.c: Likewise.
	* gcc.target/powerpc/fold-vec-extract-short.p8.c: Likewise.
	* gcc.target/powerpc/fold-vec-extract-short.p9.c: Likewise.
	* gcc.target/powerpc/p9-extract-1.c: Likewise.
	* gcc.target/powerpc/pr110331-p8.c: New.
	* gcc.target/powerpc/pr110331-p9.c: New.
	* gcc.target/powerpc/pr110331.h: New.

patch.diff
diff mbox series

Patch

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index f70118ea40f..ccef280122b 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -161,6 +161,8 @@  extern bool rs6000_function_pcrel_p (struct function *);
 extern bool rs6000_pcrel_p (void);
 extern bool rs6000_fndecl_pcrel_p (const_tree);
 extern void rs6000_output_addr_vec_elt (FILE *, int);
+extern bool rs6000_vsx_element_in_dword0_p (rtx, enum machine_mode);
+extern void rs6000_vsx_extract_element_from_dword0 (rtx, rtx, rtx, bool);

 /* Different PowerPC instruction formats that are used by GCC.  There are
    various other instruction formats used by the PowerPC hardware, but these
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index efe9adce1f8..e15f8bd964c 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -29105,6 +29105,74 @@  rs6000_opaque_type_invalid_use_p (gimple *stmt)
   return false;
 }

+/* Return true when the element is in dword0 of a vector.  Exclude word
+   element 1 (BE order) as the word can be extracted by mfvsrwz directly.  */
+
+bool
+rs6000_vsx_element_in_dword0_p (rtx op, enum machine_mode mode)
+{
+  gcc_assert (CONST_INT_P (op));
+  gcc_assert (mode == V16QImode || mode == V8HImode || mode == V4SImode);
+
+  int units = GET_MODE_NUNITS (mode);
+  int elt = INTVAL (op);
+  elt = BYTES_BIG_ENDIAN ? units - 1 - elt : elt;
+
+  if (elt > units / 2
+      || (elt == units / 2 && mode != V4SImode))
+    return true;
+  else
+    return false;
+}
+
+/* Extract element from dword0 by mfvsrd and lshiftrt and mask.  Extend_p
+   indicates if zero extend is needed or not.  */
+
+void
+rs6000_vsx_extract_element_from_dword0 (rtx dest, rtx src, rtx element,
+					bool extend_p)
+{
+  enum machine_mode mode = GET_MODE (src);
+  gcc_assert (rs6000_vsx_element_in_dword0_p (element, mode));
+
+  enum machine_mode dest_mode = GET_MODE (dest);
+  enum machine_mode inner_mode = GET_MODE_INNER (mode);
+  int units = GET_MODE_NUNITS (mode);
+  int elt = INTVAL (element);
+  elt = BYTES_BIG_ENDIAN ? units - 1 - elt : elt;
+  int value, shift;
+  unsigned int mask;
+
+  rtx vec_tmp = gen_lowpart (V2DImode, src);
+  rtx tmp1 = can_create_pseudo_p ()
+	     ? gen_reg_rtx (DImode)
+	     : simplify_gen_subreg (DImode, dest, dest_mode, 0);
+  value = BYTES_BIG_ENDIAN ? 0 : 1;
+  emit_insn (gen_vsx_extract_v2di (tmp1, vec_tmp, GEN_INT (value)));
+
+  rtx tmp2;
+  shift = (elt - units / 2) * GET_MODE_BITSIZE (inner_mode);
+  if (shift || extend_p)
+    {
+      tmp2 = (dest_mode == DImode)
+	     ? dest
+	     : (can_create_pseudo_p ()
+		? gen_reg_rtx (DImode)
+		: simplify_gen_subreg (DImode, dest, dest_mode, 0));
+      mask = (1ULL << GET_MODE_BITSIZE (inner_mode)) - 1;
+      rtx shift_op = gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (shift));
+      emit_insn (gen_rotldi3_mask (tmp2, tmp1, GEN_INT (shift), GEN_INT (mask),
+				   shift_op));
+    }
+  else
+    tmp2 = tmp1;
+
+  if (dest_mode != DImode)
+    emit_move_insn (dest, gen_lowpart (dest_mode, tmp2));
+
+  return;
+}
+
 struct gcc_target targetm = TARGET_INITIALIZER;

 #include "gt-rs6000.h"
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 1a9a7b1a479..a9638a279a6 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -4106,7 +4106,7 @@  (define_insn "*eqv<mode>3"
 
 ;; Rotate-and-mask and insert.

-(define_insn "*rotl<mode>3_mask"
+(define_insn "rotl<mode>3_mask"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
 	(and:GPR (match_operator:GPR 4 "rotate_mask_operator"
 		  [(match_operand:GPR 1 "gpc_reg_operand" "r")
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index 19abfeb565a..7bde98c59b7 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -3855,6 +3855,28 @@  (define_insn "vsx_extract_<mode>_p9"
   [(set_attr "type" "vecsimple")
    (set_attr "isa" "p9v,*")])

+(define_insn_and_split "*vsx_extract_<mode>_zero_extend"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+	(zero_extend:DI
+	  (vec_select:<VEC_base>
+	    (match_operand:VSX_EXTRACT_I 1 "gpc_reg_operand" "v")
+	    (parallel [(match_operand:QI 2 "<VSX_EXTRACT_PREDICATE>" "n")]))))
+   (clobber (match_scratch:VSX_EXTRACT_I 3 "=v"))]
+  "TARGET_DIRECT_MOVE_64BIT
+   && rs6000_vsx_element_in_dword0_p (operands[2], <MODE>mode)"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx element = operands[2];
+
+  rs6000_vsx_extract_element_from_dword0 (dest, src, element, true);
+  DONE;
+}
+  [(set_attr "type" "mfvsr")])
+
 (define_split
   [(set (match_operand:<VEC_base> 0 "int_reg_operand")
 	(vec_select:<VEC_base>
@@ -3864,6 +3886,15 @@  (define_split
   "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_VEXTRACTUB && reload_completed"
   [(const_int 0)]
 {
+  /* If the element is in dword0, it can be extracted by mfvsrd and lshiftrt
+     and mask.  */
+  if (rs6000_vsx_element_in_dword0_p (operands[2], <MODE>mode))
+    {
+      rs6000_vsx_extract_element_from_dword0 (operands[0], operands[1],
+					      operands[2], false);
+      DONE;
+    }
+
   rtx op0_si = gen_rtx_REG (SImode, REGNO (operands[0]));
   rtx op1 = operands[1];
   rtx op2 = operands[2];
@@ -3886,7 +3917,7 @@  (define_insn_and_split "*vsx_extract_<mode>_di_p9"
 	  (match_operand:VSX_EXTRACT_I 1 "gpc_reg_operand" "v,<VSX_EX>")
 	  (parallel [(match_operand:QI 2 "const_int_operand" "n,n")]))))
    (clobber (match_scratch:SI 3 "=r,X"))]
-  "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_VEXTRACTUB"
+  "TARGET_VEXTRACTUB"
   "#"
   "&& reload_completed"
   [(parallel [(set (match_dup 4)
@@ -3897,6 +3928,7 @@  (define_insn_and_split "*vsx_extract_<mode>_di_p9"
 {
   gcc_assert (<MODE>mode != V4SImode
 	      || INTVAL (operands[2]) != (BYTES_BIG_ENDIAN ? 1 : 2));
+  gcc_assert (!rs6000_vsx_element_in_dword0_p (operands[2], <MODE>mode));

   operands[4] = gen_rtx_REG (<VEC_base>mode, REGNO (operands[0]));
 }
@@ -3954,6 +3986,14 @@  (define_insn_and_split "*vsx_extract_v4si_w023"
   rtx element = operands[2];
   rtx vec_tmp;

+  /* If the element is in dword0, it can be extracted by mfvsrd and lshiftrt
+     and mask.  */
+  if (rs6000_vsx_element_in_dword0_p (element, V4SImode))
+    {
+      rs6000_vsx_extract_element_from_dword0 (dest, src, element, false);
+      DONE;
+    }
+
   if (GET_CODE (operands[3]) == SCRATCH)
     vec_tmp = gen_reg_rtx (V4SImode);
   else
@@ -3978,43 +4018,52 @@  (define_insn_and_split  "*vsx_extract_<mode>_p8"
 	 (match_operand:VSX_EXTRACT_I2 1 "gpc_reg_operand" "v")
 	 (parallel [(match_operand:QI 2 "<VSX_EXTRACT_PREDICATE>" "n")])))
    (clobber (match_scratch:VSX_EXTRACT_I2 3 "=v"))]
-  "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_DIRECT_MOVE_64BIT
-   && !TARGET_P9_VECTOR"
+  "TARGET_DIRECT_MOVE_64BIT && !TARGET_P9_VECTOR"
   "#"
-  "&& reload_completed"
+  "&& 1"
   [(const_int 0)]
 {
   rtx dest = operands[0];
   rtx src = operands[1];
   rtx element = operands[2];
-  rtx vec_tmp = operands[3];
+  rtx vec_tmp;
   int value;
+  int num_elt = GET_MODE_NUNITS (<MODE>mode);
+  enum machine_mode dest_mode = GET_MODE (dest);

-  if (!BYTES_BIG_ENDIAN)
-    element = GEN_INT (GET_MODE_NUNITS (<MODE>mode) - 1 - INTVAL (element));
+  /* If the element is in dword0, it can be extracted by mfvsrd and lshiftrt
+     and mask.  */
+  if (rs6000_vsx_element_in_dword0_p (element, <MODE>mode))
+    {
+      rs6000_vsx_extract_element_from_dword0 (dest, src, element, false);
+      DONE;
+    }

-  /* If the value is in the correct position, we can avoid doing the VSPLT<x>
-     instruction.  */
+  if (GET_CODE (operands[3]) == SCRATCH)
+    vec_tmp = gen_reg_rtx (<MODE>mode);
+  else
+    vec_tmp = operands[3];
+
+  if (!BYTES_BIG_ENDIAN)
+    element = GEN_INT (num_elt - 1 - INTVAL (element));
   value = INTVAL (element);
+
   if (<MODE>mode == V16QImode)
-    {
-      if (value != 7)
-	emit_insn (gen_altivec_vspltb_direct (vec_tmp, src, element));
-      else
-	vec_tmp = src;
-    }
+    emit_insn (gen_altivec_vspltb_direct (vec_tmp, src, element));
   else if (<MODE>mode == V8HImode)
-    {
-      if (value != 3)
-	emit_insn (gen_altivec_vsplth_direct (vec_tmp, src, element));
-      else
-	vec_tmp = src;
-    }
+    emit_insn (gen_altivec_vsplth_direct (vec_tmp, src, element));
   else
     gcc_unreachable ();

-  emit_move_insn (gen_rtx_REG (DImode, REGNO (dest)),
-		  gen_rtx_REG (DImode, REGNO (vec_tmp)));
+  value = BYTES_BIG_ENDIAN ? 0 : 1;
+  rtx tmp1 = can_create_pseudo_p ()
+	     ? gen_reg_rtx (DImode)
+	     : simplify_gen_subreg (DImode, dest, dest_mode, 0);
+  rtx vec_tmp1 = gen_lowpart (V2DImode, vec_tmp);
+  emit_insn (gen_vsx_extract_v2di (tmp1, vec_tmp1, GEN_INT (value)));
+
+  emit_move_insn (dest, gen_lowpart (dest_mode, tmp1));
+
   DONE;
 }
   [(set_attr "type" "mfvsr")])
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p8.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p8.c
index f3b9556b2e6..caead22beca 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p8.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p8.c
@@ -49,21 +49,27 @@  testuc_var (vector unsigned char vuc2, signed int si)
   return vec_extract (vuc2, si);
 }

+#ifdef __BIG_ENDIAN__
+#define LANE 12
+#else
+#define LANE 3
+#endif
+
 unsigned char
 testbc_cst (vector bool char vbc2)
 {
-  return vec_extract (vbc2, 12);
+  return vec_extract (vbc2, LANE);
 }

 signed char
 testsc_cst (vector signed char vsc2)
 {
-  return vec_extract (vsc2, 12);
+  return vec_extract (vsc2, LANE);
 }

 unsigned char
 testuc_cst (vector unsigned char vuc2)
 {
-  return vec_extract (vuc2, 12);
+  return vec_extract (vuc2, LANE);
 }

diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p9.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p9.c
index 8a4c380edad..6b7c3f0c9eb 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p9.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-char.p9.c
@@ -34,21 +34,27 @@  testuc_var (vector unsigned char vuc2, signed int si)
   return vec_extract (vuc2, si);
 }

+#ifdef __BIG_ENDIAN__
+#define LANE 12
+#else
+#define LANE 3
+#endif
+
 unsigned char
 testbc_cst (vector bool char vbc2)
 {
-  return vec_extract (vbc2, 12);
+  return vec_extract (vbc2, LANE);
 }

 signed char
 testsc_cst (vector signed char vsc2)
 {
-  return vec_extract (vsc2, 12);
+  return vec_extract (vsc2, LANE);
 }

 unsigned char
 testuc_cst (vector unsigned char vuc2)
 {
-  return vec_extract (vuc2, 12);
+  return vec_extract (vuc2, LANE);
 }

diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p8.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p8.c
index f5f953320d8..961bf2b2a9f 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p8.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p8.c
@@ -54,21 +54,27 @@  testui_var (vector unsigned int vui2, signed int si)
   return vec_extract (vui2, si);
 }

+#ifdef __BIG_ENDIAN__
+#define LANE 11
+#else
+#define LANE 0
+#endif
+
 unsigned int
 testbi_cst (vector bool int vbi2)
 {
-  return vec_extract (vbi2, 12);
+  return vec_extract (vbi2, LANE);
 }

 signed int
 testsi_cst (vector signed int vsi2)
 {
-  return vec_extract (vsi2, 12);
+  return vec_extract (vsi2, LANE);
 }

 unsigned int
 testui_cst (vector unsigned int vui2)
 {
-  return vec_extract (vui2, 12);
+  return vec_extract (vui2, LANE);
 }

diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p9.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p9.c
index 1abf19da40d..46d6a7ce140 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p9.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-int.p9.c
@@ -40,21 +40,27 @@  testui_var (vector unsigned int vui2, signed int si)
   return vec_extract (vui2, si);
 }

+#ifdef __BIG_ENDIAN__
+#define LANE 11
+#else
+#define LANE 0
+#endif
+
 unsigned int
 testbi_cst (vector bool int vbi2)
 {
-  return vec_extract (vbi2, 12);
+  return vec_extract (vbi2, LANE);
 }

 signed int
 testsi_cst (vector signed int vsi2)
 {
-  return vec_extract (vsi2, 12);
+  return vec_extract (vsi2, LANE);
 }

 unsigned int
 testui_cst (vector unsigned int vui2)
 {
-  return vec_extract (vui2, 12);
+  return vec_extract (vui2, LANE);
 }

diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p8.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p8.c
index 0ddecb4e4b5..92ea1f54dec 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p8.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p8.c
@@ -38,22 +38,28 @@ 

 #include <altivec.h>

+#ifdef __BIG_ENDIAN__
+#define LANE 15
+#else
+#define LANE 1
+#endif
+
 unsigned short
 testbi_cst (vector bool short vbs2)
 {
-  return vec_extract (vbs2, 12);
+  return vec_extract (vbs2, LANE);
 }

 signed short
 testsi_cst (vector signed short vss2)
 {
-  return vec_extract (vss2, 12);
+  return vec_extract (vss2, LANE);
 }

 unsigned short
 testui_cst12 (vector unsigned short vus2)
 {
-  return vec_extract (vus2, 12);
+  return vec_extract (vus2, LANE);
 }

 unsigned short
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p9.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p9.c
index fac35cb792f..4cb3fa7d313 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p9.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-extract-short.p9.c
@@ -17,22 +17,28 @@ 

 #include <altivec.h>

+#ifdef __BIG_ENDIAN__
+#define LANE 15
+#else
+#define LANE 1
+#endif
+
 unsigned short
 testbi_cst (vector bool short vbs2)
 {
-  return vec_extract (vbs2, 12);
+  return vec_extract (vbs2, LANE);
 }

 signed short
 testsi_cst (vector signed short vss2)
 {
-  return vec_extract (vss2, 12);
+  return vec_extract (vss2, LANE);
 }

 unsigned short
 testui_cst12 (vector unsigned short vus2)
 {
-  return vec_extract (vus2, 12);
+  return vec_extract (vus2, LANE);
 }

 unsigned short
diff --git a/gcc/testsuite/gcc.target/powerpc/p9-extract-1.c b/gcc/testsuite/gcc.target/powerpc/p9-extract-1.c
index d7d3ad77aea..2e5f2d11bf0 100644
--- a/gcc/testsuite/gcc.target/powerpc/p9-extract-1.c
+++ b/gcc/testsuite/gcc.target/powerpc/p9-extract-1.c
@@ -9,123 +9,124 @@ 

 #include <altivec.h>

+#ifdef __BIG_ENDIAN__
+#define DWORD1_FIRST_INT 3
+#define DWORD1_LAST_INT 2
+#define DWORD1_FIRST_SHORT 7
+#define DWORD1_LAST_SHORT 4
+#define DWORD1_FIRST_CHAR 15
+#define DWORD1_LAST_CHAR 8
+#else
+#define DWORD1_FIRST_INT 0
+#define DWORD1_LAST_INT 1
+#define DWORD1_FIRST_SHORT 0
+#define DWORD1_LAST_SHORT 3
+#define DWORD1_FIRST_CHAR 0
+#define DWORD1_LAST_CHAR 7
+#endif
+
 int
 extract_int_0 (vector int a)
 {
-  int c = 0;
-  int b = vec_extract (a, c);
+  int b = vec_extract (a, DWORD1_FIRST_INT);
   return b;
 }

 int
 extract_int_3 (vector int a)
 {
-  int c = 3;
-  int b = vec_extract (a, c);
+  int b = vec_extract (a, DWORD1_LAST_INT);
   return b;
 }

 unsigned int
 extract_uint_0 (vector unsigned int a)
 {
-  int c = 0;
-  unsigned int b = vec_extract (a, c);
+  unsigned int b = vec_extract (a, DWORD1_FIRST_INT);
   return b;
 }

 unsigned int
 extract_uint_3 (vector unsigned int a)
 {
-  int c = 3;
-  unsigned int b = vec_extract (a, c);
+  unsigned int b = vec_extract (a, DWORD1_LAST_INT);
   return b;
 }

 short
 extract_short_0 (vector short a)
 {
-  int c = 0;
-  short b = vec_extract (a, c);
+  short b = vec_extract (a, DWORD1_FIRST_SHORT);
   return b;
 }

 short
 extract_short_7 (vector short a)
 {
-  int c = 7;
-  short b = vec_extract (a, c);
+  short b = vec_extract (a, DWORD1_LAST_SHORT);
   return b;
 }

 unsigned short
 extract_ushort_0 (vector unsigned short a)
 {
-  int c = 0;
-  unsigned short b = vec_extract (a, c);
+  unsigned short b = vec_extract (a, DWORD1_FIRST_SHORT);
   return b;
 }

 unsigned short
 extract_ushort_7 (vector unsigned short a)
 {
-  int c = 7;
-  unsigned short b = vec_extract (a, c);
+  unsigned short b = vec_extract (a, DWORD1_LAST_SHORT);
   return b;
 }

 signed char
 extract_schar_0 (vector signed char a)
 {
-  int c = 0;
-  signed char b = vec_extract (a, c);
+  signed char b = vec_extract (a, DWORD1_FIRST_CHAR);
   return b;
 }

 signed char
 extract_schar_15 (vector signed char a)
 {
-  int c = 15;
-  signed char b = vec_extract (a, c);
+  signed char b = vec_extract (a, DWORD1_LAST_CHAR);
   return b;
 }

 unsigned char
 extract_uchar_0 (vector unsigned char a)
 {
-  int c = 0;
-  unsigned char b = vec_extract (a, c);
+  unsigned char b = vec_extract (a, DWORD1_FIRST_CHAR);
   return b;
 }

 unsigned char
 extract_uchar_15 (vector unsigned char a)
 {
-  int c = 15;
-  signed char b = vec_extract (a, c);
+  signed char b = vec_extract (a, DWORD1_LAST_CHAR);
   return b;
 }

 unsigned char
 extract_bool_char_0 (vector bool char a)
 {
-  int c = 0;
-  unsigned char b = vec_extract (a, c);
+  unsigned char b = vec_extract (a, DWORD1_FIRST_CHAR);
   return b;
 }

 unsigned int
 extract_bool_int_0 (vector bool int a)
 {
-  int c = 0;
-  unsigned int b = vec_extract (a, c);
+  unsigned int b = vec_extract (a, DWORD1_FIRST_INT);
   return b;
 }

 unsigned short int
 extract_bool_short_int_0 (vector bool short int a)
 {
-  int c = 0;
-  unsigned short int b = vec_extract (a, c);
+  unsigned short int b = vec_extract (a, DWORD1_FIRST_SHORT);
   return b;
 }

diff --git a/gcc/testsuite/gcc.target/powerpc/pr110331-p8.c b/gcc/testsuite/gcc.target/powerpc/pr110331-p8.c
new file mode 100644
index 00000000000..e942443c45b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr110331-p8.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mdejagnu-cpu=power8 -O2" } */
+/* { dg-require-effective-target has_arch_ppc64 } */
+
+#include "pr110331.h"
+
+/* { dg-final { scan-assembler-times {\mmfvsrd\M} 10 } } */
+/* { dg-final { scan-assembler-times {\mmfvsrwz\M} 2 } } */
+/* { dg-final { scan-assembler-times {\mrldicl\M} 8 } } */
+/* { dg-final { scan-assembler-times {\mexts[bhw]\M} 6 } } */
+/* { dg-final { scan-assembler-not {\mvsplt} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr110331-p9.c b/gcc/testsuite/gcc.target/powerpc/pr110331-p9.c
new file mode 100644
index 00000000000..a5c84d237c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr110331-p9.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -O2" } */
+/* { dg-require-effective-target has_arch_ppc64 } */
+
+#include "pr110331.h"
+
+/* { dg-final { scan-assembler-times {\mmfvsrd\M} 10 } } */
+/* { dg-final { scan-assembler-times {\mmfvsrwz\M} 2 } } */
+/* { dg-final { scan-assembler-times {\mrldicl\M} 8 } } */
+/* { dg-final { scan-assembler-times {\mexts[bhw]\M} 6 } } */
+/* { dg-final { scan-assembler-not {\mvextu} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr110331.h b/gcc/testsuite/gcc.target/powerpc/pr110331.h
new file mode 100644
index 00000000000..01deb19534a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr110331.h
@@ -0,0 +1,90 @@ 
+#include <altivec.h>
+
+#ifdef __BIG_ENDIAN__
+#define DWORD0_FIRST_INT 1
+#define DWORD0_LAST_INT 0
+#define DWORD0_FIRST_SHORT 3
+#define DWORD0_LAST_SHORT 0
+#define DWORD0_FIRST_CHAR 7
+#define DWORD0_LAST_CHAR 0
+#else
+#define DWORD0_FIRST_INT 2
+#define DWORD0_LAST_INT 3
+#define DWORD0_FIRST_SHORT 4
+#define DWORD0_LAST_SHORT 7
+#define DWORD0_FIRST_CHAR 8
+#define DWORD0_LAST_CHAR 15
+#endif
+
+/* mfvsrd, rldicl */
+unsigned char testuc_f (vector unsigned char v)
+{
+  return vec_extract (v, DWORD0_FIRST_CHAR);
+}
+
+/* mfvsrd, extsb */
+signed char testsc_f (vector signed char v)
+{
+  return vec_extract (v, DWORD0_FIRST_CHAR);
+}
+
+/* mfvsrd, rldicl */
+unsigned char testuc_l (vector unsigned char v)
+{
+  return vec_extract (v, DWORD0_LAST_CHAR);
+}
+
+/* mfvsrd, rldicl, extsb */
+signed char testsc_l (vector signed char v)
+{
+  return vec_extract (v, DWORD0_LAST_CHAR);
+}
+
+/* mfvsrd, rldicl */
+unsigned short testus_f (vector unsigned short v)
+{
+  return vec_extract (v, DWORD0_FIRST_SHORT);
+}
+
+/* mfvsrd, extsh */
+signed short testss_f (vector signed short v)
+{
+  return vec_extract (v, DWORD0_FIRST_SHORT);
+}
+
+/* mfvsrd, rldicl */
+unsigned short testus_l (vector unsigned short v)
+{
+  return vec_extract (v, DWORD0_LAST_SHORT);
+}
+
+/* mfvsrd, rldicl, extsh */
+signed short testss_l (vector signed short v)
+{
+  return vec_extract (v, DWORD0_LAST_SHORT);
+}
+
+/* mfvsrwz */
+unsigned int testui_f (vector unsigned int v)
+{
+  return vec_extract (v, DWORD0_FIRST_INT);
+}
+
+/* mfvsrwz, extsw */
+signed int testsi_f (vector signed int v)
+{
+  return vec_extract (v, DWORD0_FIRST_INT);
+}
+
+/* mfvsrd, rldicl */
+unsigned int testui_l (vector unsigned int v)
+{
+  return vec_extract (v, DWORD0_LAST_INT);
+}
+
+/* mfvsrd, rldicl, extsw */
+signed int testsi_l (vector signed int v)
+{
+  return vec_extract (v, DWORD0_LAST_INT);
+}
+