diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index c4c09b6..a21d229 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -110,7 +110,6 @@ static tree decode_field_reference (location_t, tree, HOST_WIDE_INT *,
 static int all_ones_mask_p (const_tree, int);
 static tree sign_bit_p (tree, const_tree);
 static int simple_operand_p (const_tree);
-static bool simple_operand_p_2 (tree);
 static tree range_binop (enum tree_code, tree, tree, int, tree, int);
 static tree range_predecessor (tree);
 static tree range_successor (tree);
@@ -3818,7 +3817,7 @@ simple_operand_p (const_tree exp)
    I addition to simple_operand_p, we assume that comparisons, conversions,
    and logic-not operations are simple, if their operands are simple, too.  */
 
-static bool
+bool
 simple_operand_p_2 (tree exp)
 {
   enum tree_code code;
diff --git a/gcc/tree.h b/gcc/tree.h
index d40d416..bb6fa55 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4835,6 +4835,9 @@ extern bool is_tm_ending_fndecl (tree);
 extern void record_tm_replacement (tree, tree);
 extern void tm_malloc_replacement (tree);
 
+/* In fold-const.c.  */
+extern bool simple_operand_p_2 (tree);
+
 static inline bool
 is_tm_safe_or_pure (const_tree x)
 {
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index 268275e..5c4e1db 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
 #include "tree.h"
 #include "basic-block.h"
 #include "tree-pretty-print.h"
@@ -294,6 +296,234 @@ recognize_bits_test (gimple cond, tree *name, tree *bits, bool inv)
   return true;
 }
 
+#ifndef LOGICAL_OP_NON_SHORT_CIRCUIT
+#define LOGICAL_OP_NON_SHORT_CIRCUIT \
+  (BRANCH_COST (optimize_function_for_speed_p (cfun), \
+		false) >= 2)
+#endif
+
+/* Verify if the basic block BB have overhead (more than one instruction).
+   Return true in this case, else false.  */
+
+static bool
+bb_has_overhead_p (basic_block bb, gimple inner_cond)
+{
+  gimple_stmt_iterator gsi;
+
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple stmt = gsi_stmt (gsi);
+      /* Skip label and debug.  */
+      if (gimple_code (stmt) == GIMPLE_LABEL
+	  || gimple_code (stmt) == GIMPLE_DEBUG)
+	continue;
+      /* BB has only one statement INNER_COND.
+	 TBD: If conditional compare is supported, it can have be a complex
+	 condition.  */
+      if (stmt == inner_cond)
+	return false;
+      else
+	return true;
+    }
+
+  return true;
+}
+
+/* Create a tree node with CODE to reprent the condition of COND.
+   Note: CODE is not the same as gimple_cond_code (cond).  */
+
+static tree
+generate_condition_node (gimple_stmt_iterator *gsi, gimple cond,
+		       enum tree_code code)
+{
+  tree t;
+  gimple tem;
+
+  if (code == NE_EXPR
+      && integer_zerop(gimple_cond_rhs (cond))
+      && TREE_CODE (TREE_TYPE (gimple_cond_lhs (cond))) == BOOLEAN_TYPE)
+    {
+      t = gimple_cond_lhs (cond);
+    }
+  else
+    {
+      t = make_ssa_name (boolean_type_node, NULL);
+      tem = gimple_build_assign_with_ops (code, t,
+					  gimple_cond_lhs (cond),
+					  gimple_cond_rhs (cond));
+      if (!tem)
+	return NULL_TREE;
+      gimple_set_location (tem, gimple_location (cond));
+      gsi_insert_before (gsi, tem, GSI_SAME_STMT);
+    }
+  return t;
+}
+
+/* Recover a non-short-circuit branch.  The inner if is specified by its
+   INNER_COND_BB, the outer by OUTER_COND_BB.
+   INNER_INV and OUT_INV indicate whether the conditions are inverted.
+   It tries to generate candidates for conditional compare.
+   Returns true if the edges to the common else basic-block were merged.
+   case 1:
+     if (cond1)
+       if (cond2)
+   to
+     if (cond1 && cond2)
+
+   case 2:
+     if (cond1)
+       goto L1
+     if (cond2)
+       goto L1
+   to
+     if (cond1 || cond2)
+       goto L1
+
+   case 3:
+     if (cond1)
+       goto L1
+     else
+       goto L2
+     L1:
+     if (cond2)
+       goto L2
+   to
+     if (invert (cond1) || cond2)
+       goto L2
+
+   case 4:
+     if (cond1)
+       goto L1
+     if (cond2)
+       goto L2
+     L1:
+   to
+     if (invert (cond1) && cond2)
+       goto L2
+*/
+
+static bool
+ifcombine_ccmp (gimple inner_cond, bool inner_inv,
+		gimple outer_cond, bool outer_inv)
+{
+  enum tree_code inner_cond_code = gimple_cond_code (inner_cond);
+  enum tree_code outer_cond_code = gimple_cond_code (outer_cond);
+  tree t0, t1, t2, t3;
+  gimple tem;
+  gimple_stmt_iterator gsi;
+
+  /* For sequence point consistancy, we need to check for trapping,
+     and side-effects.  The check is the same as it in
+     function fold_truth_andor of fold-const.c.  */
+  if (!simple_operand_p_2(gimple_cond_lhs (outer_cond))
+      || !simple_operand_p_2(gimple_cond_rhs (outer_cond))
+      || !simple_operand_p_2(gimple_cond_lhs (inner_cond))
+      || !simple_operand_p_2(gimple_cond_rhs (inner_cond)))
+    return false;
+
+  if (outer_inv != inner_inv)
+    {
+      enum machine_mode mode;
+      mode = TYPE_MODE (TREE_TYPE (gimple_cond_lhs (outer_cond)));
+      outer_cond_code = invert_tree_comparison (outer_cond_code,
+						HONOR_NANS (mode));
+    }
+  if (outer_cond_code == ERROR_MARK)
+    return false;
+
+  gsi = gsi_for_stmt (inner_cond);
+  t0 = generate_condition_node (&gsi, outer_cond, outer_cond_code);
+  if (t0 == NULL_TREE)
+    return false;
+  t1 = generate_condition_node (&gsi, inner_cond, inner_cond_code);
+  if (t1 == NULL_TREE)
+    return false;
+
+  t2 = make_ssa_name (boolean_type_node, NULL);
+  tem = gimple_build_assign_with_ops (inner_inv ? BIT_IOR_EXPR : BIT_AND_EXPR,
+				       t2, t0, t1);
+  gsi_insert_before (&gsi, tem, GSI_SAME_STMT);
+
+  t3 = fold_build2 (NE_EXPR, TREE_TYPE (t2), t2, integer_zero_node);
+  t3 = canonicalize_cond_expr_cond (t3);
+  if (!t3)
+    return false;
+
+  gimple_cond_set_condition_from_tree (inner_cond, t3);
+  update_stmt (inner_cond);
+
+  /* Leave CFG optimization to cfg_cleanup.  */
+  gimple_cond_set_condition_from_tree (outer_cond,
+				       outer_inv ? boolean_false_node
+						   : boolean_true_node);
+  update_stmt (outer_cond);
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "Recovering non short circuit.\n");
+    }
+
+  return true;
+}
+
+/* If-convert on a and pattern with a common else block.  The inner
+   if is specified by its INNER_COND_BB, the outer by OUTER_COND_BB.
+   INNER_INV, OUT_INV and RESULT_INV indicate whether the conditions
+   are inverted.  This convert depends on maybe_fold_and_comparisons.
+   Returns true if the edges to the common else basic-block were merged.  */
+
+static bool
+ifcombine_fold_ifandif (gimple inner_cond, bool inner_inv,
+			gimple outer_cond, bool outer_inv, bool result_inv)
+{
+  tree t;
+  enum tree_code inner_cond_code = gimple_cond_code (inner_cond);
+  enum tree_code outer_cond_code = gimple_cond_code (outer_cond);
+
+  /* Invert comparisons if necessary (and possible).  */
+  if (inner_inv)
+    inner_cond_code = invert_tree_comparison (inner_cond_code,
+      HONOR_NANS (TYPE_MODE (TREE_TYPE (gimple_cond_lhs (inner_cond)))));
+  if (inner_cond_code == ERROR_MARK)
+    return false;
+  if (outer_inv)
+    outer_cond_code = invert_tree_comparison (outer_cond_code,
+      HONOR_NANS (TYPE_MODE (TREE_TYPE (gimple_cond_lhs (outer_cond)))));
+  if (outer_cond_code == ERROR_MARK)
+    return false;
+  /* Don't return false so fast, try maybe_fold_or_comparisons?  */
+
+  if (!(t = maybe_fold_and_comparisons (inner_cond_code,
+					gimple_cond_lhs (inner_cond),
+					gimple_cond_rhs (inner_cond),
+					outer_cond_code,
+					gimple_cond_lhs (outer_cond),
+					gimple_cond_rhs (outer_cond))))
+    return false;
+  if (result_inv)
+    t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
+  t = canonicalize_cond_expr_cond (t);
+  if (!t)
+    return false;
+  gimple_cond_set_condition_from_tree (inner_cond, t);
+  update_stmt (inner_cond);
+
+  /* Leave CFG optimization to cfg_cleanup.  */
+  gimple_cond_set_condition_from_tree (outer_cond,
+				       outer_inv ? boolean_false_node
+						   : boolean_true_node);
+  update_stmt (outer_cond);
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "optimizing two comparisons to ");
+      print_generic_expr (dump_file, t, 0);
+      fprintf (dump_file, "\n");
+    }
+
+  return true;
+}
+
 /* If-convert on a and pattern with a common else block.  The inner
    if is specified by its INNER_COND_BB, the outer by OUTER_COND_BB.
    inner_inv, outer_inv and result_inv indicate whether the conditions
@@ -457,55 +687,18 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
       return true;
     }
 
-  /* See if we have two comparisons that we can merge into one.  */
   else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
 	   && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison)
     {
-      tree t;
-      enum tree_code inner_cond_code = gimple_cond_code (inner_cond);
-      enum tree_code outer_cond_code = gimple_cond_code (outer_cond);
-
-      /* Invert comparisons if necessary (and possible).  */
-      if (inner_inv)
-	inner_cond_code = invert_tree_comparison (inner_cond_code,
-	  HONOR_NANS (TYPE_MODE (TREE_TYPE (gimple_cond_lhs (inner_cond)))));
-      if (inner_cond_code == ERROR_MARK)
-	return false;
-      if (outer_inv)
-	outer_cond_code = invert_tree_comparison (outer_cond_code,
-	  HONOR_NANS (TYPE_MODE (TREE_TYPE (gimple_cond_lhs (outer_cond)))));
-      if (outer_cond_code == ERROR_MARK)
-	return false;
-      /* Don't return false so fast, try maybe_fold_or_comparisons?  */
-
-      if (!(t = maybe_fold_and_comparisons (inner_cond_code,
-					    gimple_cond_lhs (inner_cond),
-					    gimple_cond_rhs (inner_cond),
-					    outer_cond_code,
-					    gimple_cond_lhs (outer_cond),
-					    gimple_cond_rhs (outer_cond))))
-	return false;
-      if (result_inv)
-	t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
-      t = canonicalize_cond_expr_cond (t);
-      if (!t)
-	return false;
-      gimple_cond_set_condition_from_tree (inner_cond, t);
-      update_stmt (inner_cond);
-
-      /* Leave CFG optimization to cfg_cleanup.  */
-      gimple_cond_set_condition_from_tree (outer_cond,
-	outer_inv ? boolean_false_node : boolean_true_node);
-      update_stmt (outer_cond);
-
-      if (dump_file)
-	{
-	  fprintf (dump_file, "optimizing two comparisons to ");
-	  print_generic_expr (dump_file, t, 0);
-	  fprintf (dump_file, "\n");
-	}
-
-      return true;
+      /* See if we have two comparisons that we can merge into one.  */
+      if (ifcombine_fold_ifandif (inner_cond, inner_inv,
+				  outer_cond, outer_inv, result_inv))
+	return true;
+
+      /* See if we have two comparisons that we can use NON_SHORT_CIRCUIT.  */
+      if ((LOGICAL_OP_NON_SHORT_CIRCUIT)
+	   && !bb_has_overhead_p (inner_cond_bb, inner_cond))
+	return ifcombine_ccmp (inner_cond, inner_inv, outer_cond, outer_inv);
     }
 
   return false;
@@ -519,10 +712,21 @@ static bool
 tree_ssa_ifcombine_bb (basic_block inner_cond_bb)
 {
   basic_block then_bb = NULL, else_bb = NULL;
+  gimple inner_cond;
 
   if (!recognize_if_then_else (inner_cond_bb, &then_bb, &else_bb))
     return false;
 
+  inner_cond = last_stmt (inner_cond_bb);
+  if (!inner_cond
+      || gimple_code (inner_cond) != GIMPLE_COND)
+    return false;
+
+  /* If innner_cond is already optimized, just return FALSE.  */
+  if (TREE_CODE (gimple_cond_lhs (inner_cond)) == INTEGER_CST
+      && TREE_CODE (gimple_cond_rhs (inner_cond)) == INTEGER_CST)
+    return false;
+
   /* Recognize && and || of two conditions with a common
      then/else block which entry edges we can merge.  That is:
        if (a || b)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-3.c
index 0d53f50..6fbce47 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-3.c
@@ -42,7 +42,7 @@ expand_one_var (tree var, unsigned char toplevel, unsigned char really_expand)
     abort ();
 }
 /* We should thread the jump, through an intermediate block.  */
-/* { dg-final { scan-tree-dump-times "Threaded" 2 "dom1"} } */
-/* { dg-final { scan-tree-dump-times "Registering jump thread: \\(.*\\) incoming edge;  \\(.*\\) joiner;  \\(.*\\) nocopy;" 1 "dom1"} } */
+/* { dg-final { scan-tree-dump "Threaded" "dom1"} } */
+/* { dg-final { scan-tree-dump-times "Registering jump thread: \\(.*\\) incoming edge;" 1 "dom1"} } */
 /* { dg-final { cleanup-tree-dump "dom1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-1.c
new file mode 100644
index 0000000..56c936d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -g -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int t (int a, int b)
+{
+  if (a > 0)
+    if (b > 0)
+      return 0;
+  return 1;
+}
+/* { dg-final { scan-tree-dump "\&" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-2.c
new file mode 100644
index 0000000..3273bcc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-2.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -g -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int t (int a, int b)
+{
+  if (a > 0)
+    goto L1;
+  if (b > 0)
+    goto L1;
+  return 0;
+L1:
+  return 1;
+}
+/* { dg-final { scan-tree-dump "\|" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-3.c
new file mode 100644
index 0000000..500cb01
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-3.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -g -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int t (int a, int b)
+{
+  if (a > 0)
+    goto L1;
+  else
+    goto L2;
+L1:
+  if (b > 0)
+    goto L2;
+  return 5;
+L2:
+  return 6;
+}
+/* { dg-final { scan-tree-dump "\|" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-4.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-4.c
new file mode 100644
index 0000000..8b87101
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-4.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -g -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int t (int a, int b)
+{
+  if (a > 0)
+    goto L1;
+  if (b > 0)
+    goto L2;
+L1:
+  return 0;
+L2:
+  return 1;
+}
+/* { dg-final { scan-tree-dump "\&" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-5.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-5.c
new file mode 100644
index 0000000..2aa225b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -g -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int t (int a, int b, int c)
+{
+  if (a > 0 && b > 0 && c > 0)
+      return 0;
+  return 1;
+}
+/* { dg-final { scan-tree-dump-times "\&" 2 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-6.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-6.c
new file mode 100644
index 0000000..659e816
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-6.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -g -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int t (int a, int b, int c)
+{
+  if (a > 0 || b > 0 || c > 0)
+      return 0;
+  return 1;
+}
+/* { dg-final { scan-tree-dump-times "\\|" 2 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
