diff mbox

Improve ifcombine (PR 52005)

Message ID alpine.DEB.2.02.1207261748040.17097@stedding.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse July 26, 2012, 4:01 p.m. UTC
Hello,

here is a new version of the ifcombine patch, which handles Andrew's 
examples (though only with -O2 for one of them, same_phi_args_p returns 
false otherwise).

Note that the new patch never calls maybe_fold_or_comparisons, only 
maybe_fold_and_comparisons. It would be possible to call 
maybe_fold_or_comparisons, when maybe_fold_and_comparisons fails, but I 
don't know if there are optimizations that one does and not the other, 
except for the odd trapping-math case.

Bootstrap and testsuite are fine.

2012-07-26 Marc Glisse <marc.glisse@inria.fr>

gcc/
 	PR tree-optimization/51938
 	PR tree-optimization/52005
 	* tree-ssa-ifcombine.c (ifcombine_ifandif): New parameters for
 	inverted conditions.
 	(ifcombine_iforif): Remove, merge code into ifcombine_ifandif.
 	(tree_ssa_ifcombine_bb): Update calls to the above. Detect !a&&b
 	and !a||b patterns.


gcc/testsuite/
 	PR tree-optimization/51938
 	PR tree-optimization/52005
 	* gcc.dg/tree-ssa/ssa-ifcombine-8.c: New testcase.
 	* gcc.dg/tree-ssa/ssa-ifcombine-9.c: Likewise.
 	* gcc.dg/tree-ssa/ssa-ifcombine-10.c: Likewise.
 	* gcc.dg/tree-ssa/ssa-ifcombine-11.c: Likewise.

Comments

Marc Glisse Aug. 6, 2012, 6:27 a.m. UTC | #1
Hello,

do you have an opinion on this patch (available here:
http://gcc.gnu.org/ml/gcc-patches/2012-07/msg01352.html
) ?

Or should we go back to my old patch, or Andrew's patch?

On Thu, 26 Jul 2012, Marc Glisse wrote:

> Hello,
>
> here is a new version of the ifcombine patch, which handles Andrew's examples 
> (though only with -O2 for one of them, same_phi_args_p returns false 
> otherwise).
>
> Note that the new patch never calls maybe_fold_or_comparisons, only 
> maybe_fold_and_comparisons. It would be possible to call 
> maybe_fold_or_comparisons, when maybe_fold_and_comparisons fails, but I don't 
> know if there are optimizations that one does and not the other, except for 
> the odd trapping-math case.
>
> Bootstrap and testsuite are fine.
>
> 2012-07-26 Marc Glisse <marc.glisse@inria.fr>
>
> gcc/
> 	PR tree-optimization/51938
> 	PR tree-optimization/52005
> 	* tree-ssa-ifcombine.c (ifcombine_ifandif): New parameters for
> 	inverted conditions.
> 	(ifcombine_iforif): Remove, merge code into ifcombine_ifandif.
> 	(tree_ssa_ifcombine_bb): Update calls to the above. Detect !a&&b
> 	and !a||b patterns.
>
>
> gcc/testsuite/
> 	PR tree-optimization/51938
> 	PR tree-optimization/52005
> 	* gcc.dg/tree-ssa/ssa-ifcombine-8.c: New testcase.
> 	* gcc.dg/tree-ssa/ssa-ifcombine-9.c: Likewise.
> 	* gcc.dg/tree-ssa/ssa-ifcombine-10.c: Likewise.
> 	* gcc.dg/tree-ssa/ssa-ifcombine-11.c: Likewise.
Richard Biener Aug. 6, 2012, 8:23 a.m. UTC | #2
On Mon, Aug 6, 2012 at 8:27 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
>
> Hello,
>
> do you have an opinion on this patch (available here:
> http://gcc.gnu.org/ml/gcc-patches/2012-07/msg01352.html
> ) ?

I like it.  Thus, the referenced patch is ok for trunk.

Thanks,
Richard.

> Or should we go back to my old patch, or Andrew's patch?
>
>
> On Thu, 26 Jul 2012, Marc Glisse wrote:
>
>> Hello,
>>
>> here is a new version of the ifcombine patch, which handles Andrew's
>> examples (though only with -O2 for one of them, same_phi_args_p returns
>> false otherwise).
>>
>> Note that the new patch never calls maybe_fold_or_comparisons, only
>> maybe_fold_and_comparisons. It would be possible to call
>> maybe_fold_or_comparisons, when maybe_fold_and_comparisons fails, but I
>> don't know if there are optimizations that one does and not the other,
>> except for the odd trapping-math case.
>>
>> Bootstrap and testsuite are fine.
>>
>> 2012-07-26 Marc Glisse <marc.glisse@inria.fr>
>>
>> gcc/
>>         PR tree-optimization/51938
>>         PR tree-optimization/52005
>>         * tree-ssa-ifcombine.c (ifcombine_ifandif): New parameters for
>>         inverted conditions.
>>         (ifcombine_iforif): Remove, merge code into ifcombine_ifandif.
>>         (tree_ssa_ifcombine_bb): Update calls to the above. Detect !a&&b
>>         and !a||b patterns.
>>
>>
>> gcc/testsuite/
>>         PR tree-optimization/51938
>>         PR tree-optimization/52005
>>         * gcc.dg/tree-ssa/ssa-ifcombine-8.c: New testcase.
>>         * gcc.dg/tree-ssa/ssa-ifcombine-9.c: Likewise.
>>         * gcc.dg/tree-ssa/ssa-ifcombine-10.c: Likewise.
>>         * gcc.dg/tree-ssa/ssa-ifcombine-11.c: Likewise.
>
>
> --
> Marc Glisse
diff mbox

Patch

Index: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-10.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/ssa-ifcombine-10.c	(revision 0)
+++ testsuite/gcc.dg/tree-ssa/ssa-ifcombine-10.c	(revision 0)
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Testcase for PR31657.  */
+
+int f(int x, int a, int b)
+{
+  int t = 0;
+  int c = 1 << a;
+  if (!(x & 1))
+    t = 0;
+  else
+    if (x & (1 << 2))
+      t = 3;
+    else
+      t = 0;
+  return t;
+}
+/* { dg-final { scan-tree-dump "& 5" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */

Property changes on: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-10.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c	(revision 0)
+++ testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c	(revision 0)
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fno-trapping-math -fdump-tree-ifcombine" } */
+
+double test1 (double i, double j)
+{
+  if (i >= j)
+    if (i <= j)
+      goto plif;
+    else
+      goto plouf;
+  else
+    goto plif;
+
+plif:
+  return 0;
+plouf:
+  return -1;
+}
+
+/* The above should be optimized to a i > j test by ifcombine.
+   The transformation would also be legal with -ftrapping-math.
+   Instead we get u<=, which is acceptable with -fno-trapping-math.  */
+
+/* { dg-final { scan-tree-dump " u<= " "ifcombine" } } */
+/* { dg-final { cleanup-tree-dump "ifcombine" } } */

Property changes on: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-11.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/ssa-ifcombine-11.c	(revision 0)
+++ testsuite/gcc.dg/tree-ssa/ssa-ifcombine-11.c	(revision 0)
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+/* Testcase for PR31657.  */
+int g(void);
+int f(int x, int a, int b)
+{
+  int t = 0;
+  int c = 1 << a;
+  if (!(x & 1))
+    t = 0;
+  else
+    if (x & (1 << 2))
+      t = g();
+    else
+      t = 0;
+  return t;
+}
+
+/* { dg-final { scan-tree-dump "& 5" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */

Property changes on: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-11.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c	(revision 0)
+++ testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c	(revision 0)
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-trapping-math -fdump-tree-ifcombine" } */
+
+void f ();
+enum Sign { NEG=-1, ZERO, POS };
+
+static inline enum Sign sign (double x)
+{
+  if (x > 0) return POS;
+  if (x < 0) return NEG;
+  return ZERO;
+}
+void g (double x)
+{
+  if (sign (x) == NEG) f();
+}
+
+/* The above should be optimized to x < 0 by ifcombine.
+   The transformation would also be legal with -ftrapping-math.  */
+
+/* { dg-final { scan-tree-dump "optimizing.* < " "ifcombine" } } */
+/* { dg-final { cleanup-tree-dump "ifcombine" } } */

Property changes on: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: tree-ssa-ifcombine.c
===================================================================
--- tree-ssa-ifcombine.c	(revision 189891)
+++ tree-ssa-ifcombine.c	(working copy)
@@ -159,26 +159,26 @@  get_name_for_bit_test (tree candidate)
 
   return candidate;
 }
 
 /* Recognize a single bit test pattern in GIMPLE_COND and its defining
    statements.  Store the name being tested in *NAME and the bit
    in *BIT.  The GIMPLE_COND computes *NAME & (1 << *BIT).
    Returns true if the pattern matched, false otherwise.  */
 
 static bool
-recognize_single_bit_test (gimple cond, tree *name, tree *bit)
+recognize_single_bit_test (gimple cond, tree *name, tree *bit, bool inv)
 {
   gimple stmt;
 
   /* Get at the definition of the result of the bit test.  */
-  if (gimple_cond_code (cond) != NE_EXPR
+  if (gimple_cond_code (cond) != (inv ? EQ_EXPR : NE_EXPR)
       || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME
       || !integer_zerop (gimple_cond_rhs (cond)))
     return false;
   stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond));
   if (!is_gimple_assign (stmt))
     return false;
 
   /* Look at which bit is tested.  One form to recognize is
      D.1985_5 = state_3(D) >> control1_4(D);
      D.1986_6 = (int) D.1985_5;
@@ -267,170 +267,118 @@  recognize_single_bit_test (gimple cond,
 
   return false;
 }
 
 /* Recognize a bit test pattern in a GIMPLE_COND and its defining
    statements.  Store the name being tested in *NAME and the bits
    in *BITS.  The COND_EXPR computes *NAME & *BITS.
    Returns true if the pattern matched, false otherwise.  */
 
 static bool
-recognize_bits_test (gimple cond, tree *name, tree *bits)
+recognize_bits_test (gimple cond, tree *name, tree *bits, bool inv)
 {
   gimple stmt;
 
   /* Get at the definition of the result of the bit test.  */
-  if (gimple_cond_code (cond) != NE_EXPR
+  if (gimple_cond_code (cond) != (inv ? EQ_EXPR : NE_EXPR)
       || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME
       || !integer_zerop (gimple_cond_rhs (cond)))
     return false;
   stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond));
   if (!is_gimple_assign (stmt)
       || gimple_assign_rhs_code (stmt) != BIT_AND_EXPR)
     return false;
 
   *name = get_name_for_bit_test (gimple_assign_rhs1 (stmt));
   *bits = gimple_assign_rhs2 (stmt);
 
   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
+   are inverted.
    Returns true if the edges to the common else basic-block were merged.  */
 
 static bool
-ifcombine_ifandif (basic_block inner_cond_bb, basic_block outer_cond_bb)
+ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
+		   basic_block outer_cond_bb, bool outer_inv, bool result_inv)
 {
   gimple_stmt_iterator gsi;
   gimple inner_cond, outer_cond;
-  tree name1, name2, bit1, bit2;
+  tree name1, name2, bit1, bit2, bits1, bits2;
 
   inner_cond = last_stmt (inner_cond_bb);
   if (!inner_cond
       || gimple_code (inner_cond) != GIMPLE_COND)
     return false;
 
   outer_cond = last_stmt (outer_cond_bb);
   if (!outer_cond
       || gimple_code (outer_cond) != GIMPLE_COND)
     return false;
 
   /* See if we test a single bit of the same name in both tests.  In
      that case remove the outer test, merging both else edges,
      and change the inner one to test for
      name & (bit1 | bit2) == (bit1 | bit2).  */
-  if (recognize_single_bit_test (inner_cond, &name1, &bit1)
-      && recognize_single_bit_test (outer_cond, &name2, &bit2)
+  if (recognize_single_bit_test (inner_cond, &name1, &bit1, inner_inv)
+      && recognize_single_bit_test (outer_cond, &name2, &bit2, outer_inv)
       && name1 == name2)
     {
       tree t, t2;
 
       /* Do it.  */
       gsi = gsi_for_stmt (inner_cond);
       t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
 		       build_int_cst (TREE_TYPE (name1), 1), bit1);
       t2 = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
 		        build_int_cst (TREE_TYPE (name1), 1), bit2);
       t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), t, t2);
       t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 				    true, GSI_SAME_STMT);
       t2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
       t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE,
 				     true, GSI_SAME_STMT);
-      t = fold_build2 (EQ_EXPR, boolean_type_node, t2, t);
+      t = fold_build2 (result_inv ? NE_EXPR : EQ_EXPR,
+		       boolean_type_node, t2, 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, boolean_true_node);
+      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 double bit test to ");
 	  print_generic_expr (dump_file, name1, 0);
 	  fprintf (dump_file, " & T == T\nwith temporary T = (1 << ");
 	  print_generic_expr (dump_file, bit1, 0);
 	  fprintf (dump_file, ") | (1 << ");
 	  print_generic_expr (dump_file, bit2, 0);
 	  fprintf (dump_file, ")\n");
 	}
 
       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;
-
-      if (!(t = maybe_fold_and_comparisons (gimple_cond_code (inner_cond),
-					    gimple_cond_lhs (inner_cond),
-					    gimple_cond_rhs (inner_cond),
-					    gimple_cond_code (outer_cond),
-					    gimple_cond_lhs (outer_cond),
-					    gimple_cond_rhs (outer_cond))))
-	return false;
-      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, 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;
-    }
-
-  return false;
-}
-
-/* If-convert on a or pattern with a common then block.  The inner
-   if is specified by its INNER_COND_BB, the outer by OUTER_COND_BB.
-   Returns true, if the edges leading to the common then basic-block
-   were merged.  */
-
-static bool
-ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
-{
-  gimple inner_cond, outer_cond;
-  tree name1, name2, bits1, bits2;
-
-  inner_cond = last_stmt (inner_cond_bb);
-  if (!inner_cond
-      || gimple_code (inner_cond) != GIMPLE_COND)
-    return false;
-
-  outer_cond = last_stmt (outer_cond_bb);
-  if (!outer_cond
-      || gimple_code (outer_cond) != GIMPLE_COND)
-    return false;
-
   /* See if we have two bit tests of the same name in both tests.
      In that case remove the outer test and change the inner one to
      test for name & (bits1 | bits2) != 0.  */
-  if (recognize_bits_test (inner_cond, &name1, &bits1)
-      && recognize_bits_test (outer_cond, &name2, &bits2))
+  else if (recognize_bits_test (inner_cond, &name1, &bits1, !inner_inv)
+      && recognize_bits_test (outer_cond, &name2, &bits2, !outer_inv))
     {
       gimple_stmt_iterator gsi;
       tree t;
 
       /* Find the common name which is bit-tested.  */
       if (name1 == name2)
 	;
       else if (bits1 == bits2)
 	{
 	  t = name2;
@@ -475,69 +423,86 @@  ifcombine_iforif (basic_block inner_cond
 	}
 
       /* Do it.  */
       gsi = gsi_for_stmt (inner_cond);
       t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2);
       t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 				    true, GSI_SAME_STMT);
       t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
       t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
 				    true, GSI_SAME_STMT);
-      t = fold_build2 (NE_EXPR, boolean_type_node, t,
+      t = fold_build2 (result_inv ? NE_EXPR : EQ_EXPR, boolean_type_node, t,
 		       build_int_cst (TREE_TYPE (t), 0));
       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, boolean_false_node);
+      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 bits or bits test to ");
 	  print_generic_expr (dump_file, name1, 0);
 	  fprintf (dump_file, " & T != 0\nwith temporary T = ");
 	  print_generic_expr (dump_file, bits1, 0);
 	  fprintf (dump_file, " | ");
 	  print_generic_expr (dump_file, bits2, 0);
 	  fprintf (dump_file, "\n");
 	}
 
       return true;
     }
 
-  /* See if we have two comparisons that we can merge into one.
-     This happens for C++ operator overloading where for example
-     GE_EXPR is implemented as GT_EXPR || EQ_EXPR.  */
-    else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
+  /* 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);
 
-      if (!(t = maybe_fold_or_comparisons (gimple_cond_code (inner_cond),
-					   gimple_cond_lhs (inner_cond),
-					   gimple_cond_rhs (inner_cond),
-					   gimple_cond_code (outer_cond),
-					   gimple_cond_lhs (outer_cond),
-					   gimple_cond_rhs (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, boolean_false_node);
+      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;
@@ -580,40 +545,77 @@  tree_ssa_ifcombine_bb (basic_block inner
 	{
 	  /* We have
 	       <outer_cond_bb>
 		 if (q) goto inner_cond_bb; else goto else_bb;
 	       <inner_cond_bb>
 		 if (p) goto ...; else goto else_bb;
 		 ...
 	       <else_bb>
 		 ...
 	   */
-	  return ifcombine_ifandif (inner_cond_bb, outer_cond_bb);
+	  return ifcombine_ifandif (inner_cond_bb, false, outer_cond_bb, false,
+				    false);
+	}
+
+      /* And a version where the outer condition is negated.  */
+      if (recognize_if_then_else (outer_cond_bb, &else_bb, &inner_cond_bb)
+	  && same_phi_args_p (outer_cond_bb, inner_cond_bb, else_bb)
+	  && bb_no_side_effects_p (inner_cond_bb))
+	{
+	  /* We have
+	       <outer_cond_bb>
+		 if (q) goto else_bb; else goto inner_cond_bb;
+	       <inner_cond_bb>
+		 if (p) goto ...; else goto else_bb;
+		 ...
+	       <else_bb>
+		 ...
+	   */
+	  return ifcombine_ifandif (inner_cond_bb, false, outer_cond_bb, true,
+				    false);
 	}
 
       /* The || form is characterized by a common then_bb with the
 	 two edges leading to it mergable.  The latter is guaranteed
          by matching PHI arguments in the then_bb and the inner cond_bb
 	 having no side-effects.  */
       if (recognize_if_then_else (outer_cond_bb, &then_bb, &inner_cond_bb)
 	  && same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb)
 	  && bb_no_side_effects_p (inner_cond_bb))
 	{
 	  /* We have
 	       <outer_cond_bb>
 		 if (q) goto then_bb; else goto inner_cond_bb;
 	       <inner_cond_bb>
 		 if (q) goto then_bb; else goto ...;
 	       <then_bb>
 		 ...
 	   */
-	  return ifcombine_iforif (inner_cond_bb, outer_cond_bb);
+	  return ifcombine_ifandif (inner_cond_bb, true, outer_cond_bb, true,
+				    true);
+	}
+
+      /* And a version where the outer condition is negated.  */
+      if (recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &then_bb)
+	  && same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb)
+	  && bb_no_side_effects_p (inner_cond_bb))
+	{
+	  /* We have
+	       <outer_cond_bb>
+		 if (q) goto inner_cond_bb; else goto then_bb;
+	       <inner_cond_bb>
+		 if (q) goto then_bb; else goto ...;
+	       <then_bb>
+		 ...
+	   */
+	  return ifcombine_ifandif (inner_cond_bb, true, outer_cond_bb, false,
+				    true);
 	}
     }
 
   return false;
 }
 
 /* Main entry for the tree if-conversion pass.  */
 
 static unsigned int
 tree_ssa_ifcombine (void)