===================================================================
@@ -11378,6 +11378,43 @@ fold_binary_loc (location_t loc,
fold_build1_loc (loc, BIT_NOT_EXPR, type, tem),
fold_convert_loc (loc, type, arg0));
}
+ /* Fold X & (~X | Y) as X & Y. */
+ if (TREE_CODE (arg1) == BIT_IOR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg1, 0)) == BIT_NOT_EXPR
+ && operand_equal_p (arg0, TREE_OPERAND (TREE_OPERAND (arg1, 0), 0), 0))
+ {
+ tem = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1));
+ return fold_build2_loc (loc, BIT_AND_EXPR, type,
+ fold_convert_loc (loc, type, arg0), tem);
+ }
+ /* Fold X & (Y | ~X) as X & Y. */
+ if (TREE_CODE (arg1) == BIT_IOR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg1, 1)) == BIT_NOT_EXPR
+ && operand_equal_p (arg0, TREE_OPERAND (TREE_OPERAND (arg1, 1), 0), 0))
+ {
+ tem = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0));
+ return fold_build2_loc (loc, BIT_AND_EXPR, type,
+ fold_convert_loc (loc, type, arg0), tem);
+ }
+ /* Fold (~X | Y) & X as X & Y. */
+ if (TREE_CODE (arg0) == BIT_IOR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_NOT_EXPR
+ && operand_equal_p (arg1, TREE_OPERAND (TREE_OPERAND (arg0, 0), 0), 0))
+ {
+ tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
+ return fold_build2_loc (loc, BIT_AND_EXPR, type,
+ fold_convert_loc (loc, type, arg1), tem);
+ }
+ /* Fold (Y | ~X) & X as Y & X. */
+ if (TREE_CODE (arg0) == BIT_IOR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == BIT_NOT_EXPR
+ && operand_equal_p (arg1, TREE_OPERAND (TREE_OPERAND (arg0, 1), 0), 0))
+ {
+ tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+ return fold_build2_loc (loc, BIT_AND_EXPR, type,
+ tem, fold_convert_loc (loc, type, arg1));
+ }
+
/* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
((A & N) + B) & M -> (A + B) & M
===================================================================
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-original" } */
+
+int f(int y, int x)
+{
+ return x & ((~x) | y);
+}
+int f1(int y, int x)
+{
+ return x & (y | (~x));
+}
+int f2(int y, int x)
+{
+ return ((~x) | y) & x;
+}
+int f3(int y, int x)
+{
+ return (y | (~x)) & x;
+}
+
+
+/* { dg-final { scan-tree-dump-times "~x" 0 "original" } } */
+/* { dg-final { scan-tree-dump-times "x \& y" 4 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */