re PR tree-optimization/41442 (missed optimization for boolean expression)
authorBernd Schmidt <bernds@codesourcery.com>
Sat, 24 Apr 2010 18:53:47 +0000 (18:53 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Sat, 24 Apr 2010 18:53:47 +0000 (18:53 +0000)
gcc/
PR tree-optimization/41442
* fold-const.c (merge_truthop_with_opposite_arm): New function.
(fold_binary_loc): Call it.

gcc/testsuite/
PR tree-optimization/41442
* gcc.target/i386/pr41442.c: New test.

From-SVN: r158689

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr41442.c [new file with mode: 0644]

index 2ec92ea6583e91da2edebb5aa4ef8be7bd242b96..9e1a30a101b84ee5c75d0412efba5af579d94698 100644 (file)
@@ -1,3 +1,9 @@
+2010-04-24  Bernd Schmidt  <bernds@codesourcery.com>
+
+       PR tree-optimization/41442
+       * fold-const.c (merge_truthop_with_opposite_arm): New function.
+       (fold_binary_loc): Call it.
+
 2010-04-23  Manuel López-Ibáñez  <manu@gcc.gnu.org>
 
        * toplev.c (general_init): Set default for
index cdae661733c5b4e59e93745e3529e08b5325e255..ffd9d30ef2e0a873bef76a4c7347d0bece934773 100644 (file)
@@ -4997,6 +4997,76 @@ unextend (tree c, int p, int unsignedp, tree mask)
                       const_binop (BIT_XOR_EXPR, c, temp, 0));
 }
 \f
+/* For an expression that has the form
+     (A && B) || ~B
+   or
+     (A || B) && ~B,
+   we can drop one of the inner expressions and simplify to
+     A || ~B
+   or
+     A && ~B
+   LOC is the location of the resulting expression.  OP is the inner 
+   logical operation; the left-hand side in the examples above, while CMPOP
+   is the right-hand side.  RHS_ONLY is used to prevent us from accidentally
+   removing a condition that guards another, as in
+     (A != NULL && A->...) || A == NULL
+   which we must not transform.  If RHS_ONLY is true, only eliminate the
+   right-most operand of the inner logical operation.  */
+
+static tree
+merge_truthop_with_opposite_arm (location_t loc, tree op, tree cmpop,
+                                bool rhs_only)
+{
+  tree type = TREE_TYPE (cmpop);
+  enum tree_code code = TREE_CODE (cmpop);
+  enum tree_code truthop_code = TREE_CODE (op);
+  tree lhs = TREE_OPERAND (op, 0);
+  tree rhs = TREE_OPERAND (op, 1);
+  tree orig_lhs = lhs, orig_rhs = rhs;
+  enum tree_code rhs_code = TREE_CODE (rhs);
+  enum tree_code lhs_code = TREE_CODE (lhs);
+  enum tree_code inv_code;
+
+  if (TREE_SIDE_EFFECTS (op) || TREE_SIDE_EFFECTS (cmpop))
+    return NULL_TREE;
+
+  if (TREE_CODE_CLASS (code) != tcc_comparison)
+    return NULL_TREE;
+
+  if (rhs_code == truthop_code)
+    {
+      tree newrhs = merge_truthop_with_opposite_arm (loc, rhs, cmpop, rhs_only);
+      if (newrhs != NULL_TREE)
+       {
+         rhs = newrhs;
+         rhs_code = TREE_CODE (rhs);
+       }
+    }
+  if (lhs_code == truthop_code && !rhs_only)
+    {
+      tree newlhs = merge_truthop_with_opposite_arm (loc, lhs, cmpop, false);
+      if (newlhs != NULL_TREE)
+       {
+         lhs = newlhs;
+         lhs_code = TREE_CODE (lhs);
+       }
+    }
+
+  inv_code = invert_tree_comparison (code, HONOR_NANS (TYPE_MODE (type)));
+  if (inv_code == rhs_code
+      && operand_equal_p (TREE_OPERAND (rhs, 0), TREE_OPERAND (cmpop, 0), 0)
+      && operand_equal_p (TREE_OPERAND (rhs, 1), TREE_OPERAND (cmpop, 1), 0))
+    return lhs;
+  if (!rhs_only && inv_code == lhs_code
+      && operand_equal_p (TREE_OPERAND (lhs, 0), TREE_OPERAND (cmpop, 0), 0)
+      && operand_equal_p (TREE_OPERAND (lhs, 1), TREE_OPERAND (cmpop, 1), 0))
+    return rhs;
+  if (rhs != orig_rhs || lhs != orig_lhs)
+    return fold_build2_loc (loc, truthop_code, TREE_TYPE (cmpop),
+                           lhs, rhs);
+  return NULL_TREE;
+}
+
 /* Find ways of folding logical expressions of LHS and RHS:
    Try to merge two comparisons to the same innermost item.
    Look for range tests like "ch >= '0' && ch <= '9'".
@@ -11833,6 +11903,22 @@ fold_binary_loc (location_t loc,
       if (0 != (tem = fold_range_test (loc, code, type, op0, op1)))
        return tem;
 
+      if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR)
+         || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == TRUTH_ANDIF_EXPR))
+       {
+         tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true);
+         if (tem)
+           return fold_build2_loc (loc, code, type, tem, arg1);
+       }
+
+      if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR)
+         || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == TRUTH_ANDIF_EXPR))
+       {
+         tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false);
+         if (tem)
+           return fold_build2_loc (loc, code, type, arg0, tem);
+       }
+
       /* Check for the possibility of merging component references.  If our
         lhs is another similar operation, try to merge its rhs with our
         rhs.  Then try to merge our lhs and rhs.  */
index 26ae3d0bee0278dc871f3ef503427e4ad9983945..0133717fc204a964e1587b866f256b247c43fcb4 100644 (file)
@@ -1,3 +1,8 @@
+2010-04-24  Bernd Schmidt  <bernds@codesourcery.com>
+
+       PR tree-optimization/41442
+       * gcc.target/i386/pr41442.c: New test.
+
 2010-04-24  Hans-Peter Nilsson  <hp@axis.com>
 
        PR fortran/43832
diff --git a/gcc/testsuite/gcc.target/i386/pr41442.c b/gcc/testsuite/gcc.target/i386/pr41442.c
new file mode 100644 (file)
index 0000000..feae791
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef struct LINK link;
+struct LINK
+{
+    link* next;
+};
+
+int haha(link* p1, link* p2)
+{
+  if ((p1->next && !p2->next) || p2->next)
+    return 0;
+
+  return 1;
+}
+
+/* { dg-final { scan-assembler-times "test|cmp" 2 } } */