--- gcc/tree-ssa-dce.c.jj	2012-08-15 10:55:33.000000000 +0200
+++ gcc/tree-ssa-dce.c	2012-10-22 16:50:03.011497546 +0200
@@ -381,7 +381,7 @@ mark_stmt_if_obviously_necessary (gimple
 
 /* Mark the last statement of BB as necessary.  */
 
-static void
+static bool
 mark_last_stmt_necessary (basic_block bb)
 {
   gimple stmt = last_stmt (bb);
@@ -391,7 +391,11 @@ mark_last_stmt_necessary (basic_block bb
 
   /* We actually mark the statement only if it is a control statement.  */
   if (stmt && is_ctrl_stmt (stmt))
-    mark_stmt_necessary (stmt, true);
+    {
+      mark_stmt_necessary (stmt, true);
+      return true;
+    }
+  return false;
 }
 
 
@@ -423,8 +427,18 @@ mark_control_dependent_edges_necessary (
 	  continue;
 	}
 
-      if (!TEST_BIT (last_stmt_necessary, cd_bb->index))
-	mark_last_stmt_necessary (cd_bb);
+      if (!TEST_BIT (last_stmt_necessary, cd_bb->index)
+	  && !mark_last_stmt_necessary (cd_bb))
+	{
+	  /* In presence of infinite loops, some bbs on a path
+	     to an infinite loop might not end with a control stmt,
+	     but due to a fake edge to exit stop find_control_dependence.
+	     Recurse for those.  */
+	  if (get_immediate_dominator (CDI_POST_DOMINATORS, cd_bb)
+	      == EXIT_BLOCK_PTR
+	      && single_succ_p (cd_bb))
+	    mark_control_dependent_edges_necessary (cd_bb, el, false);
+	}
     }
 
   if (!skipped)
--- gcc/testsuite/gcc.dg/torture/pr55018.c.jj	2012-10-22 16:53:56.623083723 +0200
+++ gcc/testsuite/gcc.dg/torture/pr55018.c	2012-10-22 16:54:21.278934668 +0200
@@ -0,0 +1,22 @@
+/* PR tree-optimization/55018 */
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-optimized" } */
+
+void
+foo (int x)
+{
+  unsigned int a = 0;
+  int b = 3;
+  if (x)
+    b = 0;
+lab:
+  if (x)
+    goto lab;
+  a++;
+  if (b != 2)
+    __builtin_printf ("%u", a);
+  goto lab;
+}
+
+/* { dg-final { scan-tree-dump "printf" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
