diff mbox series

rs6000: Add xxeval and vec_ternarylogic

Message ID 20200509011322.35014-1-wschmidt@linux.ibm.com
State New
Headers show
Series rs6000: Add xxeval and vec_ternarylogic | expand

Commit Message

Bill Schmidt May 9, 2020, 1:13 a.m. UTC
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

Comments

David Edelsohn May 9, 2020, 5:15 p.m. UTC | #1
On Fri, May 8, 2020 at 9:13 PM Bill Schmidt <wschmidt@linux.ibm.com> wrote:
>
> 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.

The above two should be altivec.md

>         * 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.

I would add "Use it".

>         (BU_FUTURE_OVERLOAD_4): Likewise.

I would add "Use it".

>         * 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.

Inserting this value doesn't seem completely safe, but I guess that it works.

>         (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.

Okay with those changes, plus any issues noticed by Segher.

Thanks, David

> ---
>  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
>
Segher Boessenkool May 11, 2020, 10:50 a.m. UTC | #2
Hi!

On Sat, May 09, 2020 at 01:15:44PM -0400, David Edelsohn wrote:
> Okay with those changes, plus any issues noticed by Segher.

The only thing I can add is, I hope Bill's builtin work will make it
unnecessary to also define QUINARY and SENARY macros (yes I looked it
up), before we need those :-)

Thanks!


Segher
diff mbox series

Patch

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} } } */