===================================================================
@@ -59,6 +59,8 @@ static void remove_stmt_chain (tree);
it would promote the reassociation of adds.
1.2. Breaking up to normalized form for bitwise-not operations
on bitwise-binary and for bitwise-not operation on compares.
+ 1.3 Breaking up combined expression made out of boolean-typed bitwise
+ expressions for improving simplification.
2. Left linearization of the expression trees, so that (A+B)+(C+D)
becomes (((A+B)+C)+D), which is easier for us to rewrite later.
@@ -712,8 +714,89 @@ expand_not_bitwise_binary (tree type, tr
NULL_TREE, expr);
}
+/* Routine to expand (X | Y) ==/!= 0 and doing
+ simplification on (X cmp Y) ==/!= 0.
+ - (X | Y) == 0 to (X == 0) & (Y == 0)
+ - (X | Y) != 0 to (X != 0) | (Y != 0).
+ - (X cmp Y) == 0 to (X cmp' Y) with cmp'=invert of cmp.
+ - (X cmp Y) != 0 to (X cmp Y).
+
+ The argument CODE can be either NE_EXPR, or EQ_EXPR. It indicates
+ what kind of expansion is performed. */
+
+static tree
+expand_cmp_ior (tree op, tree type, enum tree_code code)
+{
+ tree op1, op2;
+ gimple s = NULL;
+ enum tree_code hcode;
+
+ /* Handle integral constant value case. */
+ if (TREE_CODE (op) == INTEGER_CST)
+ {
+ if (code == EQ_EXPR)
+ return fold_convert (type, (integer_zerop (op) ? integer_one_node
+ : integer_zero_node));
+ return fold_convert (type, (!integer_zerop (op) ? integer_one_node
+ : integer_zero_node));
+ }
+
+ /* If operand OP isn't a gimple-assign, or has non-single use,
+ then simply creat a comparison != 0 for it. */
+ if (TREE_CODE (op) != SSA_NAME
+ || !(s = SSA_NAME_DEF_STMT (op))
+ || !is_gimple_assign (s)
+ || !has_single_use (op))
+ return make_new_tmp_statement (type, code, op,
+ build_zero_cst (TREE_TYPE (op)), s);
+
+ hcode = gimple_assign_rhs_code (s);
+
+ /* Operand code of OP isn't of comparison kind, and not
+ a bitwise-not, then creat a comparison != 0 for it. */
+ if (TREE_CODE_CLASS (hcode) != tcc_comparison
+ && hcode != BIT_IOR_EXPR)
+ return make_new_tmp_statement (type, code, op,
+ build_zero_cst (TREE_TYPE (op)), s);
+
+ op1 = gimple_assign_rhs1 (s);
+ op2 = gimple_assign_rhs2 (s);
+
+ /* Simplify (X cmp Y) != 0 -> (X cmp Y), and
+ (X cmp Y) == 0 -> X cnp' Y, with cmp' = inverted cmp. */
+ if (TREE_CODE_CLASS (hcode) == tcc_comparison)
+ {
+ tree op1type = TREE_TYPE (op1);
+
+ if (code == EQ_EXPR)
+ {
+ enum tree_code ncode;
+ ncode = invert_tree_comparison (hcode,
+ HONOR_NANS (TYPE_MODE (op1type)));
+ if (ncode != ERROR_MARK)
+ return make_new_tmp_statement (type, ncode, op1, op2, s);
+ }
+ else
+ return make_new_tmp_statement (type, hcode, op1, op2, s);
+ }
+
+ /* Break up (X | Y) ==/!= 0 case. */
+ if (hcode == BIT_IOR_EXPR)
+ {
+ op1 = expand_cmp_ior (op1, type, code);
+ op2 = expand_cmp_ior (op2, type, code);
+ return make_new_tmp_statement (type, (code == EQ_EXPR ? BIT_AND_EXPR
+ : BIT_IOR_EXPR),
+ op1, op2, s);
+ }
+ return make_new_tmp_statement (type, code, op,
+ build_zero_cst (TREE_TYPE (op)), s);
+}
+
+
/* Break up STMT if it is a combined statement made out of
- bitwise operations. Handle expansion of ~(A op B). */
+ bitwise operations. Handle expansion of ~(A op B), and
+ (A | B) !=/== 0. */
static bool
break_up_bitwise_combined_stmt (gimple stmt)
@@ -728,9 +811,13 @@ break_up_bitwise_combined_stmt (gimple s
old_op1 = op1;
old_op2 = op2 = NULL_TREE;
+ if (code == EQ_EXPR || code == NE_EXPR)
+ old_op2 = op2 = gimple_assign_rhs2 (stmt);
+
/* Check that CODE can be handled and that left-hand operand
is of kind SSA_NAME. */
- if (code != BIT_NOT_EXPR
+ if ((code != BIT_NOT_EXPR
+ && code != EQ_EXPR && code != NE_EXPR)
|| TREE_CODE (op1) != SSA_NAME)
return false;
@@ -742,8 +829,42 @@ break_up_bitwise_combined_stmt (gimple s
|| !has_single_use (op1))
return false;
- /* Handle expansion for ~X. */
- if (code == BIT_NOT_EXPR)
+ if (code == NE_EXPR || code == EQ_EXPR)
+ {
+ tree inner_op1, inner_op2;
+
+ /* Check that operands have integral type and
+ see if it has as second argument a constant zero valued
+ operand. */
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (op1))
+ || TREE_CODE (op2) != INTEGER_CST
+ || !integer_zerop (op2))
+ return false;
+
+ /* Check for pattern X | Y == 0 and X | Y != 0 */
+ if (gimple_assign_rhs_code (op1_def) != BIT_IOR_EXPR)
+ return false;
+
+ inner_op1 = gimple_assign_rhs1 (op1_def);
+ inner_op2 = gimple_assign_rhs2 (op1_def);
+
+ /* Expand (X | Y) == 0 -> (X == 0) & (Y == 0)
+ and (X | Y) != 0 -> (X != 0) | (Y != 0) */
+
+ op1 = expand_cmp_ior (inner_op1, type, code);
+ op2 = expand_cmp_ior (inner_op2, type, code);
+
+ gsi = gsi_for_stmt (stmt);
+ gimple_assign_set_rhs_with_ops (&gsi, (code == NE_EXPR ? BIT_IOR_EXPR
+ : BIT_AND_EXPR),
+ op1, op2);
+ update_stmt (gsi_stmt (gsi));
+ remove_stmt_chain (old_op1);
+ remove_stmt_chain (old_op2);
+ return true;
+ }
+ /* Handle expansion for expansion of ~X. */
+ else if (code == BIT_NOT_EXPR)
{
enum tree_code inner_code = gimple_assign_rhs_code (op1_def);
@@ -3091,6 +3212,10 @@ can_reassociate_p (tree op)
If A or B are comparisons or are bitwise-not statement, then sink bit-not
into expression, if it is a single-use statement.
+ Break up (X | Y) == 0 into (X == 0) & (Y == 0).
+
+ Break up (X | Y) != 0 into (X != 0) | (Y != 0).
+
En passant, clear the GIMPLE visited flag on every statement. */
static void
===================================================================
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -ffast-math" } */
+
+int foo (int a, int b, int c, int d)
+{
+ int r1 = (a | b | c) == 0;
+ int r2 = (a | d | c) != 0 | b == 0;
+ return (r1 == 0 | r2 != 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
===================================================================
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -ffast-math" } */
+
+int foo (int a, int b, int c, int d)
+{
+ int r1 = a != 0 & c != 0 & b != 0;
+ int r2 = a == 0 | b != 0 | d == 0;
+ return (r1 == 0 | r2 != 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
===================================================================
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -ffast-math" } */
+
+int foo (int a, int b, int c, int d)
+{
+ int r1 = a != 0 & c != 0 & b != 0;
+ int r2 = a == 0 | b != 0 | d == 0;
+ return (r1 != 0 & r2 == 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+