diff mbox

[v2,rs6000] gcc mainline, add builtin support for vec_doublee, vec_doubleo, vec_doublel builtins

Message ID 1495815446.3485.56.camel@us.ibm.com
State New
Headers show

Commit Message

Carl Love May 26, 2017, 4:17 p.m. UTC
GCC Maintainers:

This is version 2 of the patch to add support for the various
vec_doublee, vec_doubleo, vec_doublel, vec_doubleh builtin-ins. I have
addressed the various comments from Segher.

The patch has been tested on powerpc64le-unknown-linux-gnu (Power 8 LE)
with no regressions.

Is the patch OK for gcc mainline?

                  Carl Love
---------------------------------------------------------------

gcc/ChangeLog:

2017-05-26  Carl Love  <cel@us.ibm.com>

   * config/rs6000/rs6000-c: Add support for built-in functions
   vector double vec_doublee (vector signed int);
   vector double vec_doublee (vector unsigned int);
   vector double vec_doublee (vector float);
   vector double vec_doubleh (vector signed int);
   vector double vec_doubleh (vector unsigned int);
   vector double vec_doubleh (vector float);
   vector double vec_doublel (vector signed int);
   vector double vec_doublel (vector unsigned int);
   vector double vec_doublel (vector float);
   vector double vec_doubleo (vector signed int);
   vector double vec_doubleo (vector unsigned int);
   vector double vec_doubleo (vector float);.
   * config/rs6000/rs6000-builtin.def: Add definitions for DOUBLEE,
   DOUBLEO, DOUBLEH, DOUBLEL, UNS_DOUBLEO, UNS_DOUBLEE, UNS_DOUBLEH,
   UNS_DOUBLEL.
   * config/rs6000/altivec.md: Add code generator for doublee, unsdoublee
   doubleov, unsdoubleov, doublehv, unsdoublehv, doublelv, unsdoublelv.
   * config/rs6000/altivec.h: Add define for vec_doublee, vec_doubleo,
   vec_doublel, vec_doubleh.
   * doc/extend.texi: Update the built-in documentation file for the
   new built-in functions.

2017-05-26  Carl Love  <cel@us.ibm.com>

gcc/testsuite/ChangeLog:

   * gcc.target/powerpc/builtins-3-runable.c: New file of runnable tests
   for the new built-ins.

Signed-off-by: Carl Love <carll@us.ibm.com>
---
 gcc/config/rs6000/altivec.h                        |   4 +
 gcc/config/rs6000/altivec.md                       | 338 +++++++++++++++++++++
 gcc/config/rs6000/rs6000-builtin.def               |  21 ++
 gcc/config/rs6000/rs6000-c.c                       |  29 ++
 gcc/doc/extend.texi                                |  16 +
 .../gcc.target/powerpc/builtins-3-runnable.c       |  83 +++++
 6 files changed, 491 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/builtins-3-runnable.c

Comments

Segher Boessenkool May 30, 2017, 11:23 p.m. UTC | #1
Hi!

On Fri, May 26, 2017 at 09:17:26AM -0700, Carl E. Love wrote:
>    * config/rs6000/altivec.md: Add code generator for doublee, unsdoublee
>    doubleov, unsdoubleov, doublehv, unsdoublehv, doublelv, unsdoublelv.

Please mention the full name of the define_*, i.e.

	* config/rs6000/altivec.md (doublee<mode>2, unsdoubleev4si2,
	doubleo<mode>2, [etc., write them all here]): New patterns.

> +;; Generate doublee
> +;;    signed int/float to double convert words 0 and 2
> +(define_expand "doublee<mode>2"
> +  [(set (match_operand:V2DF 0 "register_operand" "=v")
> +        (match_operand:VSX_W 1 "register_operand" "v"))]
> +   "TARGET_VSX"

Indent only two spaces please.

> +{
> +   machine_mode op_mode = GET_MODE (operands[1]);

And esp. in the C function body.

> +   if (VECTOR_ELT_ORDER_BIG)
> +     {
> +        /* Big endian word numbering for words in operand is 0 1 2 3.
> +           Input words 0 and 2 are where they need to be. */

Dot space space.

> +           conversion. */
> +        rtx rtx_tmp;
> +        rtx rtx_val = GEN_INT (1);
> +
> +        rtx_tmp = gen_reg_rtx (op_mode);
> +        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
> +                   operands[1], operands[1], rtx_val));

Indents should use a tab character instead of eight spaces.

Following parameters should be indented to the same level as the first:

       emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp, operands[1], operands[1],
					  rtx_val));

> +        /* Want to convert the words 1 and 3.
> +           Little endian word numbering for operand is 3 2 1 0.
> +           Input words 3 and 1 are where they need to be.
> +        */

The closing */ should not be on a line by itself.

> +  { VSX_BUILTIN_VEC_DOUBLEE, VSX_BUILTIN_DOUBLEE_V4SI,
> +    RS6000_BTI_V2DF, RS6000_BTI_V4SI, 0, 0 },
> +  { VSX_BUILTIN_VEC_DOUBLEE, VSX_BUILTIN_UNS_DOUBLEE_V4SI,
> +    RS6000_BTI_V2DF, RS6000_BTI_unsigned_V4SI, 0, 0 },
> +  { VSX_BUILTIN_VEC_DOUBLEE, VSX_BUILTIN_DOUBLEE_V4SF,
> +    RS6000_BTI_V2DF, RS6000_BTI_V4SF, 0, 0 },
> +
> +  { VSX_BUILTIN_VEC_DOUBLEO, VSX_BUILTIN_DOUBLEO_V4SI,
> +	 RS6000_BTI_V2DF, RS6000_BTI_V4SI, 0, 0 },
> +  { VSX_BUILTIN_VEC_DOUBLEO, VSX_BUILTIN_UNS_DOUBLEO_V4SI,
> +	 RS6000_BTI_V2DF, RS6000_BTI_unsigned_V4SI, 0, 0 },
> +  { VSX_BUILTIN_VEC_DOUBLEO, VSX_BUILTIN_DOUBLEO_V4SF,
> +	 RS6000_BTI_V2DF, RS6000_BTI_V4SF, 0, 0 },

This second (and later) blocks have the indent of the second lines
different from how existing code does it (the first block is fine).

> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/powerpc/builtins-3-runnable.c
> @@ -0,0 +1,83 @@
> +/* { dg-do run { target { powerpc*-*-linux* } } } */
> +/* { dg-require-effective-target vsx_hw } */
> +/* { dg-options "-O2 -mvsx" } */

Does this test work on power7?  Or even compile?  That is the minimum
you are requiring here.


Segher
diff mbox

Patch

diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
index c92bcce..20050eb 100644
--- a/gcc/config/rs6000/altivec.h
+++ b/gcc/config/rs6000/altivec.h
@@ -128,6 +128,10 @@ 
 #define vec_ctu __builtin_vec_ctu
 #define vec_cpsgn __builtin_vec_copysign
 #define vec_double __builtin_vec_double
+#define vec_doublee __builtin_vec_doublee
+#define vec_doubleo __builtin_vec_doubleo
+#define vec_doublel __builtin_vec_doublel
+#define vec_doubleh __builtin_vec_doubleh
 #define vec_expte __builtin_vec_expte
 #define vec_floor __builtin_vec_floor
 #define vec_loge __builtin_vec_loge
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 649f181..dd08a90 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -203,6 +203,10 @@ 
 			   (KF "FLOAT128_VECTOR_P (KFmode)")
 			   (TF "FLOAT128_VECTOR_P (TFmode)")])
 
+;; Map the Vector convert single precision to double precision for integer
+;; versus floating point
+(define_mode_attr VS_sxwsp [(V4SI "sxw") (V4SF "sp")])
+
 ;; Specific iterator for parity which does not have a byte/half-word form, but
 ;; does have a quad word form
 (define_mode_iterator VParity [V4SI
@@ -2739,6 +2743,340 @@ 
   "stvewx %1,%y0"
   [(set_attr "type" "vecstore")])
 
+;; Generate doublee
+;;    signed int/float to double convert words 0 and 2
+(define_expand "doublee<mode>2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:VSX_W 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   machine_mode op_mode = GET_MODE (operands[1]);
+
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for words in operand is 0 1 2 3.
+           Input words 0 and 2 are where they need to be. */
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], operands[1]));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           take (operand[1] operand[1]) and shift left one word
+                 3 2 1 0    3 2 1 0  =>  2 1 0 3
+           Input words 2 and 0 are now where they need to be for the
+           conversion. */
+        rtx rtx_tmp;
+        rtx rtx_val = GEN_INT (1);
+
+        rtx_tmp = gen_reg_rtx (op_mode);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], rtx_tmp));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate unsdoublee
+;;    unsigned int to double convert words 0 and 2
+(define_expand "unsdoubleev4si2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:V4SI 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for words in operand is 0 1 2 3.
+           Input words 0 and 2 are where they need to be. */
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], operands[1]));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           take (operand[1] operand[1]) and shift left one word
+                 3 2 1 0    3 2 1 0  =>   2 1 0 3
+           Input words 2 and 0 are now where they need to be for the
+           conversion. */
+        rtx rtx_tmp;
+        rtx rtx_val = GEN_INT (1);
+
+        rtx_tmp = gen_reg_rtx (V4SImode);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], rtx_tmp));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate doubleov
+;;    signed int/float to double convert words 1 and 3
+(define_expand "doubleo<mode>2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:VSX_W 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   machine_mode op_mode = GET_MODE (operands[1]);
+
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for words in operand is 0 1 2 3.
+           take (operand[1] operand[1]) and shift left one word
+                 0 1 2 3    0 1 2 3  =>  1 2 3 0
+           Input words 1 and 3 are now where they need to be for the
+           conversion. */
+        rtx rtx_tmp;
+        rtx rtx_val = GEN_INT (1);
+
+        rtx_tmp = gen_reg_rtx (op_mode);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], rtx_tmp));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           Input words 3 and 1 are where they need to be. */
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], operands[1]));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate unsdoubleov
+;;    unsigned int to double convert words 1 and 3
+(define_expand "unsdoubleov4si2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:V4SI 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for words in operand is 0 1 2 3.
+           take (operand[1] operand[1]) and shift left one word
+                 0 1 2 3    0 1 2 3  =>  1 2 3 0
+           Input words 1 and 3 are now where they need to be for the
+           conversion. */
+        rtx rtx_tmp;
+        rtx rtx_val = GEN_INT (1);
+
+        rtx_tmp = gen_reg_rtx (V4SImode);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], rtx_tmp));
+     }
+   else
+     {
+        /* Want to convert the words 1 and 3.
+           Little endian word numbering for operand is 3 2 1 0.
+           Input words 3 and 1 are where they need to be.
+        */
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], operands[1]));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate doublehv
+;;    signed int/float to double convert words 0 and 1
+(define_expand "doubleh<mode>2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:VSX_W 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   rtx rtx_tmp;
+   rtx rtx_val;
+
+   machine_mode op_mode = GET_MODE (operands[1]);
+   rtx_tmp = gen_reg_rtx (op_mode);
+
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for words in operand is 0 1 2 3.
+           Shift operand left one word, rtx_tmp word order is now 1 2 3 0.
+           take (rts_tmp operand[1]) and shift left three words
+                 1 2 3 0  0 1 2 3 => 0 0 1 2
+           Input words 0 and 1 are now where they need to be for the
+           conversion. */
+        rtx_val = GEN_INT (1);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   rtx_tmp, operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], rtx_tmp));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           Shift operand left three words, rtx_tmp word order is now 0 3 2 1.
+           take (operand[1] rts_tmp ) and shift left two words
+                 3 2 1 0  0 3 2 1   =>  1 0 0 3
+           Input words 0 and 1 are now where they need to be for the
+           conversion. */
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (2);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], rtx_tmp, rtx_val));
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], rtx_tmp));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate unsdoublehv
+;;    unsigned int to double convert words 0 and 1
+(define_expand "unsdoublehv4si2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:V4SI 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   rtx rtx_tmp = gen_reg_rtx (V4SImode);
+   rtx rtx_val = GEN_INT (12);
+
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for words in operand is 0 1 2 3.
+           Shift operand left one word, rtx_tmp word order is now 1 2 3 0.
+           take (rts_tmp operand[1]) and shift left three words
+                 1 2 3 0  0 1 2 3 => 0 0 1 2
+           Input words 0 and 1 are now where they need to be for the
+           conversion. */
+        rtx_val = GEN_INT (1);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   rtx_tmp, operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], rtx_tmp));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           Shift operand left three words, rtx_tmp word order is now 0 3 2 1.
+           take (operand[1] rts_tmp) and shift left two words
+                 3 2 1 0   0 3 2 1  =>   1 0 0 3
+           Input words 1 and 0 are now where they need to be for the
+           conversion. */
+        rtx_val = GEN_INT (3);
+
+        rtx_tmp = gen_reg_rtx (V4SImode);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (2);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], rtx_tmp, rtx_val));
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], rtx_tmp));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate doublelv
+;;    signed int/float to double convert words 2 and 3
+(define_expand "doublel<mode>2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:VSX_W 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   rtx rtx_tmp;
+   rtx rtx_val = GEN_INT (3);
+
+   machine_mode op_mode = GET_MODE (operands[1]);
+   rtx_tmp = gen_reg_rtx (op_mode);
+
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for operand is 0 1 2 3.
+           Shift operand left three words, rtx_tmp word order is now 3 0 1 2.
+           take (operand[1] rtx_tmp) and shift left two words
+                  0 1 2 3   3 0 1 2  =>  2 3 3 0
+           now use convert instruction to convert word 2 and 3 in the
+           input vector. */
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (8);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], rtx_tmp, rtx_val));
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], rtx_tmp));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           Shift operand left one word, rtx_tmp word order is now  2 1 0 3.
+           take (rtx_tmp operand[1]) and shift left three words
+                 2 1 0 3  3 2 1 0  =>  3 3 2 1
+           now use convert instruction to convert word 3 and 2 in the
+           input vector. */
+        rtx_val = GEN_INT (1);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_<mode> (rtx_tmp,
+                   rtx_tmp, operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcv<VS_sxwsp>dp (operands[0], rtx_tmp));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
+;; Generate unsdoublelv
+;;    unsigned int to double convert convert 2 and 3
+(define_expand "unsdoublelv4si2"
+  [(set (match_operand:V2DF 0 "register_operand" "=v")
+        (match_operand:V4SI 1 "register_operand" "v"))]
+   "TARGET_VSX"
+{
+   rtx rtx_tmp = gen_reg_rtx (V4SImode);
+   rtx rtx_val = GEN_INT (12);
+
+   if (VECTOR_ELT_ORDER_BIG)
+     {
+        /* Big endian word numbering for operand is 0 1 2 3.
+           Shift operand left three words, rtx_tmp word order is now 3 0 1 2.
+           take (operand[1] rtx_tmp) and shift left two words
+                  0 1 2 3   3 0 1 2  =>  2 3 3 0
+           now use convert instruction to convert word 2 and 3 in the
+           input vector. */
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (2);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], rtx_tmp, rtx_val));
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], rtx_tmp));
+     }
+   else
+     {
+        /* Little endian word numbering for operand is 3 2 1 0.
+           Shift operand left one word, rtx_tmp word order is now 2 1 0 3.
+           take (rtx_tmp operand[1]) and shift left three words
+                 2 1 0 3  3 2 1 0  =>   3 3 2 1
+           now use convert instruction to convert word 3 and 2 in the
+           input vector. */
+        rtx_val = GEN_INT (1);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   operands[1], operands[1], rtx_val));
+
+        rtx_val = GEN_INT (3);
+        emit_insn (gen_vsx_xxsldwi_v4si (rtx_tmp,
+                   rtx_tmp, operands[1], rtx_val));
+        emit_insn (gen_vsx_xvcvuxwdp (operands[0], rtx_tmp));
+     }
+   DONE;
+}
+  [(set_attr "type" "veccomplex")])
+
 ;; Generate
 ;;    xxlxor/vxor SCRATCH0,SCRATCH0,SCRATCH0
 ;;    vsubu?m SCRATCH2,SCRATCH1,%1
diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
index ebe005a..de6b2cc 100644
--- a/gcc/config/rs6000/rs6000-builtin.def
+++ b/gcc/config/rs6000/rs6000-builtin.def
@@ -1719,6 +1719,19 @@  BU_VSX_1 (XSRDPIM,	      "xsrdpim",	CONST,	floordf2)
 BU_VSX_1 (XSRDPIP,	      "xsrdpip",	CONST,	ceildf2)
 BU_VSX_1 (XSRDPIZ,	      "xsrdpiz",	CONST,	btruncdf2)
 
+BU_VSX_1 (DOUBLEE_V4SI,      "doublee_v4si",     CONST,	doubleev4si2)
+BU_VSX_1 (DOUBLEE_V4SF,      "doublee_v4sf",     CONST,	doubleev4sf2)
+BU_VSX_1 (UNS_DOUBLEE_V4SI,  "uns_doublee_v4si", CONST,	unsdoubleev4si2)
+BU_VSX_1 (DOUBLEO_V4SI,      "doubleo_v4si",     CONST,	doubleov4si2)
+BU_VSX_1 (DOUBLEO_V4SF,      "doubleo_v4sf",     CONST,	doubleov4sf2)
+BU_VSX_1 (UNS_DOUBLEO_V4SI,  "uns_doubleo_v4si", CONST,	unsdoubleov4si2)
+BU_VSX_1 (DOUBLEH_V4SI,      "doubleh_v4si",     CONST,	doublehv4si2)
+BU_VSX_1 (DOUBLEH_V4SF,      "doubleh_v4sf",     CONST,	doublehv4sf2)
+BU_VSX_1 (UNS_DOUBLEH_V4SI,  "uns_doubleh_v4si", CONST,	unsdoublehv4si2)
+BU_VSX_1 (DOUBLEL_V4SI,      "doublel_v4si",     CONST,	doublelv4si2)
+BU_VSX_1 (DOUBLEL_V4SF,      "doublel_v4sf",     CONST,	doublelv4sf2)
+BU_VSX_1 (UNS_DOUBLEL_V4SI,  "uns_doublel_v4si", CONST,	unsdoublelv4si2)
+
 /* VSX predicate functions.  */
 BU_VSX_P (XVCMPEQSP_P,	      "xvcmpeqsp_p",	CONST,	vector_eq_v4sf_p)
 BU_VSX_P (XVCMPGESP_P,	      "xvcmpgesp_p",	CONST,	vector_ge_v4sf_p)
@@ -1809,6 +1822,14 @@  BU_VSX_OVERLOAD_2 (XXSPLTW,  "xxspltw")
 
 /* 1 argument VSX overloaded builtin functions.  */
 BU_VSX_OVERLOAD_1 (DOUBLE,   "double")
+BU_VSX_OVERLOAD_1 (DOUBLEE,  "doublee")
+BU_VSX_OVERLOAD_1 (UNS_DOUBLEE,  "uns_doublee")
+BU_VSX_OVERLOAD_1 (DOUBLEO,  "doubleo")
+BU_VSX_OVERLOAD_1 (UNS_DOUBLEO,  "uns_doubleo")
+BU_VSX_OVERLOAD_1 (DOUBLEH,  "doubleh")
+BU_VSX_OVERLOAD_1 (UNS_DOUBLEH,  "uns_doubleh")
+BU_VSX_OVERLOAD_1 (DOUBLEL,  "doublel")
+BU_VSX_OVERLOAD_1 (UNS_DOUBLEL,  "uns_doublel")
 
 /* VSX builtins that are handled as special cases.  */
 BU_VSX_OVERLOAD_X (LD,	     "ld")
diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index 8039814..c3a6a11 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -1513,6 +1513,35 @@  const struct altivec_builtin_types altivec_overloaded_builtins[] = {
     RS6000_BTI_V2DF, RS6000_BTI_V2DI, 0, 0 },
   { VSX_BUILTIN_VEC_DOUBLE, VSX_BUILTIN_XVCVUXDDP,
     RS6000_BTI_V2DF, RS6000_BTI_unsigned_V2DI, 0, 0 },
+
+  { VSX_BUILTIN_VEC_DOUBLEE, VSX_BUILTIN_DOUBLEE_V4SI,
+    RS6000_BTI_V2DF, RS6000_BTI_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEE, VSX_BUILTIN_UNS_DOUBLEE_V4SI,
+    RS6000_BTI_V2DF, RS6000_BTI_unsigned_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEE, VSX_BUILTIN_DOUBLEE_V4SF,
+    RS6000_BTI_V2DF, RS6000_BTI_V4SF, 0, 0 },
+
+  { VSX_BUILTIN_VEC_DOUBLEO, VSX_BUILTIN_DOUBLEO_V4SI,
+	 RS6000_BTI_V2DF, RS6000_BTI_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEO, VSX_BUILTIN_UNS_DOUBLEO_V4SI,
+	 RS6000_BTI_V2DF, RS6000_BTI_unsigned_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEO, VSX_BUILTIN_DOUBLEO_V4SF,
+	 RS6000_BTI_V2DF, RS6000_BTI_V4SF, 0, 0 },
+
+  { VSX_BUILTIN_VEC_DOUBLEH, VSX_BUILTIN_DOUBLEH_V4SI,
+	 RS6000_BTI_V2DF, RS6000_BTI_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEH, VSX_BUILTIN_UNS_DOUBLEH_V4SI,
+	 RS6000_BTI_V2DF, RS6000_BTI_unsigned_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEH, VSX_BUILTIN_DOUBLEH_V4SF,
+	 RS6000_BTI_V2DF, RS6000_BTI_V4SF, 0, 0 },
+
+  { VSX_BUILTIN_VEC_DOUBLEL, VSX_BUILTIN_DOUBLEL_V4SI,
+	 RS6000_BTI_V2DF, RS6000_BTI_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEL, VSX_BUILTIN_UNS_DOUBLEL_V4SI,
+	 RS6000_BTI_V2DF, RS6000_BTI_unsigned_V4SI, 0, 0 },
+  { VSX_BUILTIN_VEC_DOUBLEL, VSX_BUILTIN_DOUBLEL_V4SF,
+	 RS6000_BTI_V2DF, RS6000_BTI_V4SF, 0, 0 },
+
   { ALTIVEC_BUILTIN_VEC_LD, ALTIVEC_BUILTIN_LVX_V2DF,
     RS6000_BTI_V2DF, RS6000_BTI_INTSI, ~RS6000_BTI_V2DF, 0 },
   { ALTIVEC_BUILTIN_VEC_LD, ALTIVEC_BUILTIN_LVX_V2DI,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3511d25..a895ed4 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -15872,6 +15872,22 @@  vector signed long vec_cts (vector double, const int);
 vector unsigned int vec_ctu (vector float, const int);
 vector unsigned long vec_ctu (vector double, const int);
 
+vector double vec_doublee (vector float);
+vector double vec_doublee (vector signed int);
+vector double vec_doublee (vector unsigned int);
+
+vector double vec_doubleo (vector float);
+vector double vec_doubleo (vector signed int);
+vector double vec_doubleo (vector unsigned int);
+
+vector double vec_doubleh (vector float);
+vector double vec_doubleh (vector signed int);
+vector double vec_doubleh (vector unsigned int);
+
+vector double vec_doublel (vector float);
+vector double vec_doublel (vector signed int);
+vector double vec_doublel (vector unsigned int);
+
 void vec_dss (const int);
 
 void vec_dssall (void);
diff --git a/gcc/testsuite/gcc.target/powerpc/builtins-3-runnable.c b/gcc/testsuite/gcc.target/powerpc/builtins-3-runnable.c
new file mode 100644
index 0000000..14ee252
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtins-3-runnable.c
@@ -0,0 +1,83 @@ 
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target vsx_hw } */
+/* { dg-options "-O2 -mvsx" } */
+
+#include <altivec.h> // vector
+
+void abort (void);
+
+void test_result_dp(vector double vec_result, vector double vec_expected)
+{
+	if (vec_result[0] != vec_expected[0])
+		abort();
+
+	if (vec_result[1] != vec_expected[1])
+		abort();
+}
+
+int main()
+{
+	int i;
+	vector unsigned int vec_unint;
+	vector signed int vec_int;
+	vector float  vec_flt, vec_flt_result, vec_flt_expected;
+	vector double vec_dble0, vec_dble1, vec_dble_result, vec_dble_expected;
+
+	vec_int = (vector signed int){ -1, 3, -5, 1234567 };
+	vec_unint = (vector unsigned int){ 9, 11, 15, 2468013579 };
+	vec_flt = (vector float){ -21., 3.5, -53., 78. };
+	vec_dble0 = (vector double){ 34.0, 97.0 };
+	vec_dble1 = (vector double){ 214.0, -5.5 };
+
+	/* conversion of words 0 and 2 */
+	vec_dble_expected = (vector double){-1.000000, -5.000000};
+	vec_dble_result = vec_doublee (vec_int);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+	
+	vec_dble_expected = (vector double){9.000000, 15.000000};
+	vec_dble_result = vec_doublee (vec_unint);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+	vec_dble_expected = (vector double){-21.000000, -53.000000};
+	vec_dble_result = vec_doublee (vec_flt);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+
+	/* conversion of words 1 and 3 */
+	vec_dble_expected = (vector double){3.000000, 1234567.000000};
+	vec_dble_result = vec_doubleo (vec_int);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+   
+	vec_dble_expected = (vector double){11.000000, 2468013579.000000};
+	vec_dble_result = vec_doubleo (vec_unint);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+	vec_dble_expected = (vector double){3.500000, 78.000000};
+	vec_dble_result = vec_doubleo (vec_flt);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+
+	/* conversion of words 0 and 1 */
+	vec_dble_expected = (vector double){-5.000000, 1234567.000000};
+	vec_dble_result = vec_doublel (vec_int);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+   
+	vec_dble_expected = (vector double){15.000000, 2468013579.000000};
+	vec_dble_result = vec_doublel (vec_unint);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+	vec_dble_expected = (vector double){-53.000000, 78.000000};
+	vec_dble_result = vec_doublel (vec_flt);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+   
+	/* conversion of words 2 and 3 */
+	vec_dble_expected = (vector double){-1.000000, 3.000000};
+	vec_dble_result = vec_doubleh (vec_int);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+   
+	vec_dble_expected = (vector double){9.000000, 11.000000};
+	vec_dble_result = vec_doubleh (vec_unint);
+	test_result_dp(vec_dble_result, vec_dble_expected);
+
+}