This makes us fold (X * 8) & 5 to zero and (X * 6) & 5 to (X * 6) & 4.
It amends the fix for PR52134 in that I noticed we fail to do some
simplifications on size expressions (later on SSA, CCP does the above
transform, though not (yet) changing of the constant).

Bootstrap and regtest ongoing on x86_64-unknown-linux-gnu.

Richard.

2012-05-08  Richard Guenther  <rguent...@suse.de>

        * fold-const.c (fold_binary_loc): Fold (X * CST1) & CST2
        to zero or to (X * CST1) & CST2' when CST1 has trailing zeros.

        * gcc.dg/fold-bitand-4.c: New testcase.

Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c    (revision 187276)
--- gcc/fold-const.c    (working copy)
*************** fold_binary_loc (location_t loc,
*** 11449,11454 ****
--- 11449,11478 ----
            return fold_convert_loc (loc, type, arg0);
        }
  
+       /* Fold (X * CST1) & CST2 to zero if we can, or drop known zero
+          bits from CST2.  */
+       if (TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (arg0) == MULT_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       {
+         int arg1tz
+           = double_int_ctz (tree_to_double_int (TREE_OPERAND (arg0, 1)));
+         if (arg1tz > 0)
+           {
+             double_int arg1mask, masked;
+             arg1mask = double_int_not (double_int_mask (arg1tz));
+             arg1mask = double_int_ext (arg1mask, TYPE_PRECISION (type),
+                                        TYPE_UNSIGNED (type));
+             masked = double_int_and (arg1mask, tree_to_double_int (arg1));
+             if (double_int_zero_p (masked))
+               return omit_two_operands_loc (loc, type, build_zero_cst (type),
+                                             arg0, arg1);
+             else if (!double_int_equal_p (masked, tree_to_double_int (arg1)))
+               return fold_build2_loc (loc, code, type, op0,
+                                       double_int_to_tree (type, masked));
+           }
+       }
+ 
        /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
         ((A & N) + B) & M -> (A + B) & M
         Similarly if (N & M) == 0,
Index: gcc/testsuite/gcc.dg/fold-bitand-4.c
===================================================================
*** gcc/testsuite/gcc.dg/fold-bitand-4.c        (revision 0)
--- gcc/testsuite/gcc.dg/fold-bitand-4.c        (revision 0)
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -fdump-tree-original" } */
+ 
+ int foo (int i)
+ {
+   return (i * 8) & 5;
+ }
+ 
+ unsigned bar (unsigned i)
+ {
+   return (i * 6) & 5;
+ }
+ 
+ /* { dg-final { scan-tree-dump-times "\\\&" 1 "original" } } */
+ /* { dg-final { scan-tree-dump-times "\\\& 4;" 1 "original" } } */
+ /* { dg-final { cleanup-tree-dump "original" } } */

Reply via email to