rs6000: Add vector count under mask
authorKelvin Nilsen <kelvin@gcc.gnu.org>
Mon, 11 May 2020 14:35:01 +0000 (09:35 -0500)
committerBill Schmidt <wschmidt@linux.ibm.com>
Mon, 11 May 2020 14:54:33 +0000 (09:54 -0500)
Add support for new vclzdm and vctzdm vector instructions that
count leading and trailing zeros under control of a mask.

[gcc]

2020-05-11  Kelvin Nilsen  <kelvin@gcc.gnu.org>
    Bill Schmidt  <wschmidt@linux.ibm.com>

* config/rs6000/altivec.h (vec_clzm): New macro.
(vec_ctzm): Likewise.
* config/rs6000/altivec.md (UNSPEC_VCLZDM): New constant.
(UNSPEC_VCTZDM): Likewise.
(vclzdm): New insn.
(vctzdm): Likewise.
* config/rs6000/rs6000-builtin.def (BU_FUTURE_V_0): New macro.
(BU_FUTURE_V_1): Likewise.
(BU_FUTURE_V_2): Likewise.
(BU_FUTURE_V_3): Likewise.
(__builtin_altivec_vclzdm): New builtin definition.
(__builtin_altivec_vctzdm): Likewise.
* config/rs6000/rs6000-c.c (rs6000_target_modify_macros): Cause
_ARCH_PWR_FUTURE macro to be defined if OPTION_MASK_FUTURE flag is
set.
* config/rs6000/rs6000-call.c (builtin_function_type): Set return
value and parameter types to be unsigned for VCLZDM and VCTZDM.
* config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): Add
support for TARGET_FUTURE flag.
* config/rs6000/rs6000.h (RS6000_BTM_FUTURE): New macro constant.
* doc/extend.texi (PowerPC Altivec Built-in Functions Available
for a Future Architecture): New subsubsection.

[gcc/testsuite]

2020-05-11  Kelvin Nilsen  <kelvin@gcc.gnu.org>

* gcc.target/powerpc/vec-clzm-0.c: New test.
* gcc.target/powerpc/vec-clzm-1.c: New test.
* gcc.target/powerpc/vec-ctzm-0.c: New test.
* gcc.target/powerpc/vec-ctzm-1.c: New test.

14 files changed:
gcc/ChangeLog
gcc/config/rs6000/altivec.h
gcc/config/rs6000/altivec.md
gcc/config/rs6000/rs6000-builtin.def
gcc/config/rs6000/rs6000-c.c
gcc/config/rs6000/rs6000-call.c
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/vec-clzm-0.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/vec-clzm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/vec-ctzm-0.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/vec-ctzm-1.c [new file with mode: 0644]

index 6072e78cf7715bad9006f970c31acbaa5e9c5faa..b5f64d5c03b4c487ae5112db5cdef6b53fc1c705 100644 (file)
@@ -1,3 +1,29 @@
+2020-05-11  Kelvin Nilsen  <kelvin@gcc.gnu.org>
+           Bill Schmidt  <wschmidt@linux.ibm.com>
+
+       * config/rs6000/altivec.h (vec_clzm): New macro.
+       (vec_ctzm): Likewise.
+       * config/rs6000/altivec.md (UNSPEC_VCLZDM): New constant.
+       (UNSPEC_VCTZDM): Likewise.
+       (vclzdm): New insn.
+       (vctzdm): Likewise.
+       * config/rs6000/rs6000-builtin.def (BU_FUTURE_V_0): New macro.
+       (BU_FUTURE_V_1): Likewise.
+       (BU_FUTURE_V_2): Likewise.
+       (BU_FUTURE_V_3): Likewise.
+       (__builtin_altivec_vclzdm): New builtin definition.
+       (__builtin_altivec_vctzdm): Likewise.
+       * config/rs6000/rs6000-c.c (rs6000_target_modify_macros): Cause
+       _ARCH_PWR_FUTURE macro to be defined if OPTION_MASK_FUTURE flag is
+       set.
+       * config/rs6000/rs6000-call.c (builtin_function_type): Set return
+       value and parameter types to be unsigned for VCLZDM and VCTZDM.
+       * config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): Add
+       support for TARGET_FUTURE flag.
+       * config/rs6000/rs6000.h (RS6000_BTM_FUTURE): New macro constant.
+       * doc/extend.texi (PowerPC Altivec Built-in Functions Available
+       for a Future Architecture): New subsubsection.
+
 2020-05-11  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/94988
index 5f1f5924488b94c95e354e1cecb799153275cfe4..e1e75ad0f1eef42f8ac4a0694b65296f7075780c 100644 (file)
@@ -686,4 +686,11 @@ __altivec_scalar_pred(vec_any_nle,
    to #define vec_step to __builtin_vec_step.  */
 #define vec_step(x) __builtin_vec_step (* (__typeof__ (x) *) 0)
 
+#ifdef _ARCH_PWR_FUTURE
+/* May modify these macro definitions if future capabilities overload
+   with support for different vector argument and result types.  */
+#define vec_clzm(a, b) __builtin_altivec_vclzdm (a, b)
+#define vec_ctzm(a, b) __builtin_altivec_vctzdm (a, b)
+#endif
+
 #endif /* _ALTIVEC_H */
index 6b1d987913cf9767bbaa0f14d8099b6cc00fe231..5ef4889ba55a883261a6368758907c7a9e6a870c 100644 (file)
    UNSPEC_BCD_OVERFLOW
    UNSPEC_VRLMI
    UNSPEC_VRLNM
+   UNSPEC_VCLZDM
+   UNSPEC_VCTZDM
 ])
 
 (define_c_enum "unspecv"
   "bcd<bcd_add_sub>. %0,%1,%2,%3"
   [(set_attr "type" "vecsimple")])
 
+(define_insn "vclzdm"
+  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v")
+       (unspec:V2DI [(match_operand:V2DI 1 "altivec_register_operand" "v")
+                     (match_operand:V2DI 2 "altivec_register_operand" "v")]
+        UNSPEC_VCLZDM))]
+   "TARGET_FUTURE"
+   "vclzdm %0,%1,%2"
+   [(set_attr "type" "vecsimple")])
+
+(define_insn "vctzdm"
+  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v")
+       (unspec:V2DI [(match_operand:V2DI 1 "altivec_register_operand" "v")
+                     (match_operand:V2DI 2 "altivec_register_operand" "v")]
+        UNSPEC_VCTZDM))]
+   "TARGET_FUTURE"
+   "vctzdm %0,%1,%2"
+   [(set_attr "type" "vecsimple")])
+
+
 (define_expand "bcd<bcd_add_sub>_<code>"
   [(parallel [(set (reg:CCFP CR6_REGNO)
                   (compare:CCFP
index 54f750c8384c8905267910e5eb08544906d83b1d..9293e7cf4fb2dad4b2fd9292cdc7786402c8759b 100644 (file)
                     | RS6000_BTC_BINARY),                              \
                    CODE_FOR_ ## ICODE)                 /* ICODE */
 
+/* For vector builtins for instructions which may be added at some point in
+   the future that are encoded as altivec instructions, use
+   __builtin_altivec_ as the builtin name.  */
+
+#define BU_FUTURE_V_0(ENUM, NAME, ATTR, ICODE)                 \
+  RS6000_BUILTIN_0 (FUTUREV_BUILTIN_ ## ENUM,          /* ENUM */      \
+                   "__builtin_altivec_" NAME,          /* NAME */      \
+                   RS6000_BTM_FUTURE,                  /* MASK */      \
+                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
+                    | RS6000_BTC_SPECIAL),                             \
+                   CODE_FOR_ ## ICODE)                 /* ICODE */
+
+#define BU_FUTURE_V_1(ENUM, NAME, ATTR, ICODE)                 \
+  RS6000_BUILTIN_1 (FUTURE_BUILTIN_ ## ENUM,           /* ENUM */      \
+                   "__builtin_altivec_" NAME,          /* NAME */      \
+                   RS6000_BTM_FUTURE,                  /* MASK */      \
+                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
+                    | RS6000_BTC_UNARY),                               \
+                   CODE_FOR_ ## ICODE)                 /* ICODE */
+
+#define BU_FUTURE_V_2(ENUM, NAME, ATTR, ICODE)                 \
+  RS6000_BUILTIN_2 (FUTURE_BUILTIN_ ## ENUM,           /* ENUM */      \
+                   "__builtin_altivec_" NAME,          /* NAME */      \
+                   RS6000_BTM_FUTURE,                  /* MASK */      \
+                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
+                    | RS6000_BTC_BINARY),                              \
+                   CODE_FOR_ ## ICODE)                 /* ICODE */
+
+#define BU_FUTURE_V_3(ENUM, NAME, ATTR, ICODE)                 \
+  RS6000_BUILTIN_3 (FUTURE_BUILTIN_ ## ENUM,           /* ENUM */      \
+                   "__builtin_altivec_" NAME,          /* NAME */      \
+                   RS6000_BTM_FUTURE,                  /* MASK */      \
+                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
+                    | RS6000_BTC_TERNARY),                             \
+                   CODE_FOR_ ## ICODE)                 /* ICODE */
+
 #endif
 
 \f
@@ -2479,6 +2515,10 @@ BU_P9_OVERLOAD_2 (CMPRB, "byte_in_range")
 BU_P9_OVERLOAD_2 (CMPRB2,      "byte_in_either_range")
 BU_P9_OVERLOAD_2 (CMPEQB,      "byte_in_set")
 \f
+/* Future architecture vector built-ins.  */
+BU_FUTURE_V_2 (VCLZDM, "vclzdm", CONST, vclzdm)
+BU_FUTURE_V_2 (VCTZDM, "vctzdm", CONST, vctzdm)
+\f
 /* 1 argument crypto functions.  */
 BU_CRYPTO_1 (VSBOX,            "vsbox",          CONST, crypto_vsbox_v2di)
 BU_CRYPTO_1 (VSBOX_BE,         "vsbox_be",       CONST, crypto_vsbox_v16qi)
index e59eff95cf4b11cd13f78b6bc97aac380525ed44..ee2db96f2bdcc71ffb924bd127a42ca911bb2b9e 100644 (file)
@@ -448,6 +448,8 @@ rs6000_target_modify_macros (bool define_p, HOST_WIDE_INT flags,
     rs6000_define_or_undefine_macro (define_p, "_ARCH_PWR8");
   if ((flags & OPTION_MASK_MODULO) != 0)
     rs6000_define_or_undefine_macro (define_p, "_ARCH_PWR9");
+  if ((flags & OPTION_MASK_FUTURE) != 0)
+    rs6000_define_or_undefine_macro (define_p, "_ARCH_PWR_FUTURE");
   if ((flags & OPTION_MASK_SOFT_FLOAT) != 0)
     rs6000_define_or_undefine_macro (define_p, "_SOFT_FLOAT");
   if ((flags & OPTION_MASK_RECIP_PRECISION) != 0)
index 68164b912f066c0b4e16f92d599bb37600cdfa9e..2a4ce5bd340e2c30562749d82325221c330861c8 100644 (file)
@@ -12926,6 +12926,8 @@ builtin_function_type (machine_mode mode_ret, machine_mode mode_arg0,
     case P8V_BUILTIN_ORC_V4SI_UNS:
     case P8V_BUILTIN_ORC_V2DI_UNS:
     case P8V_BUILTIN_ORC_V1TI_UNS:
+    case FUTURE_BUILTIN_VCLZDM:
+    case FUTURE_BUILTIN_VCTZDM:
       h.uns_p[0] = 1;
       h.uns_p[1] = 1;
       h.uns_p[2] = 1;
index 355aea8628def909bef27e6baaed8bbeae887207..273a7215bc5ea7b602fde21847f5272937d6fa89 100644 (file)
@@ -3336,7 +3336,8 @@ rs6000_builtin_mask_calculate (void)
              && TARGET_HARD_FLOAT
              && !TARGET_IEEEQUAD)          ? RS6000_BTM_LDBL128   : 0)
          | ((TARGET_FLOAT128_TYPE)         ? RS6000_BTM_FLOAT128  : 0)
-         | ((TARGET_FLOAT128_HW)           ? RS6000_BTM_FLOAT128_HW : 0));
+         | ((TARGET_FLOAT128_HW)           ? RS6000_BTM_FLOAT128_HW : 0)
+         | ((TARGET_FUTURE)                ? RS6000_BTM_FUTURE    : 0));
 }
 
 /* Implement TARGET_MD_ASM_ADJUST.  All asm statements are considered
index 1adc371d70f783a23ddc74ed0575b8f8894d929b..5603af994fa0b49a703a181d3ca3bf82c65f0454 100644 (file)
@@ -2304,6 +2304,8 @@ extern int frame_pointer_needed;
 #define RS6000_BTM_POWERPC64   MASK_POWERPC64  /* 64-bit registers.  */
 #define RS6000_BTM_FLOAT128    MASK_FLOAT128_KEYWORD /* IEEE 128-bit float.  */
 #define RS6000_BTM_FLOAT128_HW MASK_FLOAT128_HW /* IEEE 128-bit float h/w.  */
+#define RS6000_BTM_FUTURE      MASK_FUTURE
+
 
 #define RS6000_BTM_COMMON      (RS6000_BTM_ALTIVEC                     \
                                 | RS6000_BTM_VSX                       \
index 936c22e2fe7e55597af3502d956896a6819164ba..aa8ab3a8dc5bb06ba2f3bc9d9a68cd50c150f5e8 100644 (file)
@@ -17645,6 +17645,7 @@ briefly described below.
 * PowerPC AltiVec Built-in Functions Available on ISA 2.06::
 * PowerPC AltiVec Built-in Functions Available on ISA 2.07::
 * PowerPC AltiVec Built-in Functions Available on ISA 3.0::
+* PowerPC AltiVec Built-in Functions Available for a Future Architecture::
 @end menu
 
 @node PowerPC AltiVec Built-in Functions on ISA 2.05
@@ -20687,6 +20688,32 @@ void vec_xst (vector char, int, char *);
 void vec_xst (vector unsigned char, int, vector unsigned char *);
 void vec_xst (vector unsigned char, int, unsigned char *);
 @end smallexample
+
+@node PowerPC AltiVec Built-in Functions Available for a Future Architecture
+@subsubsection PowerPC AltiVec Built-in Functions Available for a Future Architecture
+
+The following additional built-in functions are also available for the
+PowerPC family of processors, starting with a hypothetical CPU
+which may or may not be available in the future
+(@option{-mcpu=future}) or later:
+
+@smallexample
+@exdent vector unsigned long long int
+@exdent vec_clzm (vector unsigned long long int, vector unsigned long long int)
+@end smallexample
+Perform a vector count leading zeros under bit mask operation, as if
+implemented by the Future @code{vclzdm} instruction.
+@findex vec_clzm
+
+@smallexample
+@exdent vector unsigned long long int
+@exdent vec_ctzm (vector unsigned long long int, vector unsigned long long int)
+@end smallexample
+Perform a vector count trailing zeros under bit mask operation, as if
+implemented by the Future @code{vctzdm} instruction.
+@findex vec_ctzm
+
+
 @node PowerPC Hardware Transactional Memory Built-in Functions
 @subsection PowerPC Hardware Transactional Memory Built-in Functions
 GCC provides two interfaces for accessing the Hardware Transactional
index a79cdb561ddb3e6c7ad0a323ffb523eb9108b012..db274eed95afe6773262dd74672a154826a12906 100644 (file)
 
        * gcc.target/aarch64/csinv-neg.c: New test.
 
+2020-05-11  Kelvin Nilsen  <kelvin@gcc.gnu.org>
+
+       * gcc.target/powerpc/vec-clzm-0.c: New test.
+       * gcc.target/powerpc/vec-clzm-1.c: New test.
+       * gcc.target/powerpc/vec-ctzm-0.c: New test.
+       * gcc.target/powerpc/vec-ctzm-1.c: New test.
+
 2020-05-11  Kelvin Nilsen  <kelvin@gcc.gnu.org>
 
        * gcc.target/powerpc/dg-future-0.c: New.
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-clzm-0.c b/gcc/testsuite/gcc.target/powerpc/vec-clzm-0.c
new file mode 100644 (file)
index 0000000..099c5dc
--- /dev/null
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector unsigned long long int
+do_vec_clzm (vector unsigned long long int source,
+            vector unsigned long long int mask)
+{
+  return vec_clzm (source, mask);
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned long long int source_a = { 0xa5f07e3cull, 0x7e3ca5f0ull };
+  vector unsigned long long int source_b = { 0x3ca5f07eull, 0x5a0fe7c3ull };
+
+  vector unsigned long long int mask_a = { 0xffff0000ull, 0x0000ffffull };
+  vector unsigned long long int mask_b = { 0x0f0f0f0full, 0xf0f0f0f0ull };
+
+  /* See cntlzdm-0.c for derivation of expected results.
+
+     result_aa [0] is compute (source [0], mask [0];
+     result_aa [1] is compute (source [1], mask [1].
+
+     result_ab [0] is compute (source [0], mask [2];
+     result_ab [1] is compute (source [1], mask [3].
+
+     result_ba [0] is compute (source [2], mask [0];
+     result_ba [1] is compute (source [3], mask [1].
+
+     result_bb [0] is compute (source [2], mask [2];
+     result_bb [1] is compute (source [3], mask [3].  */
+
+  vector unsigned long long int result_aa = { 0, 0 };
+  vector unsigned long long int result_ab = { 1, 1 };
+  vector unsigned long long int result_ba = { 2, 0 };
+  vector unsigned long long int result_bb = { 0, 1 };
+
+  if (!vec_all_eq (do_vec_clzm (source_a, mask_a), result_aa))
+    abort ();
+  if (!vec_all_eq (do_vec_clzm (source_a, mask_b), result_ab))
+    abort ();
+  if (!vec_all_eq (do_vec_clzm (source_b, mask_a), result_ba))
+    abort ();
+  if (!vec_all_eq (do_vec_clzm (source_b, mask_b), result_bb))
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mvclzdm\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-clzm-1.c b/gcc/testsuite/gcc.target/powerpc/vec-clzm-1.c
new file mode 100644 (file)
index 0000000..43b8611
--- /dev/null
@@ -0,0 +1,54 @@
+/* { dg-do run } */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector unsigned long long int
+do_vec_clzm (vector unsigned long long int source,
+            vector unsigned long long int mask)
+{
+  return vec_clzm (source, mask);
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned long long int source_a = { 0xa5f07e3cull, 0x7e3ca5f0ull };
+  vector unsigned long long int source_b = { 0x3ca5f07eull, 0x5a0fe7c3ull };
+
+  vector unsigned long long int mask_a = { 0xffff0000ull, 0x0000ffffull };
+  vector unsigned long long int mask_b = { 0x0f0f0f0full, 0xf0f0f0f0ull };
+
+  /* See cntlzdm-0.c for derivation of expected results.
+
+     result_aa [0] is compute (source [0], mask [0];
+     result_aa [1] is compute (source [1], mask [1].
+
+     result_ab [0] is compute (source [0], mask [2];
+     result_ab [1] is compute (source [1], mask [3].
+
+     result_ba [0] is compute (source [2], mask [0];
+     result_ba [1] is compute (source [3], mask [1].
+
+     result_bb [0] is compute (source [2], mask [2];
+     result_bb [1] is compute (source [3], mask [3].  */
+
+  vector unsigned long long int result_aa = { 0, 0 };
+  vector unsigned long long int result_ab = { 1, 1 };
+  vector unsigned long long int result_ba = { 2, 0 };
+  vector unsigned long long int result_bb = { 0, 1 };
+
+  if (!vec_all_eq (do_vec_clzm (source_a, mask_a), result_aa))
+    abort ();
+  if (!vec_all_eq (do_vec_clzm (source_a, mask_b), result_ab))
+    abort ();
+  if (!vec_all_eq (do_vec_clzm (source_b, mask_a), result_ba))
+    abort ();
+  if (!vec_all_eq (do_vec_clzm (source_b, mask_b), result_bb))
+    abort ();
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ctzm-0.c b/gcc/testsuite/gcc.target/powerpc/vec-ctzm-0.c
new file mode 100644 (file)
index 0000000..315edf4
--- /dev/null
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector unsigned long long int
+do_vec_ctzm (vector unsigned long long int source,
+            vector unsigned long long int mask)
+{
+  return vec_ctzm (source, mask);
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned long long int source_a = { 0xa5f07e3cull, 0x7e3ca5f0ull };
+  vector unsigned long long int source_b = { 0x3ca5f07eull, 0x5a0fe7c3ull };
+
+  vector unsigned long long int mask_a = { 0xffff0000ull, 0x0000ffffull };
+  vector unsigned long long int mask_b = { 0x0f0f0f0full, 0xf0f0f0f0ull };
+
+  /* See cnttzdm-0.c for derivation of expected results.
+
+     result_aa [0] is compute (source [0], mask [0];
+     result_aa [1] is compute (source [1], mask [1].
+
+     result_ab [0] is compute (source [0], mask [2];
+     result_ab [1] is compute (source [1], mask [3].
+
+     result_ba [0] is compute (source [2], mask [0];
+     result_ba [1] is compute (source [3], mask [1].
+
+     result_bb [0] is compute (source [2], mask [2];
+     result_bb [1] is compute (source [3], mask [3].  */
+
+  vector unsigned long long int result_aa = { 4, 4 };
+  vector unsigned long long int result_ab = { 2, 0 };
+  vector unsigned long long int result_ba = { 0, 0 };
+  vector unsigned long long int result_bb = { 1, 2 };
+
+  if (!vec_all_eq (do_vec_ctzm (source_a, mask_a), result_aa))
+    abort ();
+  if (!vec_all_eq (do_vec_ctzm (source_a, mask_b), result_ab))
+    abort ();
+  if (!vec_all_eq (do_vec_ctzm (source_b, mask_a),result_ba))
+    abort ();
+  if (!vec_all_eq (do_vec_ctzm (source_b, mask_b), result_bb))
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\mvctzdm\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-ctzm-1.c b/gcc/testsuite/gcc.target/powerpc/vec-ctzm-1.c
new file mode 100644 (file)
index 0000000..3dc4a03
--- /dev/null
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_future_hw } */
+/* { dg-options "-mdejagnu-cpu=future" } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector unsigned long long int
+do_vec_ctzm (vector unsigned long long int source,
+            vector unsigned long long int mask)
+{
+  return vec_ctzm (source, mask);
+}
+
+int main (int argc, char *argv [])
+{
+  vector unsigned long long int source_a = { 0xa5f07e3cull, 0x7e3ca5f0ull };
+  vector unsigned long long int source_b = { 0x3ca5f07eull, 0x5a0fe7c3ull };
+
+  vector unsigned long long int mask_a = { 0xffff0000ull, 0x0000ffffull };
+  vector unsigned long long int mask_b = { 0x0f0f0f0full, 0xf0f0f0f0ull };
+
+  /* See cnttzdm-0.c for derivation of expected results.
+
+     result_aa [0] is compute (source [0], mask [0];
+     result_aa [1] is compute (source [1], mask [1].
+
+     result_ab [0] is compute (source [0], mask [2];
+     result_ab [1] is compute (source [1], mask [3].
+
+     result_ba [0] is compute (source [2], mask [0];
+     result_ba [1] is compute (source [3], mask [1].
+
+     result_bb [0] is compute (source [2], mask [2];
+     result_bb [1] is compute (source [3], mask [3].  */
+
+  vector unsigned long long int result_aa = { 4, 4 };
+  vector unsigned long long int result_ab = { 2, 0 };
+  vector unsigned long long int result_ba = { 0, 0 };
+  vector unsigned long long int result_bb = { 1, 2 };
+
+  if (!vec_all_eq (do_vec_ctzm (source_a, mask_a), result_aa))
+    abort ();
+  if (!vec_all_eq (do_vec_ctzm (source_a, mask_b), result_ab))
+    abort ();
+  if (!vec_all_eq (do_vec_ctzm (source_b, mask_a),result_ba))
+    abort ();
+  if (!vec_all_eq (do_vec_ctzm (source_b, mask_b), result_bb))
+    abort ();
+
+  return 0;
+}