Index: gcc/gcc/tree-ssa-reassoc.c
===================================================================
--- gcc.orig/gcc/tree-ssa-reassoc.c	2011-05-19 14:25:10.404289600 +0200
+++ gcc/gcc/tree-ssa-reassoc.c	2011-05-19 14:26:11.088817100 +0200
@@ -41,6 +41,10 @@ along with GCC; see the file COPYING3.
 #include "cfgloop.h"
 #include "flags.h"
 
+/* Forward declarations of some helper routines.  */
+static gimple build_and_add_sum (tree , tree , tree , enum tree_code);
+static void remove_visited_stmt_chain (tree);
+
 /*  This is a simple global reassociation pass.  It is, in part, based
     on the LLVM pass of the same name (They do some things more/less
     than we do, in different orders, etc).
@@ -411,6 +415,236 @@ get_unary_op (tree name, enum tree_code
   return NULL_TREE;
 }
 
+/* Checks if a type is based on a BOOLEAN_TYPE, and or has 1-bit precision.
+   This check is necessary to detect ADA's 8-bit unsigned boolean types
+   proper.
+   If type is of kind boolean or compatible, TRUE is returned.  Otherwise
+   FALSE.  */
+
+static bool
+is_boolean_compatible_type_p (tree type)
+{
+  if (!type)
+    return false;
+
+  if (TYPE_PRECISION (type) == 1)
+    return true;
+
+  /* We try to look here into inner type, as ADA uses
+     boolean_type_node with type precision != 1.  */
+  while (TREE_TYPE (type)
+        && (TREE_CODE (type) == INTEGER_TYPE
+            || TREE_CODE (type) == REAL_TYPE))
+    type = TREE_TYPE (type);
+
+  return TYPE_PRECISION (type) == 1 || TREE_CODE (type) == BOOLEAN_TYPE;
+}
+
+/* This routine checks for (A | B) != 0 and (A | B) == 0.
+   If found TRUE is returned, otherwise FALSE.  */
+
+static bool
+is_ior_ne_eq_cmp (gimple stmt)
+{
+  gimple s;
+  tree op1, op2;
+  enum tree_code code;
+
+  if (!is_gimple_assign (stmt))
+    return false;
+  code = gimple_assign_rhs_code (stmt);
+  if (code != NE_EXPR && code != EQ_EXPR)
+    return false;
+  op1 = gimple_assign_rhs1 (stmt);
+  op2 = gimple_assign_rhs2 (stmt);
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (op2)) || !integer_zerop (op2))
+    return false;
+  if (TREE_CODE (op1) != SSA_NAME)
+    return false;
+  s = SSA_NAME_DEF_STMT (op1);
+  if (!is_gimple_assign (s) || gimple_assign_rhs_code (s) != BIT_IOR_EXPR)
+    return false;
+
+  return true;
+}
+
+/* This helper routine for build_expand_ne_eq_cmp () expands (A | B) != 0
+   to A != 0 || B != 0, and (A | B) == 0 to A == 0 && B == 0 to allow later
+   association to eliminate duplicates and do inverse operation.  */
+
+static tree
+build_inner_expand_ne_eq_cmp (tree op, tree zero, enum tree_code cmp_code)
+{
+  tree op1a, op1b, tmpvar;
+  gimple sum, s = NULL;
+  bool is_gimple = false;
+
+  if (TREE_CODE (op) == SSA_NAME
+      && is_gimple_assign ((s = SSA_NAME_DEF_STMT (op))))
+    is_gimple = true;
+
+  if (is_gimple
+      && gimple_assign_rhs_code (s) == BIT_IOR_EXPR)
+    {
+      op1a = build_inner_expand_ne_eq_cmp (gimple_assign_rhs1 (s),
+      					   zero, cmp_code);
+      op1b = build_inner_expand_ne_eq_cmp (gimple_assign_rhs2 (s),
+      					   zero, cmp_code);
+      tmpvar = create_tmp_reg (boolean_type_node, NULL);
+      add_referenced_var (tmpvar);
+      sum = build_and_add_sum (tmpvar, op1a, op1b,
+      			       (cmp_code == NE_EXPR ? BIT_IOR_EXPR
+						    : BIT_AND_EXPR));
+      op1a = gimple_get_lhs (sum);
+    }
+  else if (cmp_code == NE_EXPR
+	   && is_boolean_compatible_type_p (TREE_TYPE (op)))
+    return op;
+  else if (cmp_code == NE_EXPR && is_gimple && gimple_assign_cast_p (s)
+  	   && is_boolean_compatible_type_p
+		(TREE_TYPE (gimple_assign_rhs1 (s))))
+    return gimple_assign_rhs1 (s);
+  else
+    {
+      tmpvar = create_tmp_reg (boolean_type_node, NULL);
+      add_referenced_var (tmpvar);
+      sum = build_and_add_sum (tmpvar, op, zero, cmp_code);
+      op1a = gimple_get_lhs (sum);
+    }
+  return op1a;
+}
+
+/* This routine expands (A | B) != 0 to A != 0 || B != 0,
+   and (A | B) == 0 to A == 0 && B == 0 to allow later
+   association to eliminate duplicates and do inverse
+   operation.  */
+
+static void
+build_expand_ne_eq_cmp (gimple stmt)
+{
+  gimple_stmt_iterator gsi;
+  gimple s;
+  tree op1, op2, op1a, op1b, type;
+  enum tree_code code;
+
+  code = gimple_assign_rhs_code (stmt);
+  op1 = gimple_assign_rhs1 (stmt);
+  op2 = gimple_assign_rhs2 (stmt);
+  s = SSA_NAME_DEF_STMT (op1);
+
+  /* (X | Y) != 0 or (X | Y) == 0.  */
+  type = TREE_TYPE (gimple_assign_lhs (stmt));
+  op1a = gimple_assign_rhs1 (s);
+  op1b = gimple_assign_rhs2 (s);
+
+  op1a = build_inner_expand_ne_eq_cmp (op1a, op2, code);
+  op1b = build_inner_expand_ne_eq_cmp (op1b, op2, code);
+
+  if (is_boolean_compatible_type_p (type))
+    op1 = fold_build2 ((code == NE_EXPR ? BIT_IOR_EXPR : BIT_AND_EXPR),
+		       type, op1a, op1b);
+  else
+    {
+      gimple sum;
+      tree tmpvar = create_tmp_reg (boolean_type_node, NULL);
+      add_referenced_var (tmpvar);
+      sum = build_and_add_sum (tmpvar, op1a, op1b,
+			       (code == NE_EXPR ? BIT_IOR_EXPR
+						: BIT_AND_EXPR));
+      op1 = gimple_get_lhs (sum);
+      op1 = fold_convert (type, op1);
+    }
+
+  op1a = gimple_assign_rhs1 (stmt);
+  op1b = gimple_assign_rhs2 (stmt);
+  gsi = gsi_for_stmt (stmt);
+  gimple_assign_set_rhs_from_tree (&gsi, op1);
+  update_stmt (stmt);
+  remove_visited_stmt_chain (op1a);
+  remove_visited_stmt_chain (op1b);
+}
+
+/* This helper function converts (A | B) != 0 and (A | B) == 0 to their
+   binary sequence .  Additionally it walks binary &, |, and ^ trees
+   for making sure to expand operations and it tries to do a type sink
+   for boolean based expressions in SSA form like:
+     D1 = (int) BOOL-COND1
+     D2 = (int) BOOL-COND2
+     D3 = D1 | D2
+   into
+     D1 = BOOL-COND1 | BOOL-COND2
+     D2 = (int) D1
+   */
+
+static bool
+sink_cast_and_expand (gimple stmt)
+{
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  tree type, op1, op2;
+  gimple s1, s2;
+  bool ret = false;
+
+  if (is_ior_ne_eq_cmp (stmt))
+    {
+      build_expand_ne_eq_cmp (stmt);
+      return true;
+    }
+
+  if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR
+      && code != BIT_XOR_EXPR)
+    return false;
+  type = TREE_TYPE (gimple_assign_lhs (stmt));
+
+  op1 = gimple_assign_rhs1 (stmt);
+  if (TREE_CODE (op1) != SSA_NAME)
+    return false;
+  op2 = gimple_assign_rhs2 (stmt);
+  if (TREE_CODE (op2) != SSA_NAME)
+    return false;
+  s1 = SSA_NAME_DEF_STMT (op1);
+  if (!is_gimple_assign (s1))
+    return false;
+  if (sink_cast_and_expand (s1))
+    ret = true;
+  s2 = SSA_NAME_DEF_STMT (op2);
+  if (!is_gimple_assign (s2))
+    return ret;
+  if (sink_cast_and_expand (s2))
+    ret = true;
+
+  if (is_boolean_compatible_type_p (type))
+    return ret;
+  if (gimple_assign_cast_p (s1)
+      && gimple_assign_cast_p (s2)
+      && is_boolean_compatible_type_p (TREE_TYPE (gimple_assign_rhs1 (s1)))
+      && is_boolean_compatible_type_p (TREE_TYPE (gimple_assign_rhs1 (s2)))
+      && useless_type_conversion_p (TREE_TYPE (gimple_assign_rhs1 (s1)),
+      				    TREE_TYPE (gimple_assign_rhs1 (s2))))
+    {
+      gimple_stmt_iterator gsi;
+      gimple sum;
+      tree op1a, op1b, tmpvar;
+
+      tmpvar = create_tmp_reg (TREE_TYPE (gimple_assign_rhs1 (s1)), NULL);
+
+      add_referenced_var (tmpvar);
+      sum = build_and_add_sum (tmpvar, gimple_assign_rhs1 (s1),
+      			       gimple_assign_rhs1 (s2), code);
+      op1 = gimple_get_lhs (sum);
+      op1 = fold_convert (type, op1);
+      
+      op1a = gimple_assign_rhs1 (stmt);
+      op1b = gimple_assign_rhs2 (stmt);
+      gsi = gsi_for_stmt (stmt);
+      gimple_assign_set_rhs_from_tree (&gsi, op1);
+      update_stmt (stmt);
+      remove_visited_stmt_chain (op1a);
+      remove_visited_stmt_chain (op1b);
+      ret = true;
+    }
+  return ret;
+}
+
 /* If CURR and LAST are a pair of ops that OPCODE allows us to
    eliminate through equivalences, do so, remove them from OPS, and
    return true.  Otherwise, return false.  */
@@ -872,9 +1106,9 @@ zero_one_operation (tree *def, enum tree
   while (1);
 }
 
-/* Builds one statement performing OP1 OPCODE OP2 using TMPVAR for
-   the result.  Places the statement after the definition of either
-   OP1 or OP2.  Returns the new statement.  */
+/* Builds one statement performing OP1 OPCODE OP2, or UNARY-OPCODE OP1
+   using TMPVAR for the result.  Places the statement after the definition
+   of either OP1 or - for binary OPCODE - OP2 .  Returns the new statement.  */
 
 static gimple
 build_and_add_sum (tree tmpvar, tree op1, tree op2, enum tree_code opcode)
@@ -892,7 +1126,7 @@ build_and_add_sum (tree tmpvar, tree op1
   /* Find an insertion place and insert.  */
   if (TREE_CODE (op1) == SSA_NAME)
     op1def = SSA_NAME_DEF_STMT (op1);
-  if (TREE_CODE (op2) == SSA_NAME)
+  if (op2 && TREE_CODE (op2) == SSA_NAME)
     op2def = SSA_NAME_DEF_STMT (op2);
   if ((!op1def || gimple_nop_p (op1def))
       && (!op2def || gimple_nop_p (op2def)))
@@ -1223,11 +1457,11 @@ eliminate_redundant_comparison (enum tre
 				unsigned int currindex,
 				operand_entry_t curr)
 {
-  tree op1, op2;
+  tree op1, op2, matched = NULL_TREE, matched_op = NULL_TREE;
   enum tree_code lcode, rcode;
   gimple def1, def2;
-  int i;
   operand_entry_t oe;
+  int i, matched_i = 0;
 
   if (opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR)
     return false;
@@ -1294,42 +1528,84 @@ eliminate_redundant_comparison (enum tre
 	    continue;
 	}
 
+      /* If a duplicate was found, remove it and continue search.  */
+      if (TREE_CODE (t) != INTEGER_CST && operand_equal_p (t, curr->op, 0))
+        {
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      fprintf (dump_file, "Equivalence: ");
+	      print_generic_expr (dump_file, curr->op, 0);
+	      fprintf (dump_file, " %s ", op_symbol_code (opcode));
+	      print_generic_expr (dump_file, oe->op, 0);
+	      fprintf (dump_file, " -> ");
+	      print_generic_expr (dump_file, t, 0);
+	      fprintf (dump_file, "\n");
+	    }
+
+	  /* Now we can delete oe, as it has been subsumed by the new combined
+	     expression t.  */
+	  VEC_ordered_remove (operand_entry_t, *ops, i);
+	  reassociate_stats.ops_eliminated ++;
+
+	  /* Continue search, we might have another duplicate in list.  We
+	     don't break here to allow further duplicate elimination.  Also
+	     iteration might continue on next statement, when no further
+	     optimization for the current element is possible.  */
+	  --i;
+	  continue;
+        }
+      if (TREE_CODE (t) == INTEGER_CST)
+        {
+	  matched = t;
+	  matched_i = i;
+	  matched_op = oe->op;
+	  break;
+	}
+
+      if (matched)
+        continue;
+      matched = t;
+      matched_i = i;
+      matched_op = oe->op;
+    }
+
+  if (matched)
+    {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	{
 	  fprintf (dump_file, "Equivalence: ");
 	  print_generic_expr (dump_file, curr->op, 0);
 	  fprintf (dump_file, " %s ", op_symbol_code (opcode));
-	  print_generic_expr (dump_file, oe->op, 0);
+	  print_generic_expr (dump_file, matched_op, 0);
 	  fprintf (dump_file, " -> ");
-	  print_generic_expr (dump_file, t, 0);
+	  print_generic_expr (dump_file, matched, 0);
 	  fprintf (dump_file, "\n");
 	}
 
       /* Now we can delete oe, as it has been subsumed by the new combined
-         expression t.  */
-      VEC_ordered_remove (operand_entry_t, *ops, i);
+	 expression t.  */
+      VEC_ordered_remove (operand_entry_t, *ops, matched_i);
       reassociate_stats.ops_eliminated ++;
-
-      /* If t is the same as curr->op, we're done.  Otherwise we must
+      /* If matched is the same as curr->op, we're done.  Otherwise we must
 	 replace curr->op with t.  Special case is if we got a constant
 	 back, in which case we add it to the end instead of in place of
 	 the current entry.  */
-      if (TREE_CODE (t) == INTEGER_CST)
+      if (TREE_CODE (matched) == INTEGER_CST)
 	{
 	  VEC_ordered_remove (operand_entry_t, *ops, currindex);
-	  add_to_ops_vec (ops, t);
+	  add_to_ops_vec (ops, matched);
 	}
-      else if (!operand_equal_p (t, curr->op, 0))
+      else if (!operand_equal_p (matched, curr->op, 0))
 	{
 	  tree tmpvar;
 	  gimple sum;
 	  enum tree_code subcode;
 	  tree newop1;
 	  tree newop2;
-	  gcc_assert (COMPARISON_CLASS_P (t));
-	  tmpvar = create_tmp_var (TREE_TYPE (t), NULL);
+	  gcc_assert (COMPARISON_CLASS_P (matched));
+	  tmpvar = create_tmp_var (TREE_TYPE (matched), NULL);
 	  add_referenced_var (tmpvar);
-	  extract_ops_from_tree (t, &subcode, &newop1, &newop2);
+	  extract_ops_from_tree (matched, &subcode, &newop1, &newop2);
 	  STRIP_USELESS_TYPE_CONVERSION (newop1);
 	  STRIP_USELESS_TYPE_CONVERSION (newop2);
 	  gcc_checking_assert (is_gimple_val (newop1)
@@ -1975,8 +2251,11 @@ can_reassociate_p (tree op)
   return false;
 }
 
-/* Break up subtract operations in block BB.
+/* Break up subtract operations, normalize compare or operations, and
+   do type sinking for boolean based binary or/and/xor operations in
+   block BB.
 
+   For substract:
    We do this top down because we don't know whether the subtract is
    part of a possible chain of reassociation except at the top.
 
@@ -1987,32 +2266,46 @@ can_reassociate_p (tree op)
    q = b - r
    k = t - q
 
-   we want to break up k = t - q, but we won't until we've transformed q
+   We want to break up k = t - q, but we won't until we've transformed q
    = b - r, which won't be broken up until we transform b = c - d.
 
+   Compare operations:
+   For being able to reassoc in and/or/xor operations for optimized
+   comparison, we need to break up (A | B) == 0 to (A == 0 && B == 0)
+   and (A | B) != 0 to (A != 0 || B != 0).
+
    En passant, clear the GIMPLE visited flag on every statement.  */
 
 static void
-break_up_subtract_bb (basic_block bb)
+break_up_operation_bb (basic_block bb)
 {
   gimple_stmt_iterator gsi;
   basic_block son;
 
-  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
     {
       gimple stmt = gsi_stmt (gsi);
       gimple_set_visited (stmt, false);
 
+      if (is_gimple_assign (stmt) && sink_cast_and_expand (stmt))
+	continue;
+
       if (!is_gimple_assign (stmt)
 	  || !can_reassociate_p (gimple_assign_lhs (stmt)))
-	continue;
+	{
+	  gsi_next (&gsi);
+	  continue;
+	}
 
       /* Look for simple gimple subtract operations.  */
       if (gimple_assign_rhs_code (stmt) == MINUS_EXPR)
 	{
 	  if (!can_reassociate_p (gimple_assign_rhs1 (stmt))
 	      || !can_reassociate_p (gimple_assign_rhs2 (stmt)))
-	    continue;
+	    {
+	      gsi_next (&gsi);
+	      continue;
+	    }
 
 	  /* Check for a subtract used only in an addition.  If this
 	     is the case, transform it into add of a negate for better
@@ -2024,11 +2317,12 @@ break_up_subtract_bb (basic_block bb)
       else if (gimple_assign_rhs_code (stmt) == NEGATE_EXPR
 	       && can_reassociate_p (gimple_assign_rhs1 (stmt)))
 	VEC_safe_push (tree, heap, plus_negates, gimple_assign_lhs (stmt));
+      gsi_next (&gsi);
     }
   for (son = first_dom_son (CDI_DOMINATORS, bb);
        son;
        son = next_dom_son (CDI_DOMINATORS, son))
-    break_up_subtract_bb (son);
+    break_up_operation_bb (son);
 }
 
 /* Reassociate expressions in basic block BB and its post-dominator as
@@ -2180,7 +2474,7 @@ debug_ops_vector (VEC (operand_entry_t,
 static void
 do_reassoc (void)
 {
-  break_up_subtract_bb (ENTRY_BLOCK_PTR);
+  break_up_operation_bb (ENTRY_BLOCK_PTR);
   reassociate_bb (EXIT_BLOCK_PTR);
 }
 
Index: gcc/gcc/testsuite/gcc.dg/binop-tand1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tand1.c	2011-05-19 14:28:19.980184200 +0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  return ((!a && !b) && c && b && c && a);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tand2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tand2.c	2011-05-19 14:28:19.982184500 +0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  return (a != 0 && b != 0 && ((a | b) == 0) && c != 0) ? 1 : 0;
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tand4.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tand4.c	2011-05-19 14:28:19.985184900 +0200
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  int e = (a && b && c);
+  return (e && (a | b) == 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tor1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tor1.c	2011-05-19 14:28:12.189194900 +0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  return (a || b || c || (!b || !a) || c);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tor2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tor2.c	2011-05-19 14:28:12.191195200 +0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  return ((!a || !b) || c || (a | b) != 0) || c;
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tor4.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tor4.c	2011-05-19 14:28:12.194195500 +0200
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  int d = (a | b) != 0;
+  int e = (!a || c || !b || c);
+  return (e || d) != 0;
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tor5.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tor5.c	2011-05-19 14:28:12.196695900 +0200
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  _Bool d = (a | b) != 0;
+  _Bool e = (!a || c || !b || c);
+  return (e || d) != 0;
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tand3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tand3.c	2011-05-19 14:28:19.983684700 +0200
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  int d = (!a && !b);
+  int e = (b && c);
+  return (d && e && c && a);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/binop-tor3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/binop-tor3.c	2011-05-19 14:28:12.192695300 +0200
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a, int b, int c)
+{
+  int d = (a || !b);
+  int e = (!a || b);
+  return (e || d || c);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
