diff --git a/gcc/match.pd b/gcc/match.pd index 59791f44851230409cad09a0bc9e08e8612cae7e..b30de36e83623a158badd14160e262ca4211ceae 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -8672,6 +8672,50 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) wi::shifted_mask (tree_to_uhwi (@1), 1, false, prec)); }))))))) +#if GIMPLE +/* ctz(ext(X)) == ctz(X). Valid just for the UB at zero cases though. */ +(simplify + (CTZ (convert@1 @0)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1)) + && INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0))) + (with { combined_fn cfn = CFN_LAST; + tree type0 = TREE_TYPE (@0); + if (TREE_CODE (type0) == BITINT_TYPE) + { + if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE) + cfn = CFN_CTZ; + else + type0 + = build_nonstandard_integer_type (TYPE_PRECISION (type0), + 1); + } + type0 = unsigned_type_for (type0); + if (cfn == CFN_LAST + && direct_internal_fn_supported_p (IFN_CTZ, type0, + OPTIMIZE_FOR_BOTH)) + cfn = CFN_CTZ; + if (cfn == CFN_LAST + && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD + && !direct_internal_fn_supported_p (IFN_CTZ, + TREE_TYPE (@1), + OPTIMIZE_FOR_BOTH)) + { + if (TYPE_PRECISION (type0) + == TYPE_PRECISION (unsigned_type_node)) + cfn = CFN_BUILT_IN_CTZ; + else if (TYPE_PRECISION (type0) + == TYPE_PRECISION (long_long_unsigned_type_node)) + cfn = CFN_BUILT_IN_CTZLL; + } } + (if (cfn == CFN_CTZ) + (IFN_CTZ (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_CTZ) + (BUILT_IN_CTZ (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_CTZLL) + (BUILT_IN_CTZLL (convert:type0 @0)))))))) +#endif + /* POPCOUNT simplifications. */ /* popcount(X) + popcount(Y) is popcount(X|Y) when X&Y must be zero. */ (simplify @@ -8742,6 +8786,50 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (popcount:s @1)) (popcount (log2 @0 @1))))) +#if GIMPLE +/* popcount(zext(X)) == popcount(X). */ +(simplify + (POPCOUNT (convert@1 @0)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1)) + && INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_UNSIGNED (TREE_TYPE (@0)) + && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0))) + (with { combined_fn cfn = CFN_LAST; + tree type0 = TREE_TYPE (@0); + if (TREE_CODE (type0) == BITINT_TYPE) + { + if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE) + cfn = CFN_POPCOUNT; + else + type0 + = build_nonstandard_integer_type (TYPE_PRECISION (type0), + 1); + } + if (cfn == CFN_LAST + && direct_internal_fn_supported_p (IFN_POPCOUNT, type0, + OPTIMIZE_FOR_BOTH)) + cfn = CFN_POPCOUNT; + if (cfn == CFN_LAST + && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD + && !direct_internal_fn_supported_p (IFN_POPCOUNT, + TREE_TYPE (@1), + OPTIMIZE_FOR_BOTH)) + { + if (TYPE_PRECISION (type0) + == TYPE_PRECISION (unsigned_type_node)) + cfn = CFN_BUILT_IN_POPCOUNT; + else if (TYPE_PRECISION (type0) + == TYPE_PRECISION (long_long_unsigned_type_node)) + cfn = CFN_BUILT_IN_POPCOUNTLL; + } } + (if (cfn == CFN_POPCOUNT) + (IFN_POPCOUNT (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_POPCOUNT) + (BUILT_IN_POPCOUNT (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_POPCOUNTLL) + (BUILT_IN_POPCOUNTLL (convert:type0 @0)))))))) +#endif + /* PARITY simplifications. */ /* parity(~X) is parity(X). */ (simplify @@ -8780,6 +8868,54 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_xor (PARITY:s @0) (PARITY:s @1)) (PARITY (bit_xor @0 @1))) +#if GIMPLE +/* parity(zext(X)) == parity(X). */ +/* parity(sext(X)) == parity(X) if the difference in precision is even. */ +(simplify + (PARITY (convert@1 @0)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1)) + && INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)) + && (TYPE_UNSIGNED (TREE_TYPE (@0)) + || ((TYPE_PRECISION (TREE_TYPE (@1)) + - TYPE_PRECISION (TREE_TYPE (@0))) & 1) == 0)) + (with { combined_fn cfn = CFN_LAST; + tree type0 = TREE_TYPE (@0); + if (TREE_CODE (type0) == BITINT_TYPE) + { + if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE) + cfn = CFN_PARITY; + else + type0 + = build_nonstandard_integer_type (TYPE_PRECISION (type0), + 1); + } + type0 = unsigned_type_for (type0); + if (cfn == CFN_LAST + && direct_internal_fn_supported_p (IFN_PARITY, type0, + OPTIMIZE_FOR_BOTH)) + cfn = CFN_PARITY; + if (cfn == CFN_LAST + && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD + && !direct_internal_fn_supported_p (IFN_PARITY, + TREE_TYPE (@1), + OPTIMIZE_FOR_BOTH)) + { + if (TYPE_PRECISION (type0) + == TYPE_PRECISION (unsigned_type_node)) + cfn = CFN_BUILT_IN_PARITY; + else if (TYPE_PRECISION (type0) + == TYPE_PRECISION (long_long_unsigned_type_node)) + cfn = CFN_BUILT_IN_PARITYLL; + } } + (if (cfn == CFN_PARITY) + (IFN_PARITY (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_PARITY) + (BUILT_IN_PARITY (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_PARITYLL) + (BUILT_IN_PARITYLL (convert:type0 @0)))))))) +#endif + /* a != 0 ? FUN(a) : 0 -> Fun(a) for some builtin functions. */ (for func (POPCOUNT BSWAP FFS PARITY) (simplify @@ -8987,8 +9123,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (plus (CTZ:type (convert:utype @0)) { build_one_cst (type); })))) #endif -(for ffs (BUILT_IN_FFS BUILT_IN_FFSL BUILT_IN_FFSLL - BUILT_IN_FFSIMAX) +(for ffs (FFS) /* __builtin_ffs (X) == 0 -> X == 0. __builtin_ffs (X) == 6 -> (X & 63) == 32. */ (for cmp (eq ne) @@ -9035,6 +9170,50 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) false, prec)); }) { build_zero_cst (TREE_TYPE (@0)); })))))))) +#if GIMPLE +/* ffs(ext(X)) == ffs(X). */ +(simplify + (FFS (convert@1 @0)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1)) + && INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0))) + (with { combined_fn cfn = CFN_LAST; + tree type0 = TREE_TYPE (@0); + if (TREE_CODE (type0) == BITINT_TYPE) + { + if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE) + cfn = CFN_FFS; + else + type0 + = build_nonstandard_integer_type (TYPE_PRECISION (type0), + 0); + } + type0 = signed_type_for (type0); + if (cfn == CFN_LAST + && direct_internal_fn_supported_p (IFN_FFS, type0, + OPTIMIZE_FOR_BOTH)) + cfn = CFN_FFS; + if (cfn == CFN_LAST + && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD + && !direct_internal_fn_supported_p (IFN_FFS, + TREE_TYPE (@1), + OPTIMIZE_FOR_BOTH)) + { + if (TYPE_PRECISION (type0) + == TYPE_PRECISION (integer_type_node)) + cfn = CFN_BUILT_IN_FFS; + else if (TYPE_PRECISION (type0) + == TYPE_PRECISION (long_long_integer_type_node)) + cfn = CFN_BUILT_IN_FFSLL; + } } + (if (cfn == CFN_FFS) + (IFN_FFS (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_FFS) + (BUILT_IN_FFS (convert:type0 @0)) + (if (cfn == CFN_BUILT_IN_FFSLL) + (BUILT_IN_FFSLL (convert:type0 @0)))))))) +#endif + #if GIMPLE /* Simplify: diff --git a/gcc/testsuite/gcc.dg/pr112566-1.c b/gcc/testsuite/gcc.dg/pr112566-1.c new file mode 100644 index 0000000000000000000000000000000000000000..e7672ab5830a085bf96bdb5af94f3e59c2d15abf --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr112566-1.c @@ -0,0 +1,14 @@ +/* PR tree-optimization/112566 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-additional-options "-mbmi2 -mlzcnt -mpopcnt" { target i?86-*-* x86_64-*-* } } */ +/* { dg-final { scan-tree-dump-not "ll \\\(" "optimized" { target ia32 } } } */ +/* { dg-final { scan-tree-dump-not "\\\(long long (unsigned )?int\\\)" "optimized" { target ia32 } } } */ + +int foo (unsigned int x) { return __builtin_ctzll (x); } +int bar (unsigned int x) { return __builtin_popcountll (x); } +int baz (unsigned int x) { return __builtin_parityll (x); } +int qux (int x) { return __builtin_ffsll (x); } +int corge (int x) { return __builtin_ctzll (x); } +int garply (int x) { return __builtin_parityll (x); } +int fred (unsigned int x) { return __builtin_ffsll (x); } diff --git a/gcc/testsuite/gcc.dg/pr112566-2.c b/gcc/testsuite/gcc.dg/pr112566-2.c new file mode 100644 index 0000000000000000000000000000000000000000..acf9ab6d8b12623939b36ab6d65e101b35e2ba00 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr112566-2.c @@ -0,0 +1,12 @@ +/* PR tree-optimization/112566 */ +/* { dg-do compile { target bitint575 } } */ +/* { dg-options "-O2 -fdump-tree-ccp2" } */ +/* { dg-final { scan-tree-dump-not "\\\((unsigned )?_BitInt\\\(512\\\)\\\)" "ccp2" } } */ + +int foo (unsigned _BitInt(256) x) { return __builtin_ctzg ((unsigned _BitInt(512)) x); } +int bar (unsigned _BitInt(256) x) { return __builtin_popcountg ((unsigned _BitInt(512)) x); } +int baz (unsigned _BitInt(256) x) { return __builtin_parityg ((unsigned _BitInt(512)) x); } +int qux (_BitInt(256) x) { return __builtin_ffsg ((_BitInt(512)) x); } +int corge (_BitInt(256) x) { return __builtin_ctzg ((unsigned _BitInt(512)) x); } +int garply (_BitInt(256) x) { return __builtin_parityg ((unsigned _BitInt(512)) x); } +int fred (unsigned _BitInt(256) x) { return __builtin_ffsg ((_BitInt(512)) x); } diff --git a/gcc/testsuite/gcc.target/i386/pr78057.c b/gcc/testsuite/gcc.target/i386/pr78057.c index 493a53332bb1b96df66d70f3c5144597aa79fd40..b1f7a24e7acf34a0b8019f75ceb5db48b2f9d1c7 100644 --- a/gcc/testsuite/gcc.target/i386/pr78057.c +++ b/gcc/testsuite/gcc.target/i386/pr78057.c @@ -5,7 +5,7 @@ extern void link_error (void); int -foo (int x) +foo (int x, long long y) { if (__builtin_ia32_tzcnt_u16 (16) != 4 || __builtin_ia32_tzcnt_u16 (0) != 16 @@ -24,13 +24,14 @@ foo (int x) ) link_error (); x += 2; - if (x == 0) + y += 2; + if (x == 0 || y == 0) return 5; return __builtin_ia32_tzcnt_u32 (x) + __builtin_ia32_lzcnt_u32 (x) #ifdef __x86_64__ - + __builtin_ia32_tzcnt_u64 (x) - + __builtin_ia32_lzcnt_u64 (x) + + __builtin_ia32_tzcnt_u64 (y) + + __builtin_ia32_lzcnt_u64 (y) #endif ; }