diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 820c45c55c3d3b48ff0d51b2b18570b7f2f22f7e..99c9b5744ce442be8257ca6e33f325f6d275151c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2007-01-15  Jan Hubicka  <jh@suse.cz>
+
+	* tree-ssa-dce.c (DCE_TODOs): New.
+	(propagate_necessity): Return if something changed.
+	(eliminate_unnecessary_stmts): Likewise.
+	(perform_tree_ssa_dce): Return TODO flags when needed.
+	(pass_dce, pass_dce_loop, pass_cd_dce): Remove TODO flags.
+
 2007-01-15  Uros Bizjak  <ubizjak@gmail.com>
 
 	* config/i386/i386.md (fyl2xxf3_i387): Rename from fyl2x_xf3.
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index a26b87f5d8ee57ba461cb9d2af81a8f62067974e..381d91016e05263a4848b49b16e05c1fdb7253ce 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -525,10 +525,11 @@ propagate_necessity (struct edge_list *el)
 
 /* Remove dead PHI nodes from block BB.  */
 
-static void
+static bool
 remove_dead_phis (basic_block bb)
 {
   tree prev, phi;
+  bool something_changed = false;
 
   prev = NULL_TREE;
   phi = phi_nodes (bb);
@@ -540,6 +541,7 @@ remove_dead_phis (basic_block bb)
 	{
 	  tree next = PHI_CHAIN (phi);
 
+	  something_changed = true;
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
 	      fprintf (dump_file, "Deleting : ");
@@ -557,6 +559,7 @@ remove_dead_phis (basic_block bb)
 	  phi = PHI_CHAIN (phi);
 	}
     }
+  return something_changed;
 }
 
 
@@ -649,9 +652,10 @@ remove_dead_stmt (block_stmt_iterator *i, basic_block bb)
 /* Eliminate unnecessary statements. Any instruction not marked as necessary
    contributes nothing to the program, and can be deleted.  */
 
-static void
+static bool
 eliminate_unnecessary_stmts (void)
 {
+  bool something_changed = false;
   basic_block bb;
   block_stmt_iterator i;
 
@@ -662,7 +666,7 @@ eliminate_unnecessary_stmts (void)
   FOR_EACH_BB (bb)
     {
       /* Remove dead PHI nodes.  */
-      remove_dead_phis (bb);
+      something_changed |= remove_dead_phis (bb);
     }
 
   FOR_EACH_BB (bb)
@@ -676,7 +680,10 @@ eliminate_unnecessary_stmts (void)
 
 	  /* If `i' is not necessary then remove it.  */
 	  if (! NECESSARY (t))
-	    remove_dead_stmt (&i, bb);
+	    {
+	      remove_dead_stmt (&i, bb);
+	      something_changed = true;
+	    }
 	  else
 	    {
 	      tree call = get_call_expr_in (t);
@@ -686,6 +693,7 @@ eliminate_unnecessary_stmts (void)
 	    }
 	}
     }
+  return something_changed;
 }
 
 
@@ -774,10 +782,11 @@ tree_dce_done (bool aggressive)
 	  as the last tree SSA pass, but keep this in mind when you
 	  start experimenting with pass ordering.  */
 
-static void
+static unsigned int
 perform_tree_ssa_dce (bool aggressive)
 {
   struct edge_list *el = NULL;
+  bool something_changed = 0;
 
   tree_dce_init (aggressive);
 
@@ -800,9 +809,10 @@ perform_tree_ssa_dce (bool aggressive)
 
   propagate_necessity (el);
 
-  eliminate_unnecessary_stmts ();
+  something_changed |= eliminate_unnecessary_stmts ();
+  something_changed |= cfg_altered;
 
-  if (aggressive)
+  if (aggressive && something_changed)
     free_dominance_info (CDI_POST_DOMINATORS);
 
   /* If we removed paths in the CFG, then we need to update
@@ -818,30 +828,38 @@ perform_tree_ssa_dce (bool aggressive)
   tree_dce_done (aggressive);
 
   free_edge_list (el);
+
+  if (something_changed)
+    return (TODO_update_ssa | TODO_cleanup_cfg | TODO_ggc_collect 
+	    | TODO_remove_unused_locals);
+  else
+    return 0;
 }
 
 /* Pass entry points.  */
 static unsigned int
 tree_ssa_dce (void)
 {
-  perform_tree_ssa_dce (/*aggressive=*/false);
-  return 0;
+  return perform_tree_ssa_dce (/*aggressive=*/false);
 }
 
 static unsigned int
 tree_ssa_dce_loop (void)
 {
-  perform_tree_ssa_dce (/*aggressive=*/false);
-  free_numbers_of_iterations_estimates ();
-  scev_reset ();
-  return 0;
+  unsigned int todo;
+  todo = perform_tree_ssa_dce (/*aggressive=*/false);
+  if (todo)
+    {
+      free_numbers_of_iterations_estimates ();
+      scev_reset ();
+    }
+  return todo;
 }
 
 static unsigned int
 tree_ssa_cd_dce (void)
 {
-  perform_tree_ssa_dce (/*aggressive=*/optimize >= 2);
-  return 0;
+  return perform_tree_ssa_dce (/*aggressive=*/optimize >= 2);
 }
 
 static bool
@@ -863,12 +881,7 @@ struct tree_opt_pass pass_dce =
   0,					/* properties_provided */
   0,					/* properties_destroyed */
   0,					/* todo_flags_start */
-  TODO_dump_func 
-    | TODO_update_ssa
-    | TODO_cleanup_cfg
-    | TODO_ggc_collect
-    | TODO_verify_ssa
-    | TODO_remove_unused_locals,	/* todo_flags_finish */
+  TODO_dump_func | TODO_verify_ssa,	/* todo_flags_finish */
   0					/* letter */
 };
 
@@ -885,10 +898,7 @@ struct tree_opt_pass pass_dce_loop =
   0,					/* properties_provided */
   0,					/* properties_destroyed */
   0,					/* todo_flags_start */
-  TODO_dump_func 
-    | TODO_update_ssa
-    | TODO_cleanup_cfg
-    | TODO_verify_ssa,			/* todo_flags_finish */
+  TODO_dump_func | TODO_verify_ssa,	/* todo_flags_finish */
   0					/* letter */
 };
 
@@ -905,11 +915,7 @@ struct tree_opt_pass pass_cd_dce =
   0,					/* properties_provided */
   0,					/* properties_destroyed */
   0,					/* todo_flags_start */
-  TODO_dump_func
-    | TODO_update_ssa
-    | TODO_cleanup_cfg
-    | TODO_ggc_collect
-    | TODO_verify_ssa
-    | TODO_verify_flow,			/* todo_flags_finish */
+  TODO_dump_func | TODO_verify_ssa
+  | TODO_verify_flow,			/* todo_flags_finish */
   0					/* letter */
 };