diff --git a/gcc/match.pd b/gcc/match.pd index b9621a47cdf16c924054080867d82cb1188bd9a3..17613ec8ade4f8142b36472c6ad52e430da37639 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4906,6 +4906,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) - TYPE_PRECISION (TREE_TYPE (@2))))) (bit_and (convert @0) (lshift { build_minus_one_cst (type); } @1)))) +#if GIMPLE +/* (X >> C1) << (C1 + C2) -> X << C2 if the low C1 bits of X are zero. */ +(simplify + (lshift (convert? (rshift (with_possible_nonzero_bits2 @0) INTEGER_CST@1)) + INTEGER_CST@2) + (if (INTEGRAL_TYPE_P (type) + && wi::ltu_p (wi::to_wide (@1), element_precision (type)) + && wi::ltu_p (wi::to_wide (@2), element_precision (type)) + && wi::to_widest (@2) >= wi::to_widest (@1) + && wi::to_widest (@1) <= wi::ctz (get_nonzero_bits (@0))) + (lshift (convert @0) (minus @2 @1)))) +#endif + /* For (x << c) >> c, optimize into x & ((unsigned)-1 >> c) for unsigned x OR truncate into the precision(type) - c lowest bits of signed x (if they have mode precision or a precision of 1). */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c b/gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c new file mode 100644 index 0000000000000000000000000000000000000000..d88500ca8ddfecbf5f7337db6e9ffaede5281245 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c @@ -0,0 +1,61 @@ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ + +unsigned int +f1 (unsigned int x) +{ + if (x & 3) + __builtin_unreachable (); + x >>= 2; + return x << 3; +} + +unsigned int +f2 (unsigned int x) +{ + if (x & 3) + __builtin_unreachable (); + unsigned char y = x; + y >>= 2; + return y << 3; +} + +unsigned long +f3 (unsigned int x) +{ + if (x & 3) + __builtin_unreachable (); + x >>= 2; + return (unsigned long) x << 3; +} + +int +f4 (int x) +{ + if (x & 15) + __builtin_unreachable (); + x >>= 4; + return x << 5; +} + +unsigned int +f5 (int x) +{ + if (x & 31) + __builtin_unreachable (); + x >>= 5; + return x << 6; +} + +unsigned int +f6 (unsigned int x) +{ + if (x & 1) + __builtin_unreachable (); + x >>= 1; + return x << (sizeof (int) * __CHAR_BIT__ - 1); +} + +/* { dg-final { scan-tree-dump-not {<[a-z]*_div_expr,} "optimized" } } */ +/* { dg-final { scan-tree-dump-not {<rshift_expr,} "optimized" } } */ +/* { dg-final { scan-tree-dump-times {<lshift_expr, [^,]*, [^,]*, 1,} 5 "optimized" } } */ +/* { dg-final { scan-tree-dump {<lshift_expr, [^,]*, [^,]*, 30,} "optimized" { target int32 } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c b/gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c new file mode 100644 index 0000000000000000000000000000000000000000..67ba4a75aec4d749b046f40ea55ff55f950b7bb0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c @@ -0,0 +1,21 @@ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ + +unsigned int +f1 (unsigned int x) +{ + if (x & 3) + __builtin_unreachable (); + x >>= 3; + return x << 4; +} + +unsigned int +f2 (unsigned int x) +{ + if (x & 3) + __builtin_unreachable (); + x >>= 2; + return x << 1; +} + +/* { dg-final { scan-tree-dump-times {<rshift_expr,} 2 "optimized" } } */