diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5f0788fa7e00d5c8c065322adb7ff0b51ec9eb4a..ac0fd78537898336976af0086ae91a5f0077bb56 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2009-10-09  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/41634
+	* tree-ssa-dom.c (remove_local_expressions_from_table): Assert
+	we remove the correct elements.
+	(optimize_stmt): Make sure to update stmt operands before
+	optimizing redundancies.
+
 2009-10-09  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
 
 	* config/s390/s390.md ("prefetch"): Remove stcmh for prefetching.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 73596d735f217199cbd9e68c22dfcb64b93a0d13..64e65d731e8190dd3815d466b24a7d898c409411 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-10-09  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/41634
+	* gcc.c-torture/compile/pr41634.c: New testcase.
+
 2009-10-09  Uros Bizjak  <ubizjak@gmail.com>
 
 	* gfortran.dg/block_2.f08: Cleanup "original" tree dump.
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr41634.c b/gcc/testsuite/gcc.c-torture/compile/pr41634.c
new file mode 100644
index 0000000000000000000000000000000000000000..976e463e2ba80a4a719bdf04ec4255ff0dec74ad
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr41634.c
@@ -0,0 +1,19 @@
+extern int _xgetw();
+extern int foo(char*);
+
+void test_readmode( int ascii_mode )
+{
+  static const char outbuffer[]
+    = "0,1,2,3,4,5,6,7,8,9\r\n\r\nA,B,C,D,E\r\nX,Y,Z";
+  char buffer[2*512 +256];
+  int i, j, ao;
+  unsigned int fp;
+
+  foo(buffer);
+
+  for (i=0, j=0; i<6; i++) {
+      if (ao==0 || outbuffer[fp-3+i] != '\r')
+	buffer[j++] = outbuffer[fp-3+i];
+  }
+  _xgetw();
+}
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index 4bad3ddaf48a56d53b3aa56fab23ab2aa7ae48bd..1e2c8f23ce8129ceb037d1f1adce2fa8c578e43e 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -816,24 +816,25 @@ remove_local_expressions_from_table (void)
   /* Remove all the expressions made available in this block.  */
   while (VEC_length (expr_hash_elt_t, avail_exprs_stack) > 0)
     {
-      struct expr_hash_elt element;
       expr_hash_elt_t victim = VEC_pop (expr_hash_elt_t, avail_exprs_stack);
+      void **slot;
 
       if (victim == NULL)
 	break;
 
-      element = *victim;
-
       /* This must precede the actual removal from the hash table,
          as ELEMENT and the table entry may share a call argument
          vector which will be freed during removal.  */
       if (dump_file && (dump_flags & TDF_DETAILS))
         {
           fprintf (dump_file, "<<<< ");
-          print_expr_hash_elt (dump_file, &element);
+          print_expr_hash_elt (dump_file, victim);
         }
 
-      htab_remove_elt_with_hash (avail_exprs, &element, element.hash);
+      slot = htab_find_slot_with_hash (avail_exprs,
+				       victim, victim->hash, NO_INSERT);
+      gcc_assert (slot && *slot == (void *) victim);
+      htab_clear_slot (avail_exprs, slot);
     }
 }
 
@@ -2137,8 +2138,6 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
 
   if (may_optimize_p)
     {
-      eliminate_redundant_computations (&si);
-      stmt = gsi_stmt (si);
       if (gimple_code (stmt) == GIMPLE_CALL)
 	{
 	  /* Resolve __builtin_constant_p.  If it hasn't been
@@ -2153,6 +2152,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
 	      stmt = gsi_stmt (si);
 	    }
 	}
+
+      update_stmt_if_modified (stmt);
+      eliminate_redundant_computations (&si);
+      stmt = gsi_stmt (si);
     }
 
   /* Record any additional equivalences created by this statement.  */
@@ -2188,7 +2191,7 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
     {
       tree val = NULL;
       
-      update_stmt (stmt);
+      update_stmt_if_modified (stmt);
 
       if (gimple_code (stmt) == GIMPLE_COND)
         val = fold_binary_loc (gimple_location (stmt),