[PATCH] rs6000: Add xxeval and vec_ternarylogic

Bill Schmidt wschmidt@linux.ibm.com
Sat May 9 01:13:22 GMT 2020


From: Kelvin Nilsen <kelvin@gcc.gnu.org>

Add the xxeval insn and access it via the vec_ternarylogic built-in
function.  As part of this, add support to the built-in function
infrastructure for functions that take four arguments.

Bootstrapped and tested on powerpc64le-unknown-linux-gnu with no
regressions, using a native POWER9 compiler.  Is this okay for
master?

Thanks,
Bill

[gcc]

2020-05-08  Kelvin Nilsen  <wschmidt@linux.ibm.com>

	* config/rs6000/altivec.h (vec_ternarylogic): New #define.
	(UNSPEC_XXEVAL): New constant.
	(xxeval): New insn.
	* config/rs6000/predicates.md (u8bit_cint_operand): New predicate.
	* config/rs6000/rs6000-builtin.def: Add handling of new macro
	RS6000_BUILTIN_4.
	(BU_FUTURE_V_4): New macro.
	(BU_FUTURE_OVERLOAD_4): Likewise.
	* config/rs6000/rs6000-c.c (altivec_build_resolved_builtin): Add
	handling for quaternary built-in functions.
	(altivec_resolve_overloaded_builtin): Add special-case handling
	for __builtin_vec_xxeval.
	* config/rs6000/rs6000-call.c: Add handling of new macro
	RS6000_BUILTIN_4 in initialization of rs6000_builtin_info,
	bdesc0_arg, bdesc1_arg, bdesc2_arg, bdesc_3arg,
	bdesc_altivec_preds, bdesc_abs, and bdesc_htm arrays.
	(altivec_overloaded_builtins): Add definitions for
	FUTURE_BUILTIN_VEC_XXEVAL.
	(bdesc_4arg): New array.
	(htm_expand_builtin): Add handling for quaternary built-in
	functions.
	(rs6000_expand_quaternop_builtin): New function.
	(rs6000_expand_builtin): Add handling for quaternary built-in
	functions.
	(rs6000_init_builtins): Initialize builtin_mode_to_type entries
	for unsigned QImode and unsigned HImode.
	(builtin_quaternary_function_type): New function.
	(rs6000_common_init_builtins): Add handling of quaternary
	operations.
	* config/rs6000/rs6000.h (RS6000_BTC_QUATERNARY): New defined
	constant.
	(RS6000_BTC_PREDICATE): Change value of constant.
	(RS6000_BTC_ABS): Likewise.
	(rs6000_builtins): Add support for new macro RS6000_BUILTIN_4.
	* doc/extend.texi (PowerPC AltiVec Built-In Functions Available
	for a Future Architecture): Add description of vec_ternarylogic
	built-in function.

[gcc/testsuite]

2020-05-08  Kelvin Nilsen  <wschmidt@linux.ibm.com>

	* gcc.target/powerpc/vec-ternarylogic-0.c: New.
	* gcc.target/powerpc/vec-ternarylogic-1.c: New.
	* gcc.target/powerpc/vec-ternarylogic-10.c: New.
	* gcc.target/powerpc/vec-ternarylogic-2.c: New.
	* gcc.target/powerpc/vec-ternarylogic-3.c: New.
	* gcc.target/powerpc/vec-ternarylogic-4.c: New.
	* gcc.target/powerpc/vec-ternarylogic-5.c: New.
	* gcc.target/powerpc/vec-ternarylogic-6.c: New.
	* gcc.target/powerpc/vec-ternarylogic-7.c: New.
	* gcc.target/powerpc/vec-ternarylogic-8.c: New.
	* gcc.target/powerpc/vec-ternarylogic-9.c: New.
---
 gcc/config/rs6000/altivec.h                   |   1 +
 gcc/config/rs6000/altivec.md                  |  11 +
 gcc/config/rs6000/predicates.md               |   5 +
 gcc/config/rs6000/rs6000-builtin.def          |  23 ++
 gcc/config/rs6000/rs6000-c.c                  |  47 +++-
 gcc/config/rs6000/rs6000-call.c               | 251 ++++++++++++++++++
 gcc/config/rs6000/rs6000.h                    |  12 +-
 gcc/doc/extend.texi                           |  21 ++
 .../gcc.target/powerpc/vec-ternarylogic-0.c   | 120 +++++++++
 .../gcc.target/powerpc/vec-ternarylogic-1.c   | 119 +++++++++
 .../gcc.target/powerpc/vec-ternarylogic-10.c  | 129 +++++++++
 .../gcc.target/powerpc/vec-ternarylogic-2.c   | 105 ++++++++
 .../gcc.target/powerpc/vec-ternarylogic-3.c   | 106 ++++++++
 .../gcc.target/powerpc/vec-ternarylogic-4.c   | 104 ++++++++
 .../gcc.target/powerpc/vec-ternarylogic-5.c   | 103 +++++++
 .../gcc.target/powerpc/vec-ternarylogic-6.c   | 104 ++++++++
 .../gcc.target/powerpc/vec-ternarylogic-7.c   | 103 +++++++
 .../gcc.target/powerpc/vec-ternarylogic-8.c   | 128 +++++++++
 .../gcc.target/powerpc/vec-ternarylogic-9.c   | 129 +++++++++
 19 files changed, 1616 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-0.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-10.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-2.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-3.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-4.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-5.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-6.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-7.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-8.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-9.c

diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
index 74319f13fa6..addf7d0db52 100644
--- a/gcc/config/rs6000/altivec.h
+++ b/gcc/config/rs6000/altivec.h
@@ -699,6 +699,7 @@ __altivec_scalar_pred(vec_any_nle,
 #define vec_gnb(a, b)	__builtin_vec_gnb (a, b)
 #define vec_clrl(a, b)	__builtin_vec_clrl (a, b)
 #define vec_clrr(a, b)	__builtin_vec_clrr (a, b)
+#define vec_ternarylogic(a, b, c, d)	__builtin_vec_xxeval (a, b, c, d)
 #endif
 
 #endif /* _ALTIVEC_H */
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 11d2dfe9426..7382d7c4b44 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -168,6 +168,7 @@ (define_c_enum "unspec"
    UNSPEC_VPEXTD
    UNSPEC_VCLRLB
    UNSPEC_VCLRRB
+   UNSPEC_XXEVAL
 ])
 
 (define_c_enum "unspecv"
@@ -3271,6 +3272,16 @@ (define_insn "vperm_v16qiv8hi"
   [(set_attr "type" "vecperm")
    (set_attr "isa" "*,p9v")])
 
+(define_insn "xxeval"
+  [(set (match_operand:V2DI 0 "register_operand" "=wa")
+	(unspec:V2DI [(match_operand:V2DI 1 "altivec_register_operand" "wa")
+		      (match_operand:V2DI 2 "altivec_register_operand" "wa")
+		      (match_operand:V2DI 3 "altivec_register_operand" "wa")
+		      (match_operand:QI 4 "u8bit_cint_operand" "n")]
+		     UNSPEC_XXEVAL))]
+   "TARGET_FUTURE"
+   "xxeval %0,%1,%2,%3,%4"
+   [(set_attr "type" "vecsimple")])
 
 (define_expand "vec_unpacku_hi_v16qi"
   [(set (match_operand:V8HI 0 "register_operand" "=v")
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index bf04e4d431f..c3f460face2 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -234,6 +234,11 @@ (define_predicate "u7bit_cint_operand"
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), 0, 127)")))
 
+;; Return 1 if op is a unsigned 8-bit constant integer.
+(define_predicate "u8bit_cint_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 255)")))
+
 ;; Return 1 if op is a signed 8-bit constant integer.
 ;; Integer multiplication complete more quickly
 (define_predicate "s8bit_cint_operand"
diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
index 4b06323a07f..7ff8db5dccc 100644
--- a/gcc/config/rs6000/rs6000-builtin.def
+++ b/gcc/config/rs6000/rs6000-builtin.def
@@ -28,6 +28,7 @@
    RS6000_BUILTIN_1 -- 1 arg builtins
    RS6000_BUILTIN_2 -- 2 arg builtins
    RS6000_BUILTIN_3 -- 3 arg builtins
+   RS6000_BUILTIN_4 -- 4 arg builtins
    RS6000_BUILTIN_A -- ABS builtins
    RS6000_BUILTIN_D -- DST builtins
    RS6000_BUILTIN_H -- HTM builtins
@@ -57,6 +58,10 @@
   #error "RS6000_BUILTIN_3 is not defined."
 #endif
 
+#ifndef RS6000_BUILTIN_4
+  #error "RS6000_BUILTIN_4 is not defined."
+#endif
+
 #ifndef RS6000_BUILTIN_A
   #error "RS6000_BUILTIN_A is not defined."
 #endif
@@ -969,6 +974,14 @@
 		     | RS6000_BTC_TERNARY),				\
 		    CODE_FOR_ ## ICODE)			/* ICODE */
 
+#define BU_FUTURE_V_4(ENUM, NAME, ATTR, ICODE)			\
+  RS6000_BUILTIN_4 (FUTURE_BUILTIN_ ## ENUM,		/* ENUM */	\
+		    "__builtin_altivec_" NAME,		/* NAME */	\
+		    RS6000_BTM_FUTURE,			/* MASK */	\
+		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
+		     | RS6000_BTC_QUATERNARY),				\
+		    CODE_FOR_ ## ICODE)			/* ICODE */
+
 #define BU_FUTURE_OVERLOAD_1(ENUM, NAME)				\
   RS6000_BUILTIN_1 (FUTURE_BUILTIN_VEC_ ## ENUM,	/* ENUM */	\
 		    "__builtin_vec_" NAME,		/* NAME */	\
@@ -993,6 +1006,14 @@
 		     | RS6000_BTC_TERNARY),				\
 		    CODE_FOR_nothing)			/* ICODE */
 
+#define BU_FUTURE_OVERLOAD_4(ENUM, NAME)				\
+  RS6000_BUILTIN_4 (FUTURE_BUILTIN_VEC_ ## ENUM,	/* ENUM */	\
+		    "__builtin_vec_" NAME,		/* NAME */	\
+		    RS6000_BTM_FUTURE,			/* MASK */	\
+		    (RS6000_BTC_OVERLOADED		/* ATTR */	\
+		     | RS6000_BTC_QUATERNARY),				\
+		    CODE_FOR_nothing)			/* ICODE */
+
 /* Miscellaneous (non-vector) builtins for instructions which may be
    added at some point in the future.  */
 
@@ -2589,11 +2610,13 @@ BU_FUTURE_V_2 (VCTZDM, "vctzdm", CONST, vctzdm)
 BU_FUTURE_V_2 (VPDEPD, "vpdepd", CONST, vpdepd)
 BU_FUTURE_V_2 (VPEXTD, "vpextd", CONST, vpextd)
 BU_FUTURE_V_2 (VGNB, "vgnb", CONST, vgnb)
+BU_FUTURE_V_4 (XXEVAL, "xxeval", CONST, xxeval)
 
 /* Future architecture overloaded vector built-ins.  */
 BU_FUTURE_OVERLOAD_2 (CLRL, "clrl")
 BU_FUTURE_OVERLOAD_2 (CLRR, "clrr")
 BU_FUTURE_OVERLOAD_2 (GNB, "gnb")
+BU_FUTURE_OVERLOAD_4 (XXEVAL, "xxeval")
 
 
 /* 1 argument crypto functions.  */
diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index ee2db96f2bd..cacaea00bd4 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -846,7 +846,7 @@ altivec_build_resolved_builtin (tree *args, int n,
   tree impl_fndecl = rs6000_builtin_decls[desc->overloaded_code];
   tree ret_type = rs6000_builtin_type (desc->ret_type);
   tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (impl_fndecl));
-  tree arg_type[3];
+  tree arg_type[4];
   tree call;
 
   int i;
@@ -895,6 +895,13 @@ altivec_build_resolved_builtin (tree *args, int n,
 			      fully_fold_convert (arg_type[1], args[1]),
 			      fully_fold_convert (arg_type[2], args[2]));
       break;
+    case 4:
+      call = build_call_expr (impl_fndecl, 4,
+			      fully_fold_convert (arg_type[0], args[0]),
+			      fully_fold_convert (arg_type[1], args[1]),
+			      fully_fold_convert (arg_type[2], args[2]),
+			      fully_fold_convert (arg_type[3], args[3]));
+      break;
     default:
       gcc_unreachable ();
     }
@@ -913,7 +920,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
   enum rs6000_builtins fcode
     = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
   tree fnargs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-  tree types[3], args[3];
+  tree types[4], args[4];
   const struct altivec_builtin_types *desc;
   unsigned int n;
 
@@ -1606,7 +1613,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
       if (arg == error_mark_node)
 	return error_mark_node;
 
-      if (n >= 3)
+      if (n >= 4)
         abort ();
 
       arg = default_conversion (arg);
@@ -1789,6 +1796,40 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
 	      unsupported_builtin = true;
 	  }
       }
+    else if (fcode == FUTURE_BUILTIN_VEC_XXEVAL)
+      {
+	/* Need to special case __builtin_vec_xxeval because this takes
+	   4 arguments, and the existing infrastructure handles no
+	   more than three.  */
+	if (nargs != 4)
+	  {
+	    error ("builtin %qs requires 4 arguments",
+		   "__builtin_vec_xxeval");
+	    return error_mark_node;
+	  }
+	for ( ; desc->code == fcode; desc++)
+	  {
+	    if (rs6000_builtin_type_compatible (types[0], desc->op1)
+		&& rs6000_builtin_type_compatible (types[1], desc->op2)
+		&& rs6000_builtin_type_compatible (types[2], desc->op3)
+		&& rs6000_builtin_type_compatible (types[3],
+						   RS6000_BTI_UINTQI))
+	      {
+		if (rs6000_builtin_decls[desc->overloaded_code] == NULL_TREE)
+		  unsupported_builtin = true;
+		else
+		  {
+		    result = altivec_build_resolved_builtin (args, n, desc);
+		    if (rs6000_builtin_is_supported_p (desc->overloaded_code))
+		      return result;
+		    /* Allow loop to continue in case a different
+		       definition is supported.  */
+		    overloaded_code = desc->overloaded_code;
+		    unsupported_builtin = true;
+		  }
+	      }
+	  }
+      }
     else
       {
 	/* For arguments after the last, we have RS6000_BTI_NOT_OPAQUE in
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 9da5b48463e..9b9562ce4c3 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -237,6 +237,7 @@ builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2)
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -255,6 +256,9 @@ builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)  \
   { NAME, ICODE, MASK, ATTR },
 
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)  \
   { NAME, ICODE, MASK, ATTR },
 
@@ -286,6 +290,7 @@ static const struct rs6000_builtin_info_type rs6000_builtin_info[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -5527,6 +5532,25 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = {
     RS6000_BTI_unsigned_V2DI, RS6000_BTI_UINTQI, 0 },
   { FUTURE_BUILTIN_VEC_GNB, FUTURE_BUILTIN_VGNB, RS6000_BTI_unsigned_long_long,
     RS6000_BTI_unsigned_V1TI, RS6000_BTI_UINTQI, 0 },
+
+  /* The overloaded XXEVAL definitions are handled specially because the
+     fourth unsigned char operand is not encoded in this table.  */
+  { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI },
+  { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL,
+    RS6000_BTI_unsigned_V8HI, RS6000_BTI_unsigned_V8HI,
+    RS6000_BTI_unsigned_V8HI, RS6000_BTI_unsigned_V8HI },
+  { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL,
+    RS6000_BTI_unsigned_V4SI, RS6000_BTI_unsigned_V4SI,
+    RS6000_BTI_unsigned_V4SI, RS6000_BTI_unsigned_V4SI },
+  { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL,
+    RS6000_BTI_unsigned_V2DI, RS6000_BTI_unsigned_V2DI,
+    RS6000_BTI_unsigned_V2DI, RS6000_BTI_unsigned_V2DI },
+  { FUTURE_BUILTIN_VEC_XXEVAL, FUTURE_BUILTIN_XXEVAL,
+    RS6000_BTI_unsigned_V1TI, RS6000_BTI_unsigned_V1TI,
+    RS6000_BTI_unsigned_V1TI, RS6000_BTI_unsigned_V1TI },
+
   { RS6000_BUILTIN_NONE, RS6000_BUILTIN_NONE, 0, 0, 0, 0 }
 };
 
@@ -8275,6 +8299,7 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code)
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8287,6 +8312,7 @@ def_builtin (const char *name, tree type, enum rs6000_builtins code)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) \
   { MASK, ICODE, NAME, ENUM },
 
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE)
@@ -8298,12 +8324,44 @@ static const struct builtin_description bdesc_3arg[] =
 #include "rs6000-builtin.def"
 };
 
+/* Simple quaternary operations: VECd = foo (VECa, VECb, VECc, VECd).  */
+
+#undef RS6000_BUILTIN_0
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_H
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_0(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
+static const struct builtin_description bdesc_4arg[] =
+{
+#include "rs6000-builtin.def"
+};
+
 /* DST operations: void foo (void *, const int, const char).  */
 
 #undef RS6000_BUILTIN_0
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8314,6 +8372,7 @@ static const struct builtin_description bdesc_3arg[] =
 #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) \
   { MASK, ICODE, NAME, ENUM },
@@ -8333,6 +8392,7 @@ static const struct builtin_description bdesc_dst[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8345,6 +8405,7 @@ static const struct builtin_description bdesc_dst[] =
   { MASK, ICODE, NAME, ENUM },
 
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE)
@@ -8360,6 +8421,7 @@ static const struct builtin_description bdesc_2arg[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8370,6 +8432,7 @@ static const struct builtin_description bdesc_2arg[] =
 #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE)
@@ -8391,6 +8454,7 @@ static const struct builtin_description bdesc_altivec_preds[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8401,6 +8465,7 @@ static const struct builtin_description bdesc_altivec_preds[] =
 #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) \
   { MASK, ICODE, NAME, ENUM },
 
@@ -8421,6 +8486,7 @@ static const struct builtin_description bdesc_abs[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8433,6 +8499,7 @@ static const struct builtin_description bdesc_abs[] =
 
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE)
@@ -8450,6 +8517,7 @@ static const struct builtin_description bdesc_1arg[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8462,6 +8530,7 @@ static const struct builtin_description bdesc_1arg[] =
 #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE)
@@ -8478,6 +8547,7 @@ static const struct builtin_description bdesc_0arg[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -8488,6 +8558,7 @@ static const struct builtin_description bdesc_0arg[] =
 #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) \
@@ -8505,6 +8576,7 @@ static const struct builtin_description bdesc_htm[] =
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -9404,6 +9476,8 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp)
 	      expected_nopnds = 2;
 	    else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_TERNARY)
 	      expected_nopnds = 3;
+	    else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_QUATERNARY)
+	      expected_nopnds = 4;
 	    if (!(attr & RS6000_BTC_VOID))
 	      expected_nopnds += 1;
 	    if (uses_spr)
@@ -9580,6 +9654,76 @@ cpu_expand_builtin (enum rs6000_builtins fcode, tree exp ATTRIBUTE_UNUSED,
   return target;
 }
 
+static rtx
+rs6000_expand_quaternop_builtin (enum insn_code icode, tree exp, rtx target)
+{
+  rtx pat;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  tree arg2 = CALL_EXPR_ARG (exp, 2);
+  tree arg3 = CALL_EXPR_ARG (exp, 3);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  rtx op2 = expand_normal (arg2);
+  rtx op3 = expand_normal (arg3);
+  machine_mode tmode = insn_data[icode].operand[0].mode;
+  machine_mode mode0 = insn_data[icode].operand[1].mode;
+  machine_mode mode1 = insn_data[icode].operand[2].mode;
+  machine_mode mode2 = insn_data[icode].operand[3].mode;
+  machine_mode mode3 = insn_data[icode].operand[4].mode;
+
+  if (icode == CODE_FOR_nothing)
+    /* Builtin not supported on this processor.  */
+    return 0;
+
+  /* If we got invalid arguments bail out before generating bad rtl.  */
+  if (arg0 == error_mark_node
+      || arg1 == error_mark_node
+      || arg2 == error_mark_node
+      || arg3 == error_mark_node)
+    return const0_rtx;
+
+  /* Check and prepare argument depending on the instruction code.
+
+     Note that a switch statement instead of the sequence of tests
+     would be incorrect as many of the CODE_FOR values could be
+     CODE_FOR_nothing and that would yield multiple alternatives
+     with identical values.  We'd never reach here at runtime in
+     this case.  */
+  if (icode == CODE_FOR_xxeval)
+    {
+      /* Only allow 8-bit unsigned literals.  */
+      STRIP_NOPS (arg3);
+      if (TREE_CODE (arg3) != INTEGER_CST
+	  || TREE_INT_CST_LOW (arg3) & ~0xff)
+	{
+	  error ("argument 4 must be an 8-bit unsigned literal");
+	  return CONST0_RTX (tmode);
+	}
+    }
+
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
+  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
+    op2 = copy_to_mode_reg (mode2, op2);
+  if (! (*insn_data[icode].operand[4].predicate) (op3, mode3))
+    op3 = copy_to_mode_reg (mode3, op3);
+
+  pat = GEN_FCN (icode) (target, op0, op1, op2, op3);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+
+  return target;
+}
+
 static rtx
 rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
 {
@@ -11613,6 +11757,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 	case RS6000_BTC_UNARY:	   name3 = "unary";	break;
 	case RS6000_BTC_BINARY:	   name3 = "binary";	break;
 	case RS6000_BTC_TERNARY:   name3 = "ternary";	break;
+	case RS6000_BTC_QUATERNARY:name3 = "quaternary";break;
 	case RS6000_BTC_PREDICATE: name3 = "predicate";	break;
 	case RS6000_BTC_ABS:	   name3 = "abs";	break;
 	case RS6000_BTC_DST:	   name3 = "dst";	break;
@@ -11795,6 +11940,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   gcc_assert (attr == RS6000_BTC_UNARY
 	      || attr == RS6000_BTC_BINARY
 	      || attr == RS6000_BTC_TERNARY
+	      || attr == RS6000_BTC_QUATERNARY
 	      || attr == RS6000_BTC_SPECIAL);
   
   /* Handle simple unary operations.  */
@@ -11815,6 +11961,12 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     if (d->code == fcode)
       return rs6000_expand_ternop_builtin (icode, exp, target);
 
+  /* Handle simple quaternary operations.  */
+  d = bdesc_4arg;
+  for (i = 0; i < ARRAY_SIZE  (bdesc_4arg); i++, d++)
+    if (d->code == fcode)
+      return rs6000_expand_quaternop_builtin (icode, exp, target);
+
   /* Handle simple no-argument operations. */
   d = bdesc_0arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
@@ -11969,7 +12121,9 @@ rs6000_init_builtins (void)
   /* Initialize the modes for builtin_function_type, mapping a machine mode to
      tree type node.  */
   builtin_mode_to_type[QImode][0] = integer_type_node;
+  builtin_mode_to_type[QImode][1] = unsigned_intSI_type_node;
   builtin_mode_to_type[HImode][0] = integer_type_node;
+  builtin_mode_to_type[HImode][1] = unsigned_intSI_type_node;
   builtin_mode_to_type[SImode][0] = intSI_type_node;
   builtin_mode_to_type[SImode][1] = unsigned_intSI_type_node;
   builtin_mode_to_type[DImode][0] = intDI_type_node;
@@ -12850,6 +13004,46 @@ htm_init_builtins (void)
     }
 }
 
+/* Map types for builtin functions with an explicit return type and
+   exactly 4 arguments.  Functions with fewer than 3 arguments use
+   builtin_function_type.  The number of quaternary built-in
+   functions is very small.  Handle each case specially.  */
+static tree
+builtin_quaternary_function_type (machine_mode mode_ret,
+				  machine_mode mode_arg0,
+				  machine_mode mode_arg1,
+				  machine_mode mode_arg2,
+				  machine_mode mode_arg3,
+				  enum rs6000_builtins builtin)
+{
+  tree function_type = NULL;
+
+  static tree v2udi_type = builtin_mode_to_type[V2DImode][1];
+  static tree uchar_type = builtin_mode_to_type[QImode][1];
+
+  static tree xxeval_type =
+    build_function_type_list (v2udi_type, v2udi_type, v2udi_type,
+			      v2udi_type, uchar_type, NULL_TREE);
+
+  switch (builtin) {
+
+  case FUTURE_BUILTIN_XXEVAL:
+    gcc_assert ((mode_ret == V2DImode)
+		&& (mode_arg0 == V2DImode)
+		&& (mode_arg1 == V2DImode)
+		&& (mode_arg2 == V2DImode)
+		&& (mode_arg3 == QImode));
+    function_type = xxeval_type;
+    break;
+
+  default:
+    /* A case for each quaternary built-in must be provided above.  */
+    gcc_unreachable ();
+  }
+
+  return function_type;
+}
+
 /* Map types for builtin functions with an explicit return type and up to 3
    arguments.  Functions with fewer than 3 arguments use VOIDmode as the type
    of the argument.  */
@@ -13145,6 +13339,63 @@ rs6000_common_init_builtins (void)
   if (TARGET_EXTRA_BUILTINS)
     builtin_mask |= RS6000_BTM_COMMON;
 
+  /* Add the quaternary operators.  */
+  d = bdesc_4arg;
+  for (i = 0; i < ARRAY_SIZE (bdesc_4arg); i++, d++)
+    {
+      tree type;
+      HOST_WIDE_INT mask = d->mask;
+
+      if ((mask & builtin_mask) != mask)
+	{
+	  if (TARGET_DEBUG_BUILTIN)
+	    fprintf (stderr, "rs6000_builtin, skip quaternary %s\n", d->name);
+	  continue;
+	}
+
+      if (rs6000_overloaded_builtin_p (d->code))
+	{
+	  type = opaque_ftype_opaque_opaque_opaque;
+	  if (!type)
+	    type = opaque_ftype_opaque_opaque_opaque
+	      = build_function_type_list (opaque_V4SI_type_node,
+					  opaque_V4SI_type_node,
+					  opaque_V4SI_type_node,
+					  opaque_V4SI_type_node,
+					  opaque_V4SI_type_node,
+					  NULL_TREE);
+	}
+      else
+	{
+	  enum insn_code icode = d->icode;
+	  if (d->name == 0)
+	    {
+	      if (TARGET_DEBUG_BUILTIN)
+		fprintf (stderr, "rs6000_builtin, bdesc_4arg[%ld] no name\n",
+			 (long) i);
+	      continue;
+	    }
+
+          if (icode == CODE_FOR_nothing)
+	    {
+	      if (TARGET_DEBUG_BUILTIN)
+		fprintf (stderr,
+			 "rs6000_builtin, skip quaternary %s (no code)\n",
+			 d->name);
+	      continue;
+	    }
+
+	  type =
+	    builtin_quaternary_function_type (insn_data[icode].operand[0].mode,
+					      insn_data[icode].operand[1].mode,
+					      insn_data[icode].operand[2].mode,
+					      insn_data[icode].operand[3].mode,
+					      insn_data[icode].operand[4].mode,
+					      d->code);
+	}
+      def_builtin (d->name, type, d->code);
+    }
+
   /* Add the ternary operators.  */
   d = bdesc_3arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 5603af994fa..1209a33173e 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -2254,9 +2254,14 @@ extern int frame_pointer_needed;
 #define RS6000_BTC_UNARY	0x00000001	/* normal unary function.  */
 #define RS6000_BTC_BINARY	0x00000002	/* normal binary function.  */
 #define RS6000_BTC_TERNARY	0x00000003	/* normal ternary function.  */
-#define RS6000_BTC_PREDICATE	0x00000004	/* predicate function.  */
-#define RS6000_BTC_ABS		0x00000005	/* Altivec/VSX ABS function.  */
+#define RS6000_BTC_QUATERNARY	0x00000004	/* normal quaternary
+						   function. */
+
+#define RS6000_BTC_PREDICATE	0x00000005	/* predicate function.  */
+#define RS6000_BTC_ABS		0x00000006	/* Altivec/VSX ABS
+						   function.  */
 #define RS6000_BTC_DST		0x00000007	/* Altivec DST function.  */
+
 #define RS6000_BTC_TYPE_MASK	0x0000000f	/* Mask to isolate types */
 
 #define RS6000_BTC_MISC		0x00000000	/* No special attributes.  */
@@ -2334,6 +2339,7 @@ extern int frame_pointer_needed;
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
@@ -2344,6 +2350,7 @@ extern int frame_pointer_needed;
 #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
 #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
 #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
+#define RS6000_BUILTIN_4(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
 #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
 #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
 #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) ENUM,
@@ -2361,6 +2368,7 @@ enum rs6000_builtins
 #undef RS6000_BUILTIN_1
 #undef RS6000_BUILTIN_2
 #undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_4
 #undef RS6000_BUILTIN_A
 #undef RS6000_BUILTIN_D
 #undef RS6000_BUILTIN_H
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9602a310cbb..c66a9ac7c3d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -22055,6 +22055,27 @@ else
 @end smallexample
 @end deftypefn
 
+@smallexample
+@exdent vector unsigned char
+@exdent vec_ternarylogic (vector unsigned char, vector unsigned char,
+            vector unsigned char, const unsigned char)
+@exdent vector unsigned short
+@exdent vec_ternarylogic (vector unsigned short, vector unsigned short,
+            vector unsigned short, const unsigned char)
+@exdent vector unsigned int
+@exdent vec_ternarylogic (vector unsigned int, vector unsigned int,
+            vector unsigned int, const unsigned char)
+@exdent vector unsigned long long int
+@exdent vec_ternarylogic (vector unsigned long long int, vector unsigned long long int,
+            vector unsigned long long int, const unsigned char)
+@exdent vector unsigned __int128
+@exdent vec_ternarylogic (vector unsigned __int128, vector unsigned __int128,
+            vector unsigned __int128, const unsigned char)
+@end smallexample
+Perform a 128-bit vector evaluate operation, as if implemented by the
+Future @code{xxeval} instruction.  The fourth argument must be a literal
+integer value between 0 and 255 inclusive.
+@findex vec_ternarylogic
 
 The following built-in functions are made available by @option{-mmmx}.
 All of them generate the machine instruction that is part of the name.
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-0.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-0.c
new file mode 100644
index 00000000000..bc1d05c008d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-0.c
@@ -0,0 +1,120 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned char a_sources [],
+		 vector unsigned char b_sources [],
+		 vector unsigned char c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned char a = a_sources [i];
+	  vector unsigned char b = b_sources [j];
+	  vector unsigned char c = c_sources [k];
+	  vector unsigned char result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned char intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11100101 (vector unsigned char a_sources [],
+		 vector unsigned char b_sources [],
+		 vector unsigned char c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned char a = a_sources [i];
+	  vector unsigned char b = b_sources [j];
+	  vector unsigned char c = c_sources [k];
+	  vector unsigned char result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned char intended =
+	    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 16; l++)
+	    {
+	      for (int m = 0; m < 8; m++)
+	      {
+		unsigned char bit_selector = (0x01 << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11110011 (vector unsigned char a_sources [],
+		 vector unsigned char b_sources [],
+		 vector unsigned char c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned char a = a_sources [i];
+	  vector unsigned char b = b_sources [j];
+	  vector unsigned char c = c_sources [k];
+	  vector unsigned char result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned char intended = {
+	    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	  for (int i = 0; i < 16; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vec_all_eq (result, intended))
+ 	    abort ();
+	}
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned char a_sources [NumSamples] = {
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+      0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+    { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+      0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69 },
+  };
+  vector unsigned char b_sources [NumSamples] = {
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+      0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+    { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+      0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69 },
+  };
+  vector unsigned char c_sources [NumSamples] = {
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+      0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+    { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+      0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-1.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-1.c
new file mode 100644
index 00000000000..8beb80fe60a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-1.c
@@ -0,0 +1,119 @@
+/* { dg-do run} */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned char a_sources [],
+		 vector unsigned char b_sources [],
+		 vector unsigned char c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned char a = a_sources [i];
+	  vector unsigned char b = b_sources [j];
+	  vector unsigned char c = c_sources [k];
+	  vector unsigned char result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned char intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11100101 (vector unsigned char a_sources [],
+		 vector unsigned char b_sources [],
+		 vector unsigned char c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned char a = a_sources [i];
+	  vector unsigned char b = b_sources [j];
+	  vector unsigned char c = c_sources [k];
+	  vector unsigned char result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned char intended =
+	    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 16; l++)
+	    {
+	      for (int m = 0; m < 8; m++)
+	      {
+		unsigned char bit_selector = (0x01 << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11110011 (vector unsigned char a_sources [],
+		 vector unsigned char b_sources [],
+		 vector unsigned char c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned char a = a_sources [i];
+	  vector unsigned char b = b_sources [j];
+	  vector unsigned char c = c_sources [k];
+	  vector unsigned char result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned char intended = {
+	    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	  for (int i = 0; i < 16; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned char a_sources [NumSamples] = {
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+      0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+    { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+      0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69 },
+  };
+  vector unsigned char b_sources [NumSamples] = {
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+      0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+    { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+      0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69 },
+  };
+  vector unsigned char c_sources [NumSamples] = {
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+      0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+    { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
+      0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-10.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-10.c
new file mode 100644
index 00000000000..868fb23c01b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-10.c
@@ -0,0 +1,129 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+/* vec_all_eq not yet supported for arguments of type
+   vector unsigned __int128.  */
+int
+vector_equal (vector unsigned __int128 a, vector unsigned __int128 b)
+{
+  return a[0] == b[0];
+}
+
+void
+doTests00000001 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result;
+	  result = vec_ternarylogic (a, b, c, 0xfff); /* { dg-error "8-bit unsigned literal" } */
+	  vector unsigned __int128 intended = (a & b & c);
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11100101 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result;
+	  result = vec_ternarylogic (a, b, c, -1); /* { dg-error "8-bit unsigned literal" } */
+	  vector unsigned __int128 intended = { 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 1; l++)
+	    {
+	      for (int m = 0; m < 128; m++)
+	      {
+		unsigned __int128 bit_selector = 0x01;
+		bit_selector = bit_selector << m;
+
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11110011 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result;
+	  result = vec_ternarylogic (a, b, c, i);  /* { dg-error "8-bit unsigned literal" } */
+	  vector unsigned __int128 intended = { 0 };
+	  for (int i = 0; i < 1; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, int *argv [])
+{
+  vector unsigned __int128 a_sources [NumSamples];
+  vector unsigned __int128 b_sources [NumSamples];
+  vector unsigned __int128 c_sources [NumSamples];
+
+  a_sources [0][0] = 0x0123456789abcdefull;
+  a_sources [0][0] = a_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  a_sources [1][0] = 0x5555555555555555ull;
+  a_sources [1][0] = a_sources [1][0] << 64 | 0xffffffffffffffffull;
+  a_sources [2][0] = 0xcccccccc55555555ull;
+  a_sources [2][0] = a_sources [2][0] << 64 | 0x0000000000000000ull;
+  a_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  a_sources [3][0] = a_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  b_sources [0][0] = 0x0123456789abcdefull;
+  b_sources [0][0] = b_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  b_sources [1][0] = 0x5555555555555555ull;
+  b_sources [1][0] = b_sources [1][0] << 64 | 0xffffffffffffffffull;
+  b_sources [2][0] = 0xcccccccc55555555ull;
+  b_sources [2][0] = b_sources [2][0] << 64 | 0x0000000000000000ull;
+  b_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  b_sources [3][0] = b_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  c_sources [0][0] = 0x0123456789abcdefull;
+  c_sources [0][0] = c_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  c_sources [1][0] = 0x5555555555555555ull;
+  c_sources [1][0] = c_sources [1][0] << 64 | 0xffffffffffffffffull;
+  c_sources [2][0] = 0xcccccccc55555555ull;
+  c_sources [2][0] = c_sources [2][0] << 64 | 0x0000000000000000ull;
+  c_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  c_sources [3][0] = c_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-2.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-2.c
new file mode 100644
index 00000000000..0d482b8e672
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-2.c
@@ -0,0 +1,105 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned short int a_sources [],
+		 vector unsigned short int b_sources [],
+		 vector unsigned short int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned short a = a_sources [i];
+	  vector unsigned short b = b_sources [j];
+	  vector unsigned short c = c_sources [k];
+	  vector unsigned short result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned short intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11100101 (vector unsigned short int a_sources [],
+		      vector unsigned short int b_sources [],
+		      vector unsigned short int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned short a = a_sources [i];
+	  vector unsigned short b = b_sources [j];
+	  vector unsigned short c = c_sources [k];
+	  vector unsigned short result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned short intended =
+	    { 0, 0, 0, 0, 0, 0, 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 8; l++)
+	    {
+	      for (int m = 0; m < 16; m++)
+	      {
+		unsigned short int bit_selector = (0x01 << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11110011 (vector unsigned short int a_sources [],
+		      vector unsigned short int b_sources [],
+		      vector unsigned short int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned short a = a_sources [i];
+	  vector unsigned short b = b_sources [j];
+	  vector unsigned short c = c_sources [k];
+	  vector unsigned short result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned short intended = { 0, 0, 0, 0, 0, 0, 0, 0 };
+	  for (int i = 0; i < 8; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, short *argv [])
+{
+  vector unsigned short int a_sources [NumSamples] = {
+    { 0x0123, 0x4567, 0x89ab, 0xcdef, 0x1234, 0x5678, 0x9abc, 0xdef0 },
+    { 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff },
+    { 0xcccc, 0xcccc, 0x5555, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000 },
+    { 0xe7e7, 0xe7e7, 0xe7e7, 0xe7e7, 0x6969, 0x6969, 0x6969, 0x6969 },
+  };
+  vector unsigned short int b_sources [NumSamples] = {
+    { 0x0123, 0x4567, 0x89ab, 0xcdef, 0x1234, 0x5678, 0x9abc, 0xdef0 },
+    { 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff },
+    { 0xcccc, 0xcccc, 0x5555, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000 },
+    { 0xe7e7, 0xe7e7, 0xe7e7, 0xe7e7, 0x6969, 0x6969, 0x6969, 0x6969 },
+  };
+  vector unsigned short int c_sources [NumSamples] = {
+    { 0x0123, 0x4567, 0x89ab, 0xcdef, 0x1234, 0x5678, 0x9abc, 0xdef0 },
+    { 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff },
+    { 0xcccc, 0xcccc, 0x5555, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000 },
+    { 0xe7e7, 0xe7e7, 0xe7e7, 0xe7e7, 0x6969, 0x6969, 0x6969, 0x6969 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-3.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-3.c
new file mode 100644
index 00000000000..a7245e51da2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-3.c
@@ -0,0 +1,106 @@
+/* { dg-do run } */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned short int a_sources [],
+		 vector unsigned short int b_sources [],
+		 vector unsigned short int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned short a = a_sources [i];
+	  vector unsigned short b = b_sources [j];
+	  vector unsigned short c = c_sources [k];
+	  vector unsigned short result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned short intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11100101 (vector unsigned short int a_sources [],
+		      vector unsigned short int b_sources [],
+		      vector unsigned short int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned short a = a_sources [i];
+	  vector unsigned short b = b_sources [j];
+	  vector unsigned short c = c_sources [k];
+	  vector unsigned short result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned short intended =
+	    { 0, 0, 0, 0, 0, 0, 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 8; l++)
+	    {
+	      for (int m = 0; m < 16; m++)
+	      {
+		unsigned short int bit_selector = (0x01 << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11110011 (vector unsigned short int a_sources [],
+		      vector unsigned short int b_sources [],
+		      vector unsigned short int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned short a = a_sources [i];
+	  vector unsigned short b = b_sources [j];
+	  vector unsigned short c = c_sources [k];
+	  vector unsigned short result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned short intended = { 0, 0, 0, 0, 0, 0, 0, 0 };
+	  for (int i = 0; i < 8; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, short *argv [])
+{
+  vector unsigned short int a_sources [NumSamples] = {
+    { 0x0123, 0x4567, 0x89ab, 0xcdef, 0x1234, 0x5678, 0x9abc, 0xdef0 },
+    { 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff },
+    { 0xcccc, 0xcccc, 0x5555, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000 },
+    { 0xe7e7, 0xe7e7, 0xe7e7, 0xe7e7, 0x6969, 0x6969, 0x6969, 0x6969 },
+  };
+  vector unsigned short int b_sources [NumSamples] = {
+    { 0x0123, 0x4567, 0x89ab, 0xcdef, 0x1234, 0x5678, 0x9abc, 0xdef0 },
+    { 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff },
+    { 0xcccc, 0xcccc, 0x5555, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000 },
+    { 0xe7e7, 0xe7e7, 0xe7e7, 0xe7e7, 0x6969, 0x6969, 0x6969, 0x6969 },
+  };
+  vector unsigned short int c_sources [NumSamples] = {
+    { 0x0123, 0x4567, 0x89ab, 0xcdef, 0x1234, 0x5678, 0x9abc, 0xdef0 },
+    { 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff },
+    { 0xcccc, 0xcccc, 0x5555, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000 },
+    { 0xe7e7, 0xe7e7, 0xe7e7, 0xe7e7, 0x6969, 0x6969, 0x6969, 0x6969 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-4.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-4.c
new file mode 100644
index 00000000000..dbd9ffb856e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-4.c
@@ -0,0 +1,104 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned int a_sources [],
+		 vector unsigned int b_sources [],
+		 vector unsigned int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned int a = a_sources [i];
+	  vector unsigned int b = b_sources [j];
+	  vector unsigned int c = c_sources [k];
+	  vector unsigned int result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned int intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11100101 (vector unsigned int a_sources [],
+		      vector unsigned int b_sources [],
+		      vector unsigned int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned int a = a_sources [i];
+	  vector unsigned int b = b_sources [j];
+	  vector unsigned int c = c_sources [k];
+	  vector unsigned int result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned int intended = { 0, 0, 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 4; l++)
+	    {
+	      for (int m = 0; m < 32; m++)
+	      {
+		unsigned int bit_selector = (0x01 << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11110011 (vector unsigned int a_sources [],
+		      vector unsigned int b_sources [],
+		      vector unsigned int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned int a = a_sources [i];
+	  vector unsigned int b = b_sources [j];
+	  vector unsigned int c = c_sources [k];
+	  vector unsigned int result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned int intended = { 0, 0, 0, 0 };
+	  for (int i = 0; i < 4; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, int *argv [])
+{
+  vector unsigned int a_sources [NumSamples] = {
+    { 0x01234567, 0x89abcdef, 0x12345678, 0x9abcdef0 },
+    { 0x55555555, 0x55555555, 0xffffffff, 0xffffffff },
+    { 0xcccccccc, 0x55555555, 0x00000000, 0x00000000 },
+    { 0xe7e7e7e7, 0xe7e7e7e7, 0x69696969, 0x69696969 },
+  };
+  vector unsigned int b_sources [NumSamples] = {
+    { 0x01234567, 0x89abcdef, 0x12345678, 0x9abcdef0 },
+    { 0x55555555, 0x55555555, 0xffffffff, 0xffffffff },
+    { 0xcccccccc, 0x55555555, 0x00000000, 0x00000000 },
+    { 0xe7e7e7e7, 0xe7e7e7e7, 0x69696969, 0x69696969 },
+  };
+  vector unsigned int c_sources [NumSamples] = {
+    { 0x01234567, 0x89abcdef, 0x12345678, 0x9abcdef0 },
+    { 0x55555555, 0x55555555, 0xffffffff, 0xffffffff },
+    { 0xcccccccc, 0x55555555, 0x00000000, 0x00000000 },
+    { 0xe7e7e7e7, 0xe7e7e7e7, 0x69696969, 0x69696969 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-5.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-5.c
new file mode 100644
index 00000000000..4d5d8e5e0d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-5.c
@@ -0,0 +1,103 @@
+/* { dg-do run } */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned int a_sources [],
+		 vector unsigned int b_sources [],
+		 vector unsigned int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned int a = a_sources [i];
+	  vector unsigned int b = b_sources [j];
+	  vector unsigned int c = c_sources [k];
+	  vector unsigned int result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned int intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11100101 (vector unsigned int a_sources [],
+		      vector unsigned int b_sources [],
+		      vector unsigned int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned int a = a_sources [i];
+	  vector unsigned int b = b_sources [j];
+	  vector unsigned int c = c_sources [k];
+	  vector unsigned int result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned int intended = { 0, 0, 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 4; l++)
+	    {
+	      for (int m = 0; m < 32; m++)
+	      {
+		unsigned int bit_selector = (0x01 << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11110011 (vector unsigned int a_sources [],
+		      vector unsigned int b_sources [],
+		      vector unsigned int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned int a = a_sources [i];
+	  vector unsigned int b = b_sources [j];
+	  vector unsigned int c = c_sources [k];
+	  vector unsigned int result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned int intended = { 0, 0, 0, 0 };
+	  for (int i = 0; i < 4; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, int *argv [])
+{
+  vector unsigned int a_sources [NumSamples] = {
+    { 0x01234567, 0x89abcdef, 0x12345678, 0x9abcdef0 },
+    { 0x55555555, 0x55555555, 0xffffffff, 0xffffffff },
+    { 0xcccccccc, 0x55555555, 0x00000000, 0x00000000 },
+    { 0xe7e7e7e7, 0xe7e7e7e7, 0x69696969, 0x69696969 },
+  };
+  vector unsigned int b_sources [NumSamples] = {
+    { 0x01234567, 0x89abcdef, 0x12345678, 0x9abcdef0 },
+    { 0x55555555, 0x55555555, 0xffffffff, 0xffffffff },
+    { 0xcccccccc, 0x55555555, 0x00000000, 0x00000000 },
+    { 0xe7e7e7e7, 0xe7e7e7e7, 0x69696969, 0x69696969 },
+  };
+  vector unsigned int c_sources [NumSamples] = {
+    { 0x01234567, 0x89abcdef, 0x12345678, 0x9abcdef0 },
+    { 0x55555555, 0x55555555, 0xffffffff, 0xffffffff },
+    { 0xcccccccc, 0x55555555, 0x00000000, 0x00000000 },
+    { 0xe7e7e7e7, 0xe7e7e7e7, 0x69696969, 0x69696969 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-6.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-6.c
new file mode 100644
index 00000000000..0114bacd5fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-6.c
@@ -0,0 +1,104 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned long long int a_sources [],
+		 vector unsigned long long int b_sources [],
+		 vector unsigned long long int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned long long a = a_sources [i];
+	  vector unsigned long long b = b_sources [j];
+	  vector unsigned long long c = c_sources [k];
+	  vector unsigned long long result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned long long intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11100101 (vector unsigned long long int a_sources [],
+		      vector unsigned long long int b_sources [],
+		      vector unsigned long long int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned long long a = a_sources [i];
+	  vector unsigned long long b = b_sources [j];
+	  vector unsigned long long c = c_sources [k];
+	  vector unsigned long long result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned long long intended = { 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 2; l++)
+	    {
+	      for (int m = 0; m < 64; m++)
+	      {
+		unsigned long long int bit_selector = (0x01ll << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= (0x01ll << m);
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11110011 (vector unsigned long long int a_sources [],
+		      vector unsigned long long int b_sources [],
+		      vector unsigned long long int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned long long a = a_sources [i];
+	  vector unsigned long long b = b_sources [j];
+	  vector unsigned long long c = c_sources [k];
+	  vector unsigned long long result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned long long intended = { 0, 0 };
+	  intended [0] = b [0] | ~(a [0] & c [0]);
+	  intended [1] = b [1] | ~(a [1] & c [1]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned long long int a_sources [NumSamples] = {
+    { 0x0123456789abcdef, 0x123456789abcdef0 },
+    { 0x5555555555555555, 0xffffffffffffffff },
+    { 0xcccccccc55555555, 0x0000000000000000 },
+    { 0xe7e7e7e7e7e7e7e7, 0x6969696969696969 },
+  };
+  vector unsigned long long int b_sources [NumSamples] = {
+    { 0x0123456789abcdef, 0x123456789abcdef0 },
+    { 0x5555555555555555, 0xffffffffffffffff },
+    { 0xcccccccc55555555, 0x0000000000000000 },
+    { 0xe7e7e7e7e7e7e7e7, 0x6969696969696969 },
+  };
+  vector unsigned long long int c_sources [NumSamples] = {
+    { 0x0123456789abcdef, 0x123456789abcdef0 },
+    { 0x5555555555555555, 0xffffffffffffffff },
+    { 0xcccccccc55555555, 0x0000000000000000 },
+    { 0xe7e7e7e7e7e7e7e7, 0x6969696969696969 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-7.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-7.c
new file mode 100644
index 00000000000..27ac4a22866
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-7.c
@@ -0,0 +1,103 @@
+/* { dg-do run } */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+void
+doTests00000001 (vector unsigned long long int a_sources [],
+		 vector unsigned long long int b_sources [],
+		 vector unsigned long long int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned long long a = a_sources [i];
+	  vector unsigned long long b = b_sources [j];
+	  vector unsigned long long c = c_sources [k];
+	  vector unsigned long long result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned long long intended = (a & b & c);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11100101 (vector unsigned long long int a_sources [],
+		      vector unsigned long long int b_sources [],
+		      vector unsigned long long int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned long long a = a_sources [i];
+	  vector unsigned long long b = b_sources [j];
+	  vector unsigned long long c = c_sources [k];
+	  vector unsigned long long result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned long long intended = { 0, 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 2; l++)
+	    {
+	      for (int m = 0; m < 64; m++)
+	      {
+		unsigned long long int bit_selector = (0x01ll << m);
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= (0x01ll << m);
+	      }
+	    }
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+void doTests11110011 (vector unsigned long long int a_sources [],
+		      vector unsigned long long int b_sources [],
+		      vector unsigned long long int c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned long long a = a_sources [i];
+	  vector unsigned long long b = b_sources [j];
+	  vector unsigned long long c = c_sources [k];
+	  vector unsigned long long result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned long long intended = { 0, 0 };
+	  intended [0] = b [0] | ~(a [0] & c [0]);
+	  intended [1] = b [1] | ~(a [1] & c [1]);
+	  if (!vec_all_eq (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned long long int a_sources [NumSamples] = {
+    { 0x0123456789abcdef, 0x123456789abcdef0 },
+    { 0x5555555555555555, 0xffffffffffffffff },
+    { 0xcccccccc55555555, 0x0000000000000000 },
+    { 0xe7e7e7e7e7e7e7e7, 0x6969696969696969 },
+  };
+  vector unsigned long long int b_sources [NumSamples] = {
+    { 0x0123456789abcdef, 0x123456789abcdef0 },
+    { 0x5555555555555555, 0xffffffffffffffff },
+    { 0xcccccccc55555555, 0x0000000000000000 },
+    { 0xe7e7e7e7e7e7e7e7, 0x6969696969696969 },
+  };
+  vector unsigned long long int c_sources [NumSamples] = {
+    { 0x0123456789abcdef, 0x123456789abcdef0 },
+    { 0x5555555555555555, 0xffffffffffffffff },
+    { 0xcccccccc55555555, 0x0000000000000000 },
+    { 0xe7e7e7e7e7e7e7e7, 0x6969696969696969 },
+  };
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-8.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-8.c
new file mode 100644
index 00000000000..0d6b9e74239
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-8.c
@@ -0,0 +1,128 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+/* vec_all_eq not yet supported for arguments of type
+   vector unsigned __int128.  */
+int
+vector_equal (vector unsigned __int128 a, vector unsigned __int128 b)
+{
+  return a[0] == b[0];
+}
+
+void
+doTests00000001 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned __int128 intended = (a & b & c);
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11100101 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned __int128 intended = { 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 1; l++)
+	    {
+	      for (int m = 0; m < 128; m++)
+	      {
+		unsigned __int128 bit_selector = 0x01;
+		bit_selector = bit_selector << m;
+
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11110011 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned __int128 intended = { 0 };
+	  for (int i = 0; i < 1; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, int *argv [])
+{
+  vector unsigned __int128 a_sources [NumSamples];
+  vector unsigned __int128 b_sources [NumSamples];
+  vector unsigned __int128 c_sources [NumSamples];
+
+  a_sources [0][0] = 0x0123456789abcdefull;
+  a_sources [0][0] = a_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  a_sources [1][0] = 0x5555555555555555ull;
+  a_sources [1][0] = a_sources [1][0] << 64 | 0xffffffffffffffffull;
+  a_sources [2][0] = 0xcccccccc55555555ull;
+  a_sources [2][0] = a_sources [2][0] << 64 | 0x0000000000000000ull;
+  a_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  a_sources [3][0] = a_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  b_sources [0][0] = 0x0123456789abcdefull;
+  b_sources [0][0] = b_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  b_sources [1][0] = 0x5555555555555555ull;
+  b_sources [1][0] = b_sources [1][0] << 64 | 0xffffffffffffffffull;
+  b_sources [2][0] = 0xcccccccc55555555ull;
+  b_sources [2][0] = b_sources [2][0] << 64 | 0x0000000000000000ull;
+  b_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  b_sources [3][0] = b_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  c_sources [0][0] = 0x0123456789abcdefull;
+  c_sources [0][0] = c_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  c_sources [1][0] = 0x5555555555555555ull;
+  c_sources [1][0] = c_sources [1][0] << 64 | 0xffffffffffffffffull;
+  c_sources [2][0] = 0xcccccccc55555555ull;
+  c_sources [2][0] = c_sources [2][0] << 64 | 0x0000000000000000ull;
+  c_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  c_sources [3][0] = c_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-9.c b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-9.c
new file mode 100644
index 00000000000..b6113596867
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vec-ternarylogic-9.c
@@ -0,0 +1,129 @@
+/* { dg-do run } */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+#define NumSamples 4
+
+/* vec_all_eq not yet supported for arguments of type
+   vector unsigned __int128.  */
+int
+vector_equal (vector unsigned __int128 a, vector unsigned __int128 b)
+{
+  return a[0] == b[0];
+}
+
+void
+doTests00000001 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result = vec_ternarylogic (a, b, c, 0x01);
+	  vector unsigned __int128 intended = (a & b & c);
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11100101 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result = vec_ternarylogic (a, b, c, 0xe5);
+	  vector unsigned __int128 intended = { 0 };
+	  // Supposed to be a ? c: nand (b,c)
+	  for (int l = 0; l < 1; l++)
+	    {
+	      for (int m = 0; m < 128; m++)
+	      {
+		unsigned __int128 bit_selector = 0x01;
+		bit_selector = bit_selector << m;
+
+		if (a[l] & bit_selector)
+		  intended [l] |= c [l] & bit_selector;
+		else if ((b [l] & c [l] & bit_selector) == 0)
+		  intended [l] |= bit_selector;
+	      }
+	    }
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+void
+doTests11110011 (vector unsigned __int128 a_sources [],
+		 vector unsigned __int128 b_sources [],
+		 vector unsigned __int128 c_sources []) {
+  for (int i = 0; i < NumSamples; i++)
+    for (int j = 0; j < NumSamples; j++)
+      for (int k = 0; k < NumSamples; k++)
+	{
+	  vector unsigned __int128 a = a_sources [i];
+	  vector unsigned __int128 b = b_sources [j];
+	  vector unsigned __int128 c = c_sources [k];
+	  vector unsigned __int128 result = vec_ternarylogic (a, b, c, 0xfb);
+	  vector unsigned __int128 intended = { 0 };
+	  for (int i = 0; i < 1; i++)
+	    intended [i] = b [i] | ~(a [i] & c [i]);
+	  if (!vector_equal (result, intended))
+	    abort ();
+	}
+}
+
+int main (int argc, int *argv [])
+{
+  vector unsigned __int128 a_sources [NumSamples];
+  vector unsigned __int128 b_sources [NumSamples];
+  vector unsigned __int128 c_sources [NumSamples];
+
+  a_sources [0][0] = 0x0123456789abcdefull;
+  a_sources [0][0] = a_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  a_sources [1][0] = 0x5555555555555555ull;
+  a_sources [1][0] = a_sources [1][0] << 64 | 0xffffffffffffffffull;
+  a_sources [2][0] = 0xcccccccc55555555ull;
+  a_sources [2][0] = a_sources [2][0] << 64 | 0x0000000000000000ull;
+  a_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  a_sources [3][0] = a_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  b_sources [0][0] = 0x0123456789abcdefull;
+  b_sources [0][0] = b_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  b_sources [1][0] = 0x5555555555555555ull;
+  b_sources [1][0] = b_sources [1][0] << 64 | 0xffffffffffffffffull;
+  b_sources [2][0] = 0xcccccccc55555555ull;
+  b_sources [2][0] = b_sources [2][0] << 64 | 0x0000000000000000ull;
+  b_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  b_sources [3][0] = b_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  c_sources [0][0] = 0x0123456789abcdefull;
+  c_sources [0][0] = c_sources [0][0] << 64 | 0x123456789abcdef0ull;
+  c_sources [1][0] = 0x5555555555555555ull;
+  c_sources [1][0] = c_sources [1][0] << 64 | 0xffffffffffffffffull;
+  c_sources [2][0] = 0xcccccccc55555555ull;
+  c_sources [2][0] = c_sources [2][0] << 64 | 0x0000000000000000ull;
+  c_sources [3][0] = 0xe7e7e7e7e7e7e7e7ull;
+  c_sources [3][0] = c_sources [3][0] << 64 | 0x6969696969696969ull;
+
+  doTests00000001 (a_sources, b_sources, c_sources);
+  doTests11100101 (a_sources, b_sources, c_sources);
+  doTests11110011 (a_sources, b_sources, c_sources);
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mxxeval\M} } } */
-- 
2.17.1



More information about the Gcc-patches mailing list