Hi All,
The following changes have been bootstrapped and regression tested on
powerpc64le-linux. Is this okay for trunk?
Changes from V2:
* Added TARGET_VSX check to all new insn patterns.
* Added * prefix to vsx_mul pattern.
* Added new test cases vsx_simd-3.c and vsx_simd-4.c.
* Created new future-vsx stanza to map builtins.
Changes from V1:
* Incorporated wording suggestions.
* Renamed mode iterators to VIMulH and VIArith for better clarity.
* Removed extra blank line in vsx_simd-*.c test case.
* Replaced unspec with proper smul_highpart and umul_highpart RTL
codes for multiply-high patterns.
* Added * prefix to internal patterns for vsx_add, vsx_sub, altivec_add,
altivec_sub, altivec_smul and altivec_umul.
* Updated extend.texi.
This patch adds support for VSX vector arithmetic instructions that may
be added to future PowerPC processors. Note that the names of these
builtins may change in the future.
New VSX patterns are added for vector add, subtract, multiply, and
multiply-high instructions guarded by TARGET_FUTURE. Existing Altivec
patterns are renamed to altivec_* to avoid name conflicts.
2026-05-19 Jeevitha Palanisamy <[email protected]>
gcc/
* config/rs6000/altivec.md (*vsx_add<mode>3): New insn pattern.
(*altivec_add<mode>3): Renamed from add<mode>3.
(*vsx_sub<mode>3): New insn pattern.
(*altivec_sub<mode>3): Renamed from sub<mode>3.
* config/rs6000/vector.md (VIMulH): New mode iterator.
(add<mode>3): New expand pattern.
(sub<mode>3): Likewise.
(smul<mode>3_highpart): Likewise.
(umul<mode>3_highpart): Likewise.
* config/rs6000/vsx.md (VIArith): New mode iterator.
(*vsx_mul<mode>3): New insn pattern.
(vsx_smul<mode>3_highpart): Likewise.
(vsx_umul<mode>3_highpart): Likewise.
(*altivec_smul<mode>3_highpart): Renamed from smul<mode>3_highpart.
(*altivec_umul<mode>3_highpart): Renamed from umul<mode>3_highpart.
* config/rs6000/rs6000-builtins.def (__builtin_vsx_xvmulhuh): New
builtin.
(__builtin_vsx_xvmulhsh): Likewise.
* config/rs6000/rs6000-overload.def (__builtin_vec_mulh): Add
overloads for vector multiply-high signed/unsigned halfword.
* config/rs6000/rs6000-gen-builtins.cc (enum bif_stanza): Add entry
for BSTZ_FUTUREV.
(stanza_map): Add future-vsx stanza mapping.
(enable_string): Add ENB_FUTUREV.
(write_decls): Add ENB_FUTUREV to the bif_enable enum in the generated
header file.
* config/rs6000/rs6000-builtin.cc (rs6000_invalid_builtin): Handle
ENB_FUTUREV and issue a diagnostic requiring -mcpu=future and -mvsx.
(rs6000_builtin_is_supported): Return TARGET_FUTURE && TARGET_VSX for
ENB_FUTUREV built-ins.
* doc/extend.texi (PowerPC AltiVec/VSX Built-in Functions Available
on Future ISA): Document new functions.
gcc/testsuite/
* gcc.target/powerpc/vsx_simd-1.c: New test.
* gcc.target/powerpc/vsx_simd-2.c: Likewise.
* gcc.target/powerpc/vsx_simd-3.c: Likewise.
* gcc.target/powerpc/vsx_simd-4.c: Likewise.
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 129f56245cd..3bdc22d5f9e 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -503,11 +503,18 @@
;; Simple binary operations.
+(define_insn "*vsx_add<mode>3"
+ [(set (match_operand:VIArith 0 "vsx_register_operand" "=wa")
+ (plus:VIArith (match_operand:VIArith 1 "vsx_register_operand" "wa")
+ (match_operand:VIArith 2 "vsx_register_operand" "wa")))]
+ "TARGET_FUTURE && TARGET_VSX"
+ "xvaddu<VI_char>m %x0,%x1,%x2")
+
;; add
-(define_insn "add<mode>3"
- [(set (match_operand:VI2 0 "register_operand" "=v")
- (plus:VI2 (match_operand:VI2 1 "register_operand" "v")
- (match_operand:VI2 2 "register_operand" "v")))]
+(define_insn "*altivec_add<mode>3"
+ [(set (match_operand:VEC_I 0 "register_operand" "=v")
+ (plus:VEC_I (match_operand:VEC_I 1 "register_operand" "v")
+ (match_operand:VEC_I 2 "register_operand" "v")))]
"<VI_unit>"
"vaddu<VI_char>m %0,%1,%2"
[(set_attr "type" "vecsimple")])
@@ -547,11 +554,18 @@
"vadds<VI_char>s %0,%1,%2"
[(set_attr "type" "vecsimple")])
+(define_insn "*vsx_sub<mode>3"
+ [(set (match_operand:VIArith 0 "vsx_register_operand" "=wa")
+ (minus:VIArith (match_operand:VIArith 1 "vsx_register_operand" "wa")
+ (match_operand:VIArith 2 "vsx_register_operand" "wa")))]
+ "TARGET_FUTURE && TARGET_VSX"
+ "xvsubu<VI_char>m %x0,%x1,%x2")
+
;; sub
-(define_insn "sub<mode>3"
- [(set (match_operand:VI2 0 "register_operand" "=v")
- (minus:VI2 (match_operand:VI2 1 "register_operand" "v")
- (match_operand:VI2 2 "register_operand" "v")))]
+(define_insn "*altivec_sub<mode>3"
+ [(set (match_operand:VEC_I 0 "register_operand" "=v")
+ (minus:VEC_I (match_operand:VEC_I 1 "register_operand" "v")
+ (match_operand:VEC_I 2 "register_operand" "v")))]
"<VI_unit>"
"vsubu<VI_char>m %0,%1,%2"
[(set_attr "type" "vecsimple")])
diff --git a/gcc/config/rs6000/rs6000-builtin.cc
b/gcc/config/rs6000/rs6000-builtin.cc
index 4d0e541351f..94f0c9d8ab8 100644
--- a/gcc/config/rs6000/rs6000-builtin.cc
+++ b/gcc/config/rs6000/rs6000-builtin.cc
@@ -142,6 +142,10 @@ rs6000_invalid_builtin (enum rs6000_gen_builtins fncode)
case ENB_FUTURE:
error ("%qs requires the %qs option", name, "-mcpu=future");
break;
+ case ENB_FUTUREV:
+ error ("%qs requires the %qs and %qs options", name, "-mcpu=future",
+ "-mvsx");
+ break;
default:
case ENB_ALWAYS:
gcc_unreachable ();
@@ -199,6 +203,8 @@ rs6000_builtin_is_supported (enum rs6000_gen_builtins
fncode)
return TARGET_MMA;
case ENB_FUTURE:
return TARGET_FUTURE;
+ case ENB_FUTUREV:
+ return TARGET_FUTURE && TARGET_VSX;
default:
gcc_unreachable ();
}
diff --git a/gcc/config/rs6000/rs6000-builtins.def
b/gcc/config/rs6000/rs6000-builtins.def
index 0d1529b71d4..0e7553eb196 100644
--- a/gcc/config/rs6000/rs6000-builtins.def
+++ b/gcc/config/rs6000/rs6000-builtins.def
@@ -3970,3 +3970,10 @@
const vuc __builtin_galois_field_mult_xts (vuc, vuc);
XXGFMUL128XTS xxgfmul128xts {}
+
+[future-vsx]
+ const vus __builtin_vsx_xvmulhuh (vus, vus);
+ XVMULHUH vsx_umulv8hi3_highpart {}
+
+ const vss __builtin_vsx_xvmulhsh (vss, vss);
+ XVMULHSH vsx_smulv8hi3_highpart {}
diff --git a/gcc/config/rs6000/rs6000-gen-builtins.cc
b/gcc/config/rs6000/rs6000-gen-builtins.cc
index 7436404cff5..035b63f08a0 100644
--- a/gcc/config/rs6000/rs6000-gen-builtins.cc
+++ b/gcc/config/rs6000/rs6000-gen-builtins.cc
@@ -233,6 +233,7 @@ enum bif_stanza
BSTZ_P10_64,
BSTZ_MMA,
BSTZ_FUTURE,
+ BSTZ_FUTUREV,
NUMBIFSTANZAS
};
@@ -267,7 +268,8 @@ static stanza_entry stanza_map[NUMBIFSTANZAS] =
{ "power10", BSTZ_P10 },
{ "power10-64", BSTZ_P10_64 },
{ "mma", BSTZ_MMA },
- { "future", BSTZ_FUTURE }
+ { "future", BSTZ_FUTURE },
+ { "future-vsx", BSTZ_FUTUREV }
};
static const char *enable_string[NUMBIFSTANZAS] =
@@ -293,7 +295,8 @@ static const char *enable_string[NUMBIFSTANZAS] =
"ENB_P10",
"ENB_P10_64",
"ENB_MMA",
- "ENB_FUTURE"
+ "ENB_FUTURE",
+ "ENB_FUTUREV"
};
/* Function modifiers provide special handling for const, pure, and fpmath
@@ -2253,7 +2256,8 @@ write_decls (void)
fprintf (header_file, " ENB_P10,\n");
fprintf (header_file, " ENB_P10_64,\n");
fprintf (header_file, " ENB_MMA,\n");
- fprintf (header_file, " ENB_FUTURE\n");
+ fprintf (header_file, " ENB_FUTURE,\n");
+ fprintf (header_file, " ENB_FUTUREV\n");
fprintf (header_file, "};\n\n");
fprintf (header_file, "#define PPC_MAXRESTROPNDS 3\n");
diff --git a/gcc/config/rs6000/rs6000-overload.def
b/gcc/config/rs6000/rs6000-overload.def
index ef7b59ed112..09be9e7de71 100644
--- a/gcc/config/rs6000/rs6000-overload.def
+++ b/gcc/config/rs6000/rs6000-overload.def
@@ -2530,6 +2530,10 @@
VMULEUD
[VEC_MULH, vec_mulh, __builtin_vec_mulh]
+ vss __builtin_vec_mulh (vss, vss);
+ XVMULHSH
+ vus __builtin_vec_mulh (vus, vus);
+ XVMULHUH
vsi __builtin_vec_mulh (vsi, vsi);
VMULHSW
vui __builtin_vec_mulh (vui, vui);
diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md
index e6adf91002e..80fb46c8f00 100644
--- a/gcc/config/rs6000/vector.md
+++ b/gcc/config/rs6000/vector.md
@@ -71,6 +71,9 @@
;; Vector integer modes
(define_mode_iterator VI [V4SI V8HI V16QI])
+;; Vector integer multiply high modes
+(define_mode_iterator VIMulH [V4SI V2DI])
+
;; Base type from vector mode
(define_mode_attr VEC_base [(V16QI "QI")
(V8HI "HI")
@@ -188,6 +191,14 @@
"VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
"")
+;; This expander will be mapped to *vsx_add<mode>3 / *altivec_add<mode>3
+(define_expand "add<mode>3"
+ [(set (match_operand:VEC_I 0 "register_operand")
+ (plus:VEC_I (match_operand:VEC_I 1 "register_operand")
+ (match_operand:VEC_I 2 "register_operand")))]
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "")
+
(define_expand "sub<mode>3"
[(set (match_operand:VEC_F 0 "vfloat_operand")
(minus:VEC_F (match_operand:VEC_F 1 "vfloat_operand")
@@ -195,6 +206,14 @@
"VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
"")
+;; This expander will be mapped to *vsx_sub<mode>3 / *altivec_sub<mode>3
+(define_expand "sub<mode>3"
+ [(set (match_operand:VEC_I 0 "register_operand")
+ (minus:VEC_I (match_operand:VEC_I 1 "register_operand")
+ (match_operand:VEC_I 2 "register_operand")))]
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "")
+
(define_expand "mul<mode>3"
[(set (match_operand:VEC_F 0 "vfloat_operand")
(mult:VEC_F (match_operand:VEC_F 1 "vfloat_operand")
@@ -208,6 +227,28 @@
}
})
+;; This expander will be mapped to
+;; *altivec_smul<mode>3_highpart /
+;; vsx_smul<mode>3_highpart.
+(define_expand "smul<mode>3_highpart"
+ [(set (match_operand:VIMulH 0 "register_operand")
+ (smul_highpart:VIMulH
+ (match_operand:VIMulH 1 "register_operand")
+ (match_operand:VIMulH 2 "register_operand")))]
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode) && TARGET_POWER10"
+ "")
+
+;; This expander will be mapped to
+;; *altivec_umul<mode>3_highpart /
+;; vsx_umul<mode>3_highpart.
+(define_expand "umul<mode>3_highpart"
+ [(set (match_operand:VIMulH 0 "register_operand")
+ (umul_highpart:VIMulH
+ (match_operand:VIMulH 1 "register_operand")
+ (match_operand:VIMulH 2 "register_operand")))]
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode) && TARGET_POWER10"
+ "")
+
(define_expand "div<mode>3"
[(set (match_operand:VEC_F 0 "vfloat_operand")
(div:VEC_F (match_operand:VEC_F 1 "vfloat_operand")
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index f5ace28ea93..10064e3e9b1 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -418,6 +418,9 @@
(define_int_attr vczlsbb_char [(UNSPEC_VCLZLSBB "l")
(UNSPEC_VCTZLSBB "t")])
+;; Vector integer arithmetic modes
+(define_mode_iterator VIArith [V8HI V4SI])
+
;; VSX moves
;; TImode memory to memory move optimization on LE with p8vector
@@ -1711,6 +1714,13 @@
"xvsub<sd>p %x0,%x1,%x2"
[(set_attr "type" "<VStype_simple>")])
+(define_insn "*vsx_mul<mode>3"
+ [(set (match_operand:VIArith 0 "vsx_register_operand" "=wa")
+ (mult:VIArith (match_operand:VIArith 1 "vsx_register_operand" "wa")
+ (match_operand:VIArith 2 "vsx_register_operand" "wa")))]
+ "TARGET_FUTURE && TARGET_VSX"
+ "xvmulu<wd>m %x0,%x1,%x2")
+
(define_insn "*vsx_mul<mode>3"
[(set (match_operand:VSX_F 0 "vsx_register_operand" "=wa")
(mult:VSX_F (match_operand:VSX_F 1 "vsx_register_operand" "wa")
@@ -6546,20 +6556,36 @@
[(set_attr "type" "vecdiv")
(set_attr "size" "<bits>")])
-(define_insn "smul<mode>3_highpart"
- [(set (match_operand:VIlong 0 "altivec_register_operand" "=v")
- (smul_highpart:VIlong
- (match_operand:VIlong 1 "altivec_register_operand" "v")
- (match_operand:VIlong 2 "altivec_register_operand" "v")))]
+(define_insn "vsx_smul<mode>3_highpart"
+ [(set (match_operand:VIArith 0 "vsx_register_operand" "=wa")
+ (smul_highpart:VIArith
+ (match_operand:VIArith 1 "vsx_register_operand" "wa")
+ (match_operand:VIArith 2 "vsx_register_operand" "wa")))]
+ "TARGET_FUTURE && TARGET_VSX"
+ "xvmulhs<wd> %x0,%x1,%x2")
+
+(define_insn "vsx_umul<mode>3_highpart"
+ [(set (match_operand:VIArith 0 "vsx_register_operand" "=wa")
+ (umul_highpart:VIArith
+ (match_operand:VIArith 1 "vsx_register_operand" "wa")
+ (match_operand:VIArith 2 "vsx_register_operand" "wa")))]
+ "TARGET_FUTURE && TARGET_VSX"
+ "xvmulhu<wd> %x0,%x1,%x2")
+
+(define_insn "*altivec_smul<mode>3_highpart"
+ [(set (match_operand:VIMulH 0 "altivec_register_operand" "=v")
+ (smul_highpart:VIMulH
+ (match_operand:VIMulH 1 "altivec_register_operand" "v")
+ (match_operand:VIMulH 2 "altivec_register_operand" "v")))]
"TARGET_POWER10"
"vmulhs<wd> %0,%1,%2"
[(set_attr "type" "veccomplex")])
-(define_insn "umul<mode>3_highpart"
- [(set (match_operand:VIlong 0 "altivec_register_operand" "=v")
- (umul_highpart:VIlong
- (match_operand:VIlong 1 "altivec_register_operand" "v")
- (match_operand:VIlong 2 "altivec_register_operand" "v")))]
+(define_insn "*altivec_umul<mode>3_highpart"
+ [(set (match_operand:VIMulH 0 "altivec_register_operand" "=v")
+ (umul_highpart:VIMulH
+ (match_operand:VIMulH 1 "altivec_register_operand" "v")
+ (match_operand:VIMulH 2 "altivec_register_operand" "v")))]
"TARGET_POWER10"
"vmulhu<wd> %0,%1,%2"
[(set_attr "type" "veccomplex")])
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 01ffe30c441..5a5f9ce28c0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -26761,6 +26761,22 @@ vec_t __builtin_galois_field_mult_gcm (vec_t, vec_t);
vec_t __builtin_galois_field_mult_xts (vec_t, vec_t);
@end smallexample
+Future PowerPC processors may add new instructions for vector integer
+multiply high for halfword. GCC provides support for these instructions through
+the following built-in functions.
+
+@findex vec_mulh
+@smallexample
+@exdent vector signed short
+@exdent vec_mulh (vector signed short @var{a}, vector signed short @var{b});
+@exdent vector unsigned short
+@exdent vec_mulh (vector unsigned short @var{a}, vector unsigned short
@var{b});
+@end smallexample
+
+For each integer value @code{i} from 0 to 7, do the following. The integer
+value in halfword element @code{i} of @var{a} is multiplied by the integer
+value in halfword element @code{i} of @var{b}. The high-order 16 bits of the
+32-bit product are placed into halfword element @code{i} of the vector
returned.
@node PowerPC Hardware Transactional Memory Built-in Functions
@subsection PowerPC Hardware Transactional Memory Built-in Functions
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx_simd-1.c
b/gcc/testsuite/gcc.target/powerpc/vsx_simd-1.c
new file mode 100644
index 00000000000..486fef38dae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vsx_simd-1.c
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+
+#include <altivec.h>
+
+typedef vector signed int v4si_t;
+typedef vector signed short v8hi_t;
+typedef vector signed long long v2di_t;
+
+__attribute__((noinline))
+v4si_t int_add (v4si_t x, v4si_t y)
+{
+ return vec_add (x, y); /* xvadduwm */
+}
+
+__attribute__((noinline))
+v4si_t int_sub (v4si_t x, v4si_t y)
+{
+ return vec_sub (x, y); /* xvsubuwm */
+}
+
+__attribute__((noinline))
+v4si_t int_mul (v4si_t x, v4si_t y)
+{
+ return vec_mul (x, y); /* xvmuluwm */
+}
+
+__attribute__((noinline))
+v4si_t int_mulhi (v4si_t x, v4si_t y)
+{
+ return vec_mulh (x, y); /* xvmulhsw */
+}
+
+__attribute__((noinline))
+v8hi_t short_add (v8hi_t x, v8hi_t y)
+{
+ return vec_add (x, y); /* xvadduhm */
+}
+
+__attribute__((noinline))
+v8hi_t short_sub (v8hi_t x, v8hi_t y)
+{
+ return vec_sub (x, y); /* xvsubuhm */
+}
+
+__attribute__((noinline))
+v8hi_t short_mul (v8hi_t x, v8hi_t y)
+{
+ return vec_mul (x, y); /* xvmuluhm */
+}
+
+__attribute__((noinline))
+v8hi_t short_mulhi (v8hi_t x, v8hi_t y)
+{
+ return vec_mulh (x, y); /* xvmulhsh */
+}
+
+__attribute__((noinline))
+v2di_t longlong_mul (v2di_t x, v2di_t y)
+{
+ return vec_mulh (x, y); /* vmulhsd */
+}
+
+/* { dg-final { scan-assembler-times "xvadduwm" 1 } } */
+/* { dg-final { scan-assembler-times "xvsubuwm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmuluwm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmulhsw" 1 } } */
+/* { dg-final { scan-assembler-times "xvadduhm" 1 } } */
+/* { dg-final { scan-assembler-times "xvsubuhm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmuluhm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmulhsh" 1 } } */
+/* { dg-final { scan-assembler-times "vmulhsd" 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx_simd-2.c
b/gcc/testsuite/gcc.target/powerpc/vsx_simd-2.c
new file mode 100644
index 00000000000..04e1997d66f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vsx_simd-2.c
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+
+#include <altivec.h>
+
+typedef vector unsigned int v4si_t;
+typedef vector unsigned short v8hi_t;
+typedef vector unsigned long long v2di_t;
+
+__attribute__((noinline))
+v4si_t int_add (v4si_t x, v4si_t y)
+{
+ return vec_add (x, y); /* xvadduwm */
+}
+
+__attribute__((noinline))
+v4si_t int_sub (v4si_t x, v4si_t y)
+{
+ return vec_sub (x, y); /* xvsubuwm */
+}
+
+__attribute__((noinline))
+v4si_t int_mul (v4si_t x, v4si_t y)
+{
+ return vec_mul (x, y); /* xvmuluwm */
+}
+
+__attribute__((noinline))
+v4si_t int_mulhi (v4si_t x, v4si_t y)
+{
+ return vec_mulh (x, y); /* xvmulhuw */
+}
+
+__attribute__((noinline))
+v8hi_t short_add (v8hi_t x, v8hi_t y)
+{
+ return vec_add (x, y); /* xvadduhm */
+}
+
+__attribute__((noinline))
+v8hi_t short_sub (v8hi_t x, v8hi_t y)
+{
+ return vec_sub (x, y); /* xvsubuhm */
+}
+
+__attribute__((noinline))
+v8hi_t short_mul (v8hi_t x, v8hi_t y)
+{
+ return vec_mul (x, y); /* xvmuluhm */
+}
+
+__attribute__((noinline))
+v8hi_t short_mulhi (v8hi_t x, v8hi_t y)
+{
+ return vec_mulh (x, y); /* xvmulhuh */
+}
+
+__attribute__((noinline))
+v2di_t longlong_mul (v2di_t x, v2di_t y)
+{
+ return vec_mulh (x, y); /* vmulhud */
+}
+
+/* { dg-final { scan-assembler-times "xvadduwm" 1 } } */
+/* { dg-final { scan-assembler-times "xvsubuwm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmuluwm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmulhuw" 1 } } */
+/* { dg-final { scan-assembler-times "xvadduhm" 1 } } */
+/* { dg-final { scan-assembler-times "xvsubuhm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmuluhm" 1 } } */
+/* { dg-final { scan-assembler-times "xvmulhuh" 1 } } */
+/* { dg-final { scan-assembler-times "vmulhud" 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx_simd-3.c
b/gcc/testsuite/gcc.target/powerpc/vsx_simd-3.c
new file mode 100644
index 00000000000..e58db04714d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vsx_simd-3.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2 -mno-vsx" } */
+
+#include <altivec.h>
+
+typedef vector signed int vsi;
+typedef vector signed short vss;
+typedef vector unsigned int vui;
+
+__attribute__((noinline))
+vsi int_add (vsi x, vsi y)
+{
+ return vec_add (x, y); /* vadduwm */
+}
+
+__attribute__((noinline))
+vsi int_sub (vsi x, vsi y)
+{
+ return vec_sub (x, y); /* vsubuwm */
+}
+
+__attribute__((noinline))
+vsi int_mulhi (vsi x, vsi y)
+{
+ return vec_mulh (x, y); /* vmulhsw */
+}
+
+__attribute__((noinline))
+vui uint_mulh (vui x, vui y)
+{
+ return vec_mulh (x, y); /* vmulhuw */
+}
+
+__attribute__((noinline))
+vss short_add (vss x, vss y)
+{
+ return vec_add (x, y); /* vadduhm */
+}
+
+__attribute__((noinline))
+vss short_sub (vss x, vss y)
+{
+ return vec_sub (x, y); /* vsubuhm */
+}
+
+__attribute__((noinline))
+vss short_mul (vss x, vss y)
+{
+ return vec_mul (x, y); /* vmladduhm */
+}
+
+/* { dg-final { scan-assembler-times "vadduwm" 1 } } */
+/* { dg-final { scan-assembler-times "vsubuwm" 1 } } */
+/* { dg-final { scan-assembler-times "vmulhsw" 1 } } */
+/* { dg-final { scan-assembler-times "vmulhuw" 1 } } */
+/* { dg-final { scan-assembler-times "vadduhm" 1 } } */
+/* { dg-final { scan-assembler-times "vsubuhm" 1 } } */
+/* { dg-final { scan-assembler-times "vmladduhm" 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx_simd-4.c
b/gcc/testsuite/gcc.target/powerpc/vsx_simd-4.c
new file mode 100644
index 00000000000..be6ab3c91a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vsx_simd-4.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2 -mno-vsx" } */
+
+#include <altivec.h>
+
+typedef vector signed short vss;
+typedef vector unsigned short vus;
+
+__attribute__((noinline))
+vss short_mulhi (vss x, vss y)
+{
+ return vec_mulh (x, y); /* { dg-error "'__builtin_vsx_xvmulhsh' requires
the '-mcpu=future' and '-mvsx' options" } */
+}
+
+__attribute__((noinline))
+vus ushort_mulhi (vus x, vus y)
+{
+ return vec_mulh (x, y); /* { dg-error "'__builtin_vsx_xvmulhuh' requires
the '-mcpu=future' and '-mvsx' options" } */
+}