OSDN Git Service

* config/microblaze/microblaze.h (CC1_SPEC): Remove %{save-temps: }.
[pf3gnuchains/gcc-fork.git] / gcc / gcse.c
index 9bb0bbd..a0f51aa 100644 (file)
@@ -1,7 +1,7 @@
 /* Global common subexpression elimination/Partial redundancy elimination
    and global constant/copy propagation for GNU compiler.
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -329,6 +329,10 @@ struct occr
   char copied_p;
 };
 
+typedef struct occr *occr_t;
+DEF_VEC_P (occr_t);
+DEF_VEC_ALLOC_P (occr_t, heap);
+
 /* Expression and copy propagation hash tables.
    Each hash table is an array of buckets.
    ??? It is known that if it were an array of entries, structure elements
@@ -500,7 +504,7 @@ static void free_pre_mem (void);
 static void compute_pre_data (void);
 static int pre_expr_reaches_here_p (basic_block, struct expr *,
                                    basic_block);
-static void insert_insn_end_basic_block (struct expr *, basic_block, int);
+static void insert_insn_end_basic_block (struct expr *, basic_block);
 static void pre_insert_copy_insn (struct expr *, rtx);
 static void pre_insert_copies (void);
 static int pre_delete (void);
@@ -1456,7 +1460,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
                  modified.  Here we want to search from INSN+1 on, but
                  oprs_available_p searches from INSN on.  */
               && (insn == BB_END (BLOCK_FOR_INSN (insn))
-                  || (tmp = next_nonnote_insn (insn)) == NULL_RTX
+                  || (tmp = next_nonnote_nondebug_insn (insn)) == NULL_RTX
                   || BLOCK_FOR_INSN (tmp) != BLOCK_FOR_INSN (insn)
                   || oprs_available_p (pat, tmp)))
        insert_set_in_table (pat, insn, table);
@@ -1467,6 +1471,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
   else if (flag_gcse_las && REG_P (src) && MEM_P (dest))
       {
         unsigned int regno = REGNO (src);
+       int max_distance = 0;
 
         /* Do not do this for constant/copy propagation.  */
         if (! table->set_p
@@ -1478,7 +1483,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
              do that easily for EH edges so disable GCSE on these for now.  */
           && !can_throw_internal (insn)
           /* Is SET_DEST something we want to gcse?  */
-          && want_to_gcse_p (dest, NULL)
+          && want_to_gcse_p (dest, &max_distance)
           /* Don't CSE a nop.  */
           && ! set_noop_p (pat)
           /* Don't GCSE if it has attached REG_EQUIV note.
@@ -1499,8 +1504,8 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
                             && ! JUMP_P (insn);
 
               /* Record the memory expression (DEST) in the hash table.  */
-              insert_expr_in_table (dest, GET_MODE (dest), insn, 0,
-                                    antic_p, avail_p, table);
+              insert_expr_in_table (dest, GET_MODE (dest), insn,
+                                    antic_p, avail_p, max_distance, table);
              }
       }
 }
@@ -1743,7 +1748,7 @@ compute_hash_table_work (struct hash_table_d *table)
         determine when registers and memory are first and last set.  */
       FOR_BB_INSNS (current_bb, insn)
        {
-         if (! INSN_P (insn))
+         if (!NONDEBUG_INSN_P (insn))
            continue;
 
          if (CALL_P (insn))
@@ -1766,7 +1771,7 @@ compute_hash_table_work (struct hash_table_d *table)
 
       /* The next pass builds the hash table.  */
       FOR_BB_INSNS (current_bb, insn)
-       if (INSN_P (insn))
+       if (NONDEBUG_INSN_P (insn))
          hash_scan_insn (insn, table);
     }
 
@@ -2346,12 +2351,10 @@ try_replace_reg (rtx from, rtx to, rtx insn)
          && validate_change (insn, &SET_SRC (set), src, 0))
        success = 1;
 
-      /* If we've failed to do replacement, have a single SET, don't already
-        have a note, and have no special SET, add a REG_EQUAL note to not
-        lose information.  */
-      if (!success && note == 0 && set != 0
-         && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
-         && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
+      /* If we've failed perform the replacement, have a single SET to
+        a REG destination and don't yet have a note, add a REG_EQUAL note
+        to not lose information.  */
+      if (!success && note == 0 && set != 0 && REG_P (SET_DEST (set)))
        note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
     }
 
@@ -3393,6 +3396,75 @@ prune_expressions (bool pre_p)
   sbitmap_free (prune_exprs);
 }
 
+/* It may be necessary to insert a large number of insns on edges to
+   make the existing occurrences of expressions fully redundant.  This
+   routine examines the set of insertions and deletions and if the ratio
+   of insertions to deletions is too high for a particular expression, then
+   the expression is removed from the insertion/deletion sets. 
+
+   N_ELEMS is the number of elements in the hash table.  */
+
+static void
+prune_insertions_deletions (int n_elems)
+{
+  sbitmap_iterator sbi;
+  sbitmap prune_exprs;
+
+  /* We always use I to iterate over blocks/edges and J to iterate over
+     expressions.  */
+  unsigned int i, j;
+
+  /* Counts for the number of times an expression needs to be inserted and
+     number of times an expression can be removed as a result.  */
+  int *insertions = GCNEWVEC (int, n_elems);
+  int *deletions = GCNEWVEC (int, n_elems);
+
+  /* Set of expressions which require too many insertions relative to
+     the number of deletions achieved.  We will prune these out of the
+     insertion/deletion sets.  */
+  prune_exprs = sbitmap_alloc (n_elems);
+  sbitmap_zero (prune_exprs);
+
+  /* Iterate over the edges counting the number of times each expression
+     needs to be inserted.  */
+  for (i = 0; i < (unsigned) n_edges; i++)
+    {
+      EXECUTE_IF_SET_IN_SBITMAP (pre_insert_map[i], 0, j, sbi)
+       insertions[j]++;
+    }
+
+  /* Similarly for deletions, but those occur in blocks rather than on
+     edges.  */
+  for (i = 0; i < (unsigned) last_basic_block; i++)
+    {
+      EXECUTE_IF_SET_IN_SBITMAP (pre_delete_map[i], 0, j, sbi)
+       deletions[j]++;
+    }
+
+  /* Now that we have accurate counts, iterate over the elements in the
+     hash table and see if any need too many insertions relative to the
+     number of evaluations that can be removed.  If so, mark them in
+     PRUNE_EXPRS.  */
+  for (j = 0; j < (unsigned) n_elems; j++)
+    if (deletions[j]
+       && ((unsigned) insertions[j] / deletions[j]) > MAX_GCSE_INSERTION_RATIO)
+      SET_BIT (prune_exprs, j);
+
+  /* Now prune PRE_INSERT_MAP and PRE_DELETE_MAP based on PRUNE_EXPRS.  */
+  EXECUTE_IF_SET_IN_SBITMAP (prune_exprs, 0, j, sbi)
+    {
+      for (i = 0; i < (unsigned) n_edges; i++)
+       RESET_BIT (pre_insert_map[i], j);
+
+      for (i = 0; i < (unsigned) last_basic_block; i++)
+       RESET_BIT (pre_delete_map[i], j);
+    }
+
+  sbitmap_free (prune_exprs);
+  free (insertions);
+  free (deletions);
+}
+
 /* Top level routine to do the dataflow analysis needed by PRE.  */
 
 static void
@@ -3421,6 +3493,8 @@ compute_pre_data (void)
   antloc = NULL;
   sbitmap_vector_free (ae_kill);
   ae_kill = NULL;
+
+  prune_insertions_deletions (expr_hash_table.n_elems);
 }
 \f
 /* PRE utilities */
@@ -3535,14 +3609,10 @@ process_insert_insn (struct expr *expr)
 
 /* Add EXPR to the end of basic block BB.
 
-   This is used by both the PRE and code hoisting.
-
-   For PRE, we want to verify that the expr is either transparent
-   or locally anticipatable in the target block.  This check makes
-   no sense for code hoisting.  */
+   This is used by both the PRE and code hoisting.  */
 
 static void
-insert_insn_end_basic_block (struct expr *expr, basic_block bb, int pre)
+insert_insn_end_basic_block (struct expr *expr, basic_block bb)
 {
   rtx insn = BB_END (bb);
   rtx new_insn;
@@ -3569,19 +3639,13 @@ insert_insn_end_basic_block (struct expr *expr, basic_block bb, int pre)
 #ifdef HAVE_cc0
       rtx note;
 #endif
-      /* It should always be the case that we can put these instructions
-        anywhere in the basic block with performing PRE optimizations.
-        Check this.  */
-      gcc_assert (!NONJUMP_INSN_P (insn) || !pre
-                 || TEST_BIT (antloc[bb->index], expr->bitmap_index)
-                 || TEST_BIT (transp[bb->index], expr->bitmap_index));
 
       /* If this is a jump table, then we can't insert stuff here.  Since
         we know the previous real insn must be the tablejump, we insert
         the new instruction just before the tablejump.  */
       if (GET_CODE (PATTERN (insn)) == ADDR_VEC
          || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
-       insn = prev_real_insn (insn);
+       insn = prev_active_insn (insn);
 
 #ifdef HAVE_cc0
       /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts
@@ -3611,15 +3675,7 @@ insert_insn_end_basic_block (struct expr *expr, basic_block bb, int pre)
       /* Keeping in mind targets with small register classes and parameters
          in registers, we search backward and place the instructions before
         the first parameter is loaded.  Do this for everyone for consistency
-        and a presumption that we'll get better code elsewhere as well.
-
-        It should always be the case that we can put these instructions
-        anywhere in the basic block with performing PRE optimizations.
-        Check this.  */
-
-      gcc_assert (!pre
-                 || TEST_BIT (antloc[bb->index], expr->bitmap_index)
-                 || TEST_BIT (transp[bb->index], expr->bitmap_index));
+        and a presumption that we'll get better code elsewhere as well.  */
 
       /* Since different machines initialize their parameter registers
         in different orders, assume nothing.  Collect the set of all
@@ -3716,7 +3772,7 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map)
                           now.  */
 
                        if (eg->flags & EDGE_ABNORMAL)
-                         insert_insn_end_basic_block (index_map[j], bb, 0);
+                         insert_insn_end_basic_block (index_map[j], bb);
                        else
                          {
                            insn = process_insert_insn (index_map[j]);
@@ -4181,9 +4237,6 @@ add_label_notes (rtx x, rtx insn)
 static sbitmap *hoist_vbein;
 static sbitmap *hoist_vbeout;
 
-/* Hoistable expressions.  */
-static sbitmap *hoist_exprs;
-
 /* ??? We could compute post dominators and run this algorithm in
    reverse to perform tail merging, doing so would probably be
    more effective than the tail merging code in jump.c.
@@ -4202,7 +4255,6 @@ alloc_code_hoist_mem (int n_blocks, int n_exprs)
 
   hoist_vbein = sbitmap_vector_alloc (n_blocks, n_exprs);
   hoist_vbeout = sbitmap_vector_alloc (n_blocks, n_exprs);
-  hoist_exprs = sbitmap_vector_alloc (n_blocks, n_exprs);
 }
 
 /* Free vars used for code hoisting analysis.  */
@@ -4216,7 +4268,6 @@ free_code_hoist_mem (void)
 
   sbitmap_vector_free (hoist_vbein);
   sbitmap_vector_free (hoist_vbeout);
-  sbitmap_vector_free (hoist_exprs);
 
   free_dominance_info (CDI_DOMINATORS);
 }
@@ -4267,7 +4318,17 @@ compute_code_hoist_vbeinout (void)
     }
 
   if (dump_file)
-    fprintf (dump_file, "hoisting vbeinout computation: %d passes\n", passes);
+    {
+      fprintf (dump_file, "hoisting vbeinout computation: %d passes\n", passes);
+
+      FOR_EACH_BB (bb)
+        {
+         fprintf (dump_file, "vbein (%d): ", bb->index);
+         dump_sbitmap_file (dump_file, hoist_vbein[bb->index]);
+         fprintf (dump_file, "vbeout(%d): ", bb->index);
+         dump_sbitmap_file (dump_file, hoist_vbeout[bb->index]);
+       }
+    }
 }
 
 /* Top level routine to do the dataflow analysis needed by code hoisting.  */
@@ -4370,6 +4431,8 @@ static int
 hoist_code (void)
 {
   basic_block bb, dominated;
+  VEC (basic_block, heap) *dom_tree_walk;
+  unsigned int dom_tree_walk_index;
   VEC (basic_block, heap) *domby;
   unsigned int i,j;
   struct expr **index_map;
@@ -4378,8 +4441,6 @@ hoist_code (void)
   int *bb_size;
   int changed = 0;
 
-  sbitmap_vector_zero (hoist_exprs, last_basic_block);
-
   /* Compute a mapping from expression number (`bitmap_index') to
      hash table entry.  */
 
@@ -4398,54 +4459,84 @@ hoist_code (void)
   FOR_EACH_BB (bb)
     {
       rtx insn;
-      rtx bb_end;
       int to_head;
 
-      insn = BB_HEAD (bb);
-      bb_end = BB_END (bb);
       to_head = 0;
-
-      while (insn != bb_end)
+      FOR_BB_INSNS (bb, insn)
        {
          /* Don't count debug instructions to avoid them affecting
             decision choices.  */
          if (NONDEBUG_INSN_P (insn))
            to_bb_head[INSN_UID (insn)] = to_head++;
-
-         insn = NEXT_INSN (insn);
        }
 
       bb_size[bb->index] = to_head;
     }
 
+  gcc_assert (EDGE_COUNT (ENTRY_BLOCK_PTR->succs) == 1
+             && (EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
+                 == ENTRY_BLOCK_PTR->next_bb));
+
+  dom_tree_walk = get_all_dominated_blocks (CDI_DOMINATORS,
+                                           ENTRY_BLOCK_PTR->next_bb);
+
   /* Walk over each basic block looking for potentially hoistable
      expressions, nothing gets hoisted from the entry block.  */
-  FOR_EACH_BB (bb)
+  FOR_EACH_VEC_ELT (basic_block, dom_tree_walk, dom_tree_walk_index, bb)
     {
-      int found = 0;
-      int insn_inserted_p;
+      domby = get_dominated_to_depth (CDI_DOMINATORS, bb, MAX_HOIST_DEPTH);
+
+      if (VEC_length (basic_block, domby) == 0)
+       continue;
 
-      domby = get_dominated_by (CDI_DOMINATORS, bb);
       /* Examine each expression that is very busy at the exit of this
         block.  These are the potentially hoistable expressions.  */
       for (i = 0; i < hoist_vbeout[bb->index]->n_bits; i++)
        {
-         int hoistable = 0;
-
          if (TEST_BIT (hoist_vbeout[bb->index], i))
            {
+             /* Current expression.  */
+             struct expr *expr = index_map[i];
+             /* Number of occurences of EXPR that can be hoisted to BB.  */
+             int hoistable = 0;
+             /* Basic blocks that have occurences reachable from BB.  */
+             bitmap_head _from_bbs, *from_bbs = &_from_bbs;
+             /* Occurences reachable from BB.  */
+             VEC (occr_t, heap) *occrs_to_hoist = NULL;
+             /* We want to insert the expression into BB only once, so
+                note when we've inserted it.  */
+             int insn_inserted_p;
+             occr_t occr;
+
+             bitmap_initialize (from_bbs, 0);
+
              /* If an expression is computed in BB and is available at end of
                 BB, hoist all occurences dominated by BB to BB.  */
              if (TEST_BIT (comp[bb->index], i))
-               hoistable++;
+               {
+                 occr = find_occr_in_bb (expr->antic_occr, bb);
+
+                 if (occr)
+                   {
+                     /* An occurence might've been already deleted
+                        while processing a dominator of BB.  */
+                     if (occr->deleted_p)
+                       gcc_assert (MAX_HOIST_DEPTH > 1);
+                     else
+                       {
+                         gcc_assert (NONDEBUG_INSN_P (occr->insn));
+                         hoistable++;
+                       }
+                   }
+                 else
+                   hoistable++;
+               }
 
              /* We've found a potentially hoistable expression, now
                 we look at every block BB dominates to see if it
                 computes the expression.  */
-             for (j = 0; VEC_iterate (basic_block, domby, j, dominated); j++)
+             FOR_EACH_VEC_ELT (basic_block, domby, j, dominated)
                {
-                 struct expr *expr = index_map[i];
-                 struct occr *occr = NULL;
                  int max_distance;
 
                  /* Ignore self dominance.  */
@@ -4457,22 +4548,25 @@ hoist_code (void)
                  if (!TEST_BIT (antloc[dominated->index], i))
                    continue;
 
-                 max_distance = expr->max_distance;
-                 if (max_distance > 0)
-                   {
-                     struct occr *occr;
-
-                     occr = find_occr_in_bb (expr->antic_occr, dominated);
-                     gcc_assert (occr);
-
-                     gcc_assert (NONDEBUG_INSN_P (occr->insn));
+                 occr = find_occr_in_bb (expr->antic_occr, dominated);
+                 gcc_assert (occr);
 
-                     /* Adjust MAX_DISTANCE to account for the fact that
-                        OCCR won't have to travel all of DOMINATED, but
-                        only part of it.  */
-                     max_distance += (bb_size[dominated->index]
-                                      - to_bb_head[INSN_UID (occr->insn)]);
+                 /* An occurence might've been already deleted
+                    while processing a dominator of BB.  */
+                 if (occr->deleted_p)
+                   {
+                     gcc_assert (MAX_HOIST_DEPTH > 1);
+                     continue;
                    }
+                 gcc_assert (NONDEBUG_INSN_P (occr->insn));
+
+                 max_distance = expr->max_distance;
+                 if (max_distance > 0)
+                   /* Adjust MAX_DISTANCE to account for the fact that
+                      OCCR won't have to travel all of DOMINATED, but
+                      only part of it.  */
+                   max_distance += (bb_size[dominated->index]
+                                    - to_bb_head[INSN_UID (occr->insn)]);
 
                  /* Note if the expression would reach the dominated block
                     unimpared if it was placed at the end of BB.
@@ -4481,11 +4575,16 @@ hoist_code (void)
                     from a dominated block into BB.  */
                  if (hoist_expr_reaches_here_p (bb, i, dominated, NULL,
                                                 max_distance, bb_size))
-                   hoistable++;
+                   {
+                     hoistable++;
+                     VEC_safe_push (occr_t, heap,
+                                    occrs_to_hoist, occr);
+                     bitmap_set_bit (from_bbs, dominated->index);
+                   }
                }
 
              /* If we found more than one hoistable occurrence of this
-                expression, then note it in the bitmap of expressions to
+                expression, then note it in the vector of expressions to
                 hoist.  It makes no sense to hoist things which are computed
                 in only one BB, and doing so tends to pessimize register
                 allocation.  One could increase this value to try harder
@@ -4496,115 +4595,74 @@ hoist_code (void)
                 to nullify any benefit we get from code hoisting.  */
              if (hoistable > 1 && dbg_cnt (hoist_insn))
                {
-                 SET_BIT (hoist_exprs[bb->index], i);
-                 found = 1;
+                 /* If (hoistable != VEC_length), then there is
+                    an occurence of EXPR in BB itself.  Don't waste
+                    time looking for LCA in this case.  */
+                 if ((unsigned) hoistable
+                     == VEC_length (occr_t, occrs_to_hoist))
+                   {
+                     basic_block lca;
+
+                     lca = nearest_common_dominator_for_set (CDI_DOMINATORS,
+                                                             from_bbs);
+                     if (lca != bb)
+                       /* Punt, it's better to hoist these occurences to
+                          LCA.  */
+                       VEC_free (occr_t, heap, occrs_to_hoist);
+                   }
                }
-           }
-       }
-      /* If we found nothing to hoist, then quit now.  */
-      if (! found)
-        {
-         VEC_free (basic_block, heap, domby);
-         continue;
-       }
+             else
+               /* Punt, no point hoisting a single occurence.  */
+               VEC_free (occr_t, heap, occrs_to_hoist);
 
-      /* Loop over all the hoistable expressions.  */
-      for (i = 0; i < hoist_exprs[bb->index]->n_bits; i++)
-       {
-         /* We want to insert the expression into BB only once, so
-            note when we've inserted it.  */
-         insn_inserted_p = 0;
+             insn_inserted_p = 0;
 
-         /* These tests should be the same as the tests above.  */
-         if (TEST_BIT (hoist_exprs[bb->index], i))
-           {
-             /* We've found a potentially hoistable expression, now
-                we look at every block BB dominates to see if it
-                computes the expression.  */
-             for (j = 0; VEC_iterate (basic_block, domby, j, dominated); j++)
+             /* Walk through occurences of I'th expressions we want
+                to hoist to BB and make the transformations.  */
+             FOR_EACH_VEC_ELT (occr_t, occrs_to_hoist, j, occr)
                {
-                 struct expr *expr = index_map[i];
-                 int max_distance;
-
-                 /* Ignore self dominance.  */
-                 if (bb == dominated)
-                   continue;
-
-                 /* We've found a dominated block, now see if it computes
-                    the busy expression and whether or not moving that
-                    expression to the "beginning" of that block is safe.  */
-                 if (!TEST_BIT (antloc[dominated->index], i))
-                   continue;
-
-                 max_distance = expr->max_distance;
-                 if (max_distance > 0)
+                 rtx insn;
+                 rtx set;
+
+                 gcc_assert (!occr->deleted_p);
+
+                 insn = occr->insn;
+                 set = single_set (insn);
+                 gcc_assert (set);
+
+                 /* Create a pseudo-reg to store the result of reaching
+                    expressions into.  Get the mode for the new pseudo
+                    from the mode of the original destination pseudo.
+
+                    It is important to use new pseudos whenever we
+                    emit a set.  This will allow reload to use
+                    rematerialization for such registers.  */
+                 if (!insn_inserted_p)
+                   expr->reaching_reg
+                     = gen_reg_rtx_and_attrs (SET_DEST (set));
+
+                 gcse_emit_move_after (expr->reaching_reg, SET_DEST (set),
+                                       insn);
+                 delete_insn (insn);
+                 occr->deleted_p = 1;
+                 changed = 1;
+                 gcse_subst_count++;
+
+                 if (!insn_inserted_p)
                    {
-                     occr = find_occr_in_bb (expr->antic_occr, dominated);
-                     gcc_assert (occr);
-
-                     gcc_assert (NONDEBUG_INSN_P (occr->insn));
-
-                     /* Adjust MAX_DISTANCE to account for the fact that
-                        OCCR won't have to travel all of DOMINATED, but
-                        only part of it.  */
-                     max_distance += (bb_size[dominated->index]
-                                      - to_bb_head[INSN_UID (occr->insn)]);
-                   }
-
-                 /* The expression is computed in the dominated block and
-                    it would be safe to compute it at the start of the
-                    dominated block.  Now we have to determine if the
-                    expression would reach the dominated block if it was
-                    placed at the end of BB.
-                    Note: the fact that hoist_exprs has i-th bit set means
-                    that /some/, not necesserilly all, occurences from
-                    the dominated blocks can be hoisted to BB.  Here we check
-                    if a specific occurence can be hoisted to BB.  */
-                 if (hoist_expr_reaches_here_p (bb, i, dominated, NULL,
-                                                max_distance, bb_size))
-                   {
-                     rtx insn;
-                     rtx set;
-
-                     if (!occr)
-                       {
-                         occr = find_occr_in_bb (expr->antic_occr, dominated);
-                         gcc_assert (occr);
-                       }
-
-                     insn = occr->insn;
-                     set = single_set (insn);
-                     gcc_assert (set);
-
-                     /* Create a pseudo-reg to store the result of reaching
-                        expressions into.  Get the mode for the new pseudo
-                        from the mode of the original destination pseudo.
-
-                        It is important to use new pseudos whenever we
-                        emit a set.  This will allow reload to use
-                        rematerialization for such registers.  */
-                     if (!insn_inserted_p)
-                       expr->reaching_reg
-                         = gen_reg_rtx_and_attrs (SET_DEST (set));
-
-                     gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn);
-                     delete_insn (insn);
-                     occr->deleted_p = 1;
-                     changed = 1;
-                     gcse_subst_count++;
-
-                     if (!insn_inserted_p)
-                       {
-                         insert_insn_end_basic_block (index_map[i], bb, 0);
-                         insn_inserted_p = 1;
-                       }
+                     insert_insn_end_basic_block (expr, bb);
+                     insn_inserted_p = 1;
                    }
                }
+
+             VEC_free (occr_t, heap, occrs_to_hoist);
+             bitmap_clear (from_bbs);
            }
        }
       VEC_free (basic_block, heap, domby);
     }
 
+  VEC_free (basic_block, heap, dom_tree_walk);
   free (bb_size);
   free (to_bb_head);
   free (index_map);
@@ -5259,10 +5317,14 @@ gate_rtl_cprop (void)
 static unsigned int
 execute_rtl_cprop (void)
 {
+  int changed;
   delete_unreachable_blocks ();
   df_set_flags (DF_LR_RUN_DCE);
   df_analyze ();
-  flag_rerun_cse_after_global_opts |= one_cprop_pass ();
+  changed = one_cprop_pass ();
+  flag_rerun_cse_after_global_opts |= changed;
+  if (changed)
+    cleanup_cfg (0);
   return 0;
 }
 
@@ -5278,9 +5340,13 @@ gate_rtl_pre (void)
 static unsigned int
 execute_rtl_pre (void)
 {
+  int changed;
   delete_unreachable_blocks ();
   df_analyze ();
-  flag_rerun_cse_after_global_opts |= one_pre_gcse_pass ();
+  changed = one_pre_gcse_pass ();
+  flag_rerun_cse_after_global_opts |= changed;
+  if (changed)
+    cleanup_cfg (0);
   return 0;
 }
 
@@ -5299,9 +5365,13 @@ gate_rtl_hoist (void)
 static unsigned int
 execute_rtl_hoist (void)
 {
+  int changed;
   delete_unreachable_blocks ();
   df_analyze ();
-  flag_rerun_cse_after_global_opts |= one_code_hoisting_pass ();
+  changed = one_code_hoisting_pass ();
+  flag_rerun_cse_after_global_opts |= changed;
+  if (changed)
+    cleanup_cfg (0);
   return 0;
 }
 
@@ -5369,3 +5439,4 @@ struct rtl_opt_pass pass_rtl_hoist =
 };
 
 #include "gt-gcse.h"
+