https://gcc.gnu.org/g:bd261b39dedc064209a14be95ffb456f5cd01c1d
commit r17-5048-gbd261b39dedc064209a14be95ffb456f5cd01c1d Author: Stefan Schulze Frielinghaus <[email protected]> Date: Sat Oct 10 09:51:31 2026 +0200 match.pd: Fold zero test for .CLZ/.CTZ over vector modes So far only for scalars a zero test was simplified. Now, do the same for vector types, too. Also document that .CLZ/.CTZ has an optional second argument which describes the at-zero value. gcc/ChangeLog: * doc/ifn.texi (IFN_CLZ): Document optional second argument. (IFN_CTZ): Ditto. * match.pd: Fold zero test for .CLZ/.CTZ over vector modes, too. gcc/testsuite/ChangeLog: * gcc.target/s390/clz-ctz-1.c: Adapt after zero tests are folded, now. Diff: --- gcc/doc/ifn.texi | 10 +++++-- gcc/match.pd | 18 +++++++------ gcc/testsuite/gcc.target/s390/clz-ctz-1.c | 43 +++++++++---------------------- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/gcc/doc/ifn.texi b/gcc/doc/ifn.texi index 7cfc80eecf26..d80e089685a3 100644 --- a/gcc/doc/ifn.texi +++ b/gcc/doc/ifn.texi @@ -1088,12 +1088,18 @@ instruction pattern for integer and integer vector modes. @cindex @code{IFN_CLZ} internal function @item @samp{IFN_CLZ} The @code{IFN_CLZ} internal function directly maps to the @code{clz} -instruction pattern for integer and integer vector modes. +instruction pattern for integer and integer vector modes. In case the value +for zero is defined, then this is recorded in the optional second argument. +Note, this is always a scalar value even for vector modes where it represents +the scalar value of a lane. @cindex @code{IFN_CTZ} internal function @item @samp{IFN_CTZ} The @code{IFN_CTZ} internal function directly maps to the @code{ctz} -instruction pattern for integer and integer vector modes. +instruction pattern for integer and integer vector modes. In case the value +for zero is defined, then this is recorded in the optional second argument. +Note, this is always a scalar value even for vector modes where it represents +the scalar value of a lane. @cindex @code{IFN_FFS} internal function @item @samp{IFN_FFS} diff --git a/gcc/match.pd b/gcc/match.pd index 0a4f7b718b46..193dcc5cd660 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -11786,8 +11786,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) } (if (ifn == IFN_CLZ && wi::to_widest (@2) == val) (IFN_CLZ @3 @2))))) -(simplify - (cond (ne @0 integer_zerop@1) (IFN_CLZ (convert?@3 @0) INTEGER_CST@2) @2) +(for cnd (cond vec_cond) + (simplify + (cnd (ne @0 integer_zerop@1) (IFN_CLZ (convert?@3 @0) INTEGER_CST@2) uniform_integer_cst_p@4) (with { int val; internal_fn ifn = IFN_LAST; if (BITINT_TYPE_P (TREE_TYPE (@3))) @@ -11796,8 +11797,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) OPTIMIZE_FOR_BOTH)) ifn = IFN_CLZ; } - (if (ifn == IFN_CLZ) - (IFN_CLZ @3 @2)))) + (if (ifn == IFN_CLZ && tree_int_cst_equal (@2, uniform_integer_cst_p (@4))) + (IFN_CLZ @3 @2))))) /* a != 0 ? CTZ(a) : CST -> .CTZ(a) where CST is the result of the internal function for 0. */ (for func (CTZ) @@ -11825,8 +11826,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) } (if (ifn == IFN_CTZ && wi::to_widest (@2) == val) (IFN_CTZ @3 @2))))) -(simplify - (cond (ne @0 integer_zerop@1) (IFN_CTZ (convert?@3 @0) INTEGER_CST@2) @2) +(for cnd (cond vec_cond) + (simplify + (cnd (ne @0 integer_zerop@1) (IFN_CTZ (convert?@3 @0) INTEGER_CST@2) uniform_integer_cst_p@4) (with { int val; internal_fn ifn = IFN_LAST; if (BITINT_TYPE_P (TREE_TYPE (@3))) @@ -11835,8 +11837,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) OPTIMIZE_FOR_BOTH)) ifn = IFN_CTZ; } - (if (ifn == IFN_CTZ) - (IFN_CTZ @3 @2)))) + (if (ifn == IFN_CTZ && tree_int_cst_equal (@2, uniform_integer_cst_p (@4))) + (IFN_CTZ @3 @2))))) #endif /* Common POPCOUNT/PARITY simplifications. */ diff --git a/gcc/testsuite/gcc.target/s390/clz-ctz-1.c b/gcc/testsuite/gcc.target/s390/clz-ctz-1.c index 523c089755c4..4e81b205d68c 100644 --- a/gcc/testsuite/gcc.target/s390/clz-ctz-1.c +++ b/gcc/testsuite/gcc.target/s390/clz-ctz-1.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2" } */ /* { dg-final { check-function-bodies "**" "" "" } } */ -/* { dg-final { scan-assembler-times {\n\tvzero\t} 9 } } */ +/* { dg-final { scan-assembler-times {\n\tvzero\t} 3 } } */ typedef unsigned char __attribute__ ((vector_size (16))) v16qi; typedef unsigned short __attribute__ ((vector_size (16))) v8hi; @@ -172,14 +172,9 @@ v16qi clzv16qi_z13 (v16qi x) return x; } -/* TODO: fold zero test. - +/* ** clzgv16qi_z13: -** vzero (%v[0-9]+) -** vceqb (%v[0-9]+),%v24,\1 -** vgm (%v[0-9]+),4,4,0 ** vclzb %v24,%v24 -** vsel %v24,\3,%v24,\2 ** br %r14 */ @@ -210,14 +205,9 @@ v8hi clzv8hi_z13 (v8hi x) return x; } -/* TODO: fold zero test. - +/* ** clzgv8hi_z13: -** vzero (%v[0-9]+) -** vceqh (%v[0-9]+),%v24,\1 -** vgm (%v[0-9]+),11,11,1 ** vclzh %v24,%v24 -** vsel %v24,\3,%v24,\2 ** br %r14 */ @@ -354,6 +344,12 @@ void ctzsi_z13_autovec (unsigned int *x) } /* TODO: fold zero test. + In contrast to ctzsi_z13_autovec, vect-pattern recognition fails because + type precision differs for lhs and promoted rhs. Consequently no ctz ifn is + constructed which is required by match.pd in order to fold a zero test. + Furthermore, in contrast to ctzdi_z17_autovec where phiopt2 already folds + the zero test since starting with z17 ctzdi2 becomes available and + vect-patterns recog never sees a zero test. ** ctzdi_z13_autovec: ** ... @@ -409,14 +405,9 @@ void ctzti_z17_autovec (int *x, unsigned __int128 *y) } -/* TODO: fold zero test. - +/* ** ctzv16qi_z13: -** vzero (%v[0-9]+) -** vceqb (%v[0-9]+),%v24,\1 -** vgm (%v[0-9]+),4,4,0 ** vctzb %v24,%v24 -** vsel %v24,\3,%v24,\2 ** br %r14 */ @@ -428,14 +419,9 @@ v16qi ctzv16qi_z13 (v16qi x) return x; } -/* TODO: fold zero test. - +/* ** ctzv8hi_z13: -** vzero (%v[0-9]+) -** vceqh (%v[0-9]+),%v24,\1 -** vgm (%v[0-9]+),11,11,1 ** vctzh %v24,%v24 -** vsel %v24,\3,%v24,\2 ** br %r14 */ @@ -447,14 +433,9 @@ v8hi ctzv8hi_z13 (v8hi x) return x; } -/* TODO: fold zero test. - +/* ** ctzv4si_z13: -** vzero (%v[0-9]+) -** vceqf (%v[0-9]+),%v24,\1 -** vgm (%v[0-9]+),26,26,2 ** vctzf %v24,%v24 -** vsel %v24,\3,%v24,\2 ** br %r14 */
