OSDN Git Service

* Makefile.def (target_modules): Add libssp.
[pf3gnuchains/gcc-fork.git] / gcc / gcse.c
index bddbbb4..d8a1d25 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,8 +17,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* TODO
    - reordering of memory allocation and freeing to be more space efficient
@@ -264,19 +264,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    the result of the expression is copied to a new register, and the redundant
    expression is deleted by replacing it with this new register.  Classic GCSE
    doesn't have this problem as much as it computes the reaching defs of
-   each register in each block and thus can try to use an existing register.
-
-   **********************
-
-   A fair bit of simplicity is created by creating small functions for simple
-   tasks, even when the function is only called in one place.  This may
-   measurably slow things down [or may not] by creating more function call
-   overhead than is necessary.  The source is laid out so that it's trivial
-   to make the affected functions inline so that one can measure what speed
-   up, if any, can be achieved, and maybe later when things settle things can
-   be rearranged.
-
-   Help stamp out big monolithic functions!  */
+   each register in each block and thus can try to use an existing
+   register.  */
 \f
 /* GCSE global vars.  */
 
@@ -436,8 +425,8 @@ typedef struct reg_set
 {
   /* The next setting of this register.  */
   struct reg_set *next;
-  /* The insn where it was set.  */
-  rtx insn;
+  /* The index of the block where it was set.  */
+  int bb_index;
 } reg_set;
 
 static reg_set **reg_set_table;
@@ -500,7 +489,10 @@ static bitmap modify_mem_list_set;
 
 /* This array parallels modify_mem_list, but is kept canonicalized.  */
 static rtx * canon_modify_mem_list;
-static bitmap canon_modify_mem_list_set;
+
+/* Bitmap indexed by block numbers to record which blocks contain
+   function calls.  */
+static bitmap blocks_with_calls;
 
 /* Various variables for statistics gathering.  */
 
@@ -515,43 +507,28 @@ static int gcse_subst_count;
 static int gcse_create_count;
 /* Number of local constants propagated.  */
 static int local_const_prop_count;
-/* Number of local copys propagated.  */
+/* Number of local copies propagated.  */
 static int local_copy_prop_count;
 /* Number of global constants propagated.  */
 static int global_const_prop_count;
-/* Number of global copys propagated.  */
+/* Number of global copies propagated.  */
 static int global_copy_prop_count;
 \f
 /* For available exprs */
 static sbitmap *ae_kill, *ae_gen;
-
-/* Objects of this type are passed around by the null-pointer check
-   removal routines.  */
-struct null_pointer_info
-{
-  /* The basic block being processed.  */
-  basic_block current_block;
-  /* The first register to be handled in this pass.  */
-  unsigned int min_reg;
-  /* One greater than the last register to be handled in this pass.  */
-  unsigned int max_reg;
-  sbitmap *nonnull_local;
-  sbitmap *nonnull_killed;
-};
 \f
 static void compute_can_copy (void);
 static void *gmalloc (size_t) ATTRIBUTE_MALLOC;
 static void *gcalloc (size_t, size_t) ATTRIBUTE_MALLOC;
 static void *grealloc (void *, size_t);
 static void *gcse_alloc (unsigned long);
-static void alloc_gcse_mem (rtx);
+static void alloc_gcse_mem (void);
 static void free_gcse_mem (void);
 static void alloc_reg_set_mem (int);
 static void free_reg_set_mem (void);
 static void record_one_set (int, rtx);
-static void replace_one_set (int, rtx, rtx);
 static void record_set_info (rtx, rtx, void *);
-static void compute_sets (rtx);
+static void compute_sets (void);
 static void hash_scan_insn (rtx, struct hash_table *, int);
 static void hash_scan_set (rtx, rtx, struct hash_table *);
 static void hash_scan_clobber (rtx, rtx, struct hash_table *);
@@ -601,8 +578,8 @@ static void canon_list_insert (rtx, rtx, void *);
 static int cprop_insn (rtx, int);
 static int cprop (int);
 static void find_implicit_sets (void);
-static int one_cprop_pass (int, int, int);
-static bool constprop_register (rtx, rtx, rtx, int);
+static int one_cprop_pass (int, bool, bool);
+static bool constprop_register (rtx, rtx, rtx, bool);
 static struct expr *find_bypass_set (int, int);
 static bool reg_killed_on_edge (rtx, edge);
 static int bypass_block (basic_block, rtx, rtx);
@@ -668,17 +645,18 @@ static void clear_modify_mem_tables (void);
 static void free_modify_mem_tables (void);
 static rtx gcse_emit_move_after (rtx, rtx, rtx);
 static void local_cprop_find_used_regs (rtx *, void *);
-static bool do_local_cprop (rtx, rtx, int, rtx*);
+static bool do_local_cprop (rtx, rtx, bool, rtx*);
 static bool adjust_libcall_notes (rtx, rtx, rtx, rtx*);
-static void local_cprop_pass (int);
+static void local_cprop_pass (bool);
 static bool is_too_expensive (const char *);
 \f
 
 /* Entry point for global common subexpression elimination.
-   F is the first instruction in the function.  */
+   F is the first instruction in the function.  Return nonzero if a
+   change is mode.  */
 
 int
-gcse_main (rtx f, FILE *file)
+gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file)
 {
   int changed, pass;
   /* Bytes used at start of pass.  */
@@ -726,7 +704,7 @@ gcse_main (rtx f, FILE *file)
      information about memory sets when we build the hash tables.  */
 
   alloc_reg_set_mem (max_gcse_regno);
-  compute_sets (f);
+  compute_sets ();
 
   pass = 0;
   initial_bytes_used = bytes_used;
@@ -746,12 +724,12 @@ gcse_main (rtx f, FILE *file)
       /* Each pass may create new registers, so recalculate each time.  */
       max_gcse_regno = max_reg_num ();
 
-      alloc_gcse_mem (f);
+      alloc_gcse_mem ();
 
       /* Don't allow constant propagation to modify jumps
         during this pass.  */
       timevar_push (TV_CPROP1);
-      changed = one_cprop_pass (pass + 1, 0, 0);
+      changed = one_cprop_pass (pass + 1, false, false);
       timevar_pop (TV_CPROP1);
 
       if (optimize_size)
@@ -771,7 +749,7 @@ gcse_main (rtx f, FILE *file)
            }
          free_reg_set_mem ();
          alloc_reg_set_mem (max_reg_num ());
-         compute_sets (f);
+         compute_sets ();
          run_jump_opt_after_gcse = 1;
          timevar_pop (TV_PRE);
        }
@@ -793,7 +771,7 @@ gcse_main (rtx f, FILE *file)
        {
          timevar_push (TV_HOIST);
          max_gcse_regno = max_reg_num ();
-         alloc_gcse_mem (f);
+         alloc_gcse_mem ();
          changed |= one_code_hoisting_pass ();
          free_gcse_mem ();
 
@@ -816,10 +794,10 @@ gcse_main (rtx f, FILE *file)
      conditional jumps.  */
 
   max_gcse_regno = max_reg_num ();
-  alloc_gcse_mem (f);
+  alloc_gcse_mem ();
   /* This time, go ahead and allow cprop to alter jumps.  */
   timevar_push (TV_CPROP2);
-  one_cprop_pass (pass + 1, 1, 0);
+  one_cprop_pass (pass + 1, true, false);
   timevar_pop (TV_CPROP2);
   free_gcse_mem ();
 
@@ -945,35 +923,42 @@ gcse_alloc (unsigned long size)
    This is called at the start of each pass.  */
 
 static void
-alloc_gcse_mem (rtx f)
+alloc_gcse_mem (void)
 {
   int i;
+  basic_block bb;
   rtx insn;
 
   /* Find the largest UID and create a mapping from UIDs to CUIDs.
      CUIDs are like UIDs except they increase monotonically, have no gaps,
-     and only apply to real insns.  */
+     and only apply to real insns.
+     (Actually, there are gaps, for insn that are not inside a basic block.
+     but we should never see those anyway, so this is OK.)  */
 
   max_uid = get_max_uid ();
   uid_cuid = gcalloc (max_uid + 1, sizeof (int));
-  for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
-    {
-      if (INSN_P (insn))
-       uid_cuid[INSN_UID (insn)] = i++;
-      else
-       uid_cuid[INSN_UID (insn)] = i;
-    }
+  i = 0;
+  FOR_EACH_BB (bb)
+    FOR_BB_INSNS (bb, insn)
+      {
+       if (INSN_P (insn))
+         uid_cuid[INSN_UID (insn)] = i++;
+       else
+         uid_cuid[INSN_UID (insn)] = i;
+      }
 
   /* Create a table mapping cuids to insns.  */
 
   max_cuid = i;
   cuid_insn = gcalloc (max_cuid + 1, sizeof (rtx));
-  for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      CUID_INSN (i++) = insn;
+  i = 0;
+  FOR_EACH_BB (bb)
+    FOR_BB_INSNS (bb, insn)
+      if (INSN_P (insn))
+       CUID_INSN (i++) = insn;
 
   /* Allocate vars to track sets of regs.  */
-  reg_set_bitmap = BITMAP_XMALLOC ();
+  reg_set_bitmap = BITMAP_ALLOC (NULL);
 
   /* Allocate vars to track sets of regs, memory per block.  */
   reg_set_in_block = sbitmap_vector_alloc (last_basic_block, max_gcse_regno);
@@ -981,8 +966,8 @@ alloc_gcse_mem (rtx f)
      basic block.  */
   modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
   canon_modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
-  modify_mem_list_set = BITMAP_XMALLOC ();
-  canon_modify_mem_list_set = BITMAP_XMALLOC ();
+  modify_mem_list_set = BITMAP_ALLOC (NULL);
+  blocks_with_calls = BITMAP_ALLOC (NULL);
 }
 
 /* Free memory allocated by alloc_gcse_mem.  */
@@ -993,12 +978,12 @@ free_gcse_mem (void)
   free (uid_cuid);
   free (cuid_insn);
 
-  BITMAP_XFREE (reg_set_bitmap);
+  BITMAP_FREE (reg_set_bitmap);
 
   sbitmap_vector_free (reg_set_in_block);
   free_modify_mem_tables ();
-  BITMAP_XFREE (modify_mem_list_set);
-  BITMAP_XFREE (canon_modify_mem_list_set);
+  BITMAP_FREE (modify_mem_list_set);
+  BITMAP_FREE (blocks_with_calls);
 }
 \f
 /* Compute the local properties of each recorded expression.
@@ -1117,24 +1102,6 @@ free_reg_set_mem (void)
   obstack_free (&reg_set_obstack, NULL);
 }
 
-/* An OLD_INSN that used to set REGNO was replaced by NEW_INSN.
-   Update the corresponding `reg_set_table' entry accordingly.
-   We assume that NEW_INSN is not already recorded in reg_set_table[regno].  */
-
-static void
-replace_one_set (int regno, rtx old_insn, rtx new_insn)
-{
-  struct reg_set *reg_info;
-  if (regno >= reg_set_table_size)
-    return;
-  for (reg_info = reg_set_table[regno]; reg_info; reg_info = reg_info->next)
-    if (reg_info->insn == old_insn)
-      {
-        reg_info->insn = new_insn;
-        break;
-      }
-}
-
 /* Record REGNO in the reg_set table.  */
 
 static void
@@ -1157,7 +1124,7 @@ record_one_set (int regno, rtx insn)
 
   new_reg_info = obstack_alloc (&reg_set_obstack, sizeof (struct reg_set));
   bytes_used += sizeof (struct reg_set);
-  new_reg_info->insn = insn;
+  new_reg_info->bb_index = BLOCK_NUM (insn);
   new_reg_info->next = reg_set_table[regno];
   reg_set_table[regno] = new_reg_info;
 }
@@ -1181,13 +1148,15 @@ record_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data)
    `reg_set_table' for further documentation.  */
 
 static void
-compute_sets (rtx f)
+compute_sets (void)
 {
+  basic_block bb;
   rtx insn;
 
-  for (insn = f; insn != 0; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      note_stores (PATTERN (insn), record_set_info, insn);
+  FOR_EACH_BB (bb)
+    FOR_BB_INSNS (bb, insn)
+      if (INSN_P (insn))
+       note_stores (PATTERN (insn), record_set_info, insn);
 }
 \f
 /* Hash table support.  */
@@ -1365,7 +1334,6 @@ mems_conflict_for_gcse_p (rtx dest, rtx setter ATTRIBUTE_UNUSED,
 {
   while (GET_CODE (dest) == SUBREG
         || GET_CODE (dest) == ZERO_EXTRACT
-        || GET_CODE (dest) == SIGN_EXTRACT
         || GET_CODE (dest) == STRICT_LOW_PART)
     dest = XEXP (dest, 0);
 
@@ -1402,6 +1370,11 @@ static int
 load_killed_in_block_p (basic_block bb, int uid_limit, rtx x, int avail_p)
 {
   rtx list_entry = modify_mem_list[bb->index];
+
+  /* If this is a readonly then we aren't going to be changing it.  */
+  if (MEM_READONLY_P (x))
+    return 0;
+
   while (list_entry)
     {
       rtx setter;
@@ -1518,7 +1491,6 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
   unsigned int hash;
   struct expr *cur_expr, *last_expr = NULL;
   struct occr *antic_occr, *avail_occr;
-  struct occr *last_occr = NULL;
 
   hash = hash_expr (x, mode, &do_not_record_p, table->size);
 
@@ -1563,14 +1535,8 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
     {
       antic_occr = cur_expr->antic_occr;
 
-      /* Search for another occurrence in the same basic block.  */
-      while (antic_occr && BLOCK_NUM (antic_occr->insn) != BLOCK_NUM (insn))
-       {
-         /* If an occurrence isn't found, save a pointer to the end of
-            the list.  */
-         last_occr = antic_occr;
-         antic_occr = antic_occr->next;
-       }
+      if (antic_occr && BLOCK_NUM (antic_occr->insn) != BLOCK_NUM (insn))
+       antic_occr = NULL;
 
       if (antic_occr)
        /* Found another instance of the expression in the same basic block.
@@ -1582,15 +1548,10 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
          /* First occurrence of this expression in this basic block.  */
          antic_occr = gcse_alloc (sizeof (struct occr));
          bytes_used += sizeof (struct occr);
-         /* First occurrence of this expression in any block?  */
-         if (cur_expr->antic_occr == NULL)
-           cur_expr->antic_occr = antic_occr;
-         else
-           last_occr->next = antic_occr;
-
          antic_occr->insn = insn;
-         antic_occr->next = NULL;
+         antic_occr->next = cur_expr->antic_occr;
          antic_occr->deleted_p = 0;
+         cur_expr->antic_occr = antic_occr;
        }
     }
 
@@ -1598,36 +1559,23 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
     {
       avail_occr = cur_expr->avail_occr;
 
-      /* Search for another occurrence in the same basic block.  */
-      while (avail_occr && BLOCK_NUM (avail_occr->insn) != BLOCK_NUM (insn))
+      if (avail_occr && BLOCK_NUM (avail_occr->insn) == BLOCK_NUM (insn))
        {
-         /* If an occurrence isn't found, save a pointer to the end of
-            the list.  */
-         last_occr = avail_occr;
-         avail_occr = avail_occr->next;
+         /* Found another instance of the expression in the same basic block.
+            Prefer this occurrence to the currently recorded one.  We want
+            the last one in the block and the block is scanned from start
+            to end.  */
+         avail_occr->insn = insn;
        }
-
-      if (avail_occr)
-       /* Found another instance of the expression in the same basic block.
-          Prefer this occurrence to the currently recorded one.  We want
-          the last one in the block and the block is scanned from start
-          to end.  */
-       avail_occr->insn = insn;
       else
        {
          /* First occurrence of this expression in this basic block.  */
          avail_occr = gcse_alloc (sizeof (struct occr));
          bytes_used += sizeof (struct occr);
-
-         /* First occurrence of this expression in any block?  */
-         if (cur_expr->avail_occr == NULL)
-           cur_expr->avail_occr = avail_occr;
-         else
-           last_occr->next = avail_occr;
-
          avail_occr->insn = insn;
-         avail_occr->next = NULL;
+         avail_occr->next = cur_expr->avail_occr;
          avail_occr->deleted_p = 0;
+         cur_expr->avail_occr = avail_occr;
        }
     }
 }
@@ -1643,7 +1591,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table)
   int found;
   unsigned int hash;
   struct expr *cur_expr, *last_expr = NULL;
-  struct occr *cur_occr, *last_occr = NULL;
+  struct occr *cur_occr;
 
   gcc_assert (GET_CODE (x) == SET && REG_P (SET_DEST (x)));
 
@@ -1684,35 +1632,24 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table)
   /* Now record the occurrence.  */
   cur_occr = cur_expr->avail_occr;
 
-  /* Search for another occurrence in the same basic block.  */
-  while (cur_occr && BLOCK_NUM (cur_occr->insn) != BLOCK_NUM (insn))
+  if (cur_occr && BLOCK_NUM (cur_occr->insn) == BLOCK_NUM (insn))
     {
-      /* If an occurrence isn't found, save a pointer to the end of
-        the list.  */
-      last_occr = cur_occr;
-      cur_occr = cur_occr->next;
+      /* Found another instance of the expression in the same basic block.
+        Prefer this occurrence to the currently recorded one.  We want
+        the last one in the block and the block is scanned from start
+        to end.  */
+      cur_occr->insn = insn;
     }
-
-  if (cur_occr)
-    /* Found another instance of the expression in the same basic block.
-       Prefer this occurrence to the currently recorded one.  We want the
-       last one in the block and the block is scanned from start to end.  */
-    cur_occr->insn = insn;
   else
     {
       /* First occurrence of this expression in this basic block.  */
       cur_occr = gcse_alloc (sizeof (struct occr));
       bytes_used += sizeof (struct occr);
 
-      /* First occurrence of this expression in any block?  */
-      if (cur_expr->avail_occr == NULL)
-       cur_expr->avail_occr = cur_occr;
-      else
-       last_occr->next = cur_occr;
-
-      cur_occr->insn = insn;
-      cur_occr->next = NULL;
-      cur_occr->deleted_p = 0;
+         cur_occr->insn = insn;
+         cur_occr->next = cur_expr->avail_occr;
+         cur_occr->deleted_p = 0;
+         cur_expr->avail_occr = cur_occr;
     }
 }
 
@@ -2001,7 +1938,6 @@ canon_list_insert (rtx dest ATTRIBUTE_UNUSED, rtx unused1 ATTRIBUTE_UNUSED,
 
   while (GET_CODE (dest) == SUBREG
       || GET_CODE (dest) == ZERO_EXTRACT
-      || GET_CODE (dest) == SIGN_EXTRACT
       || GET_CODE (dest) == STRICT_LOW_PART)
     dest = XEXP (dest, 0);
 
@@ -2021,7 +1957,6 @@ canon_list_insert (rtx dest ATTRIBUTE_UNUSED, rtx unused1 ATTRIBUTE_UNUSED,
     alloc_EXPR_LIST (VOIDmode, dest_addr, canon_modify_mem_list[bb]);
   canon_modify_mem_list[bb] =
     alloc_EXPR_LIST (VOIDmode, dest, canon_modify_mem_list[bb]);
-  bitmap_set_bit (canon_modify_mem_list_set, bb);
 }
 
 /* Record memory modification information for INSN.  We do not actually care
@@ -2045,7 +1980,7 @@ record_last_mem_set_info (rtx insn)
         need to insert a pair of items, as canon_list_insert does.  */
       canon_modify_mem_list[bb] =
        alloc_INSN_LIST (insn, canon_modify_mem_list[bb]);
-      bitmap_set_bit (canon_modify_mem_list_set, bb);
+      bitmap_set_bit (blocks_with_calls, bb);
     }
   else
     note_stores (PATTERN (insn), canon_list_insert, (void*) insn);
@@ -2117,9 +2052,7 @@ compute_hash_table_work (struct hash_table *table)
         ??? hard-reg reg_set_in_block computation
         could be moved to compute_sets since they currently don't change.  */
 
-      for (insn = BB_HEAD (current_bb);
-          insn && insn != NEXT_INSN (BB_END (current_bb));
-          insn = NEXT_INSN (insn))
+      FOR_BB_INSNS (current_bb, insn)
        {
          if (! INSN_P (insn))
            continue;
@@ -2143,10 +2076,8 @@ compute_hash_table_work (struct hash_table *table)
                       BB_HEAD (current_bb), table);
 
       /* The next pass builds the hash table.  */
-
-      for (insn = BB_HEAD (current_bb), in_libcall_block = 0;
-          insn && insn != NEXT_INSN (BB_END (current_bb));
-          insn = NEXT_INSN (insn))
+      in_libcall_block = 0;
+      FOR_BB_INSNS (current_bb, insn)
        if (INSN_P (insn))
          {
            if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
@@ -2269,17 +2200,13 @@ clear_modify_mem_tables (void)
   EXECUTE_IF_SET_IN_BITMAP (modify_mem_list_set, 0, i, bi)
     {
       free_INSN_LIST_list (modify_mem_list + i);
-    }
-  bitmap_clear (modify_mem_list_set);
-
-  EXECUTE_IF_SET_IN_BITMAP (canon_modify_mem_list_set, 0, i, bi)
-    {
       free_insn_expr_list_list (canon_modify_mem_list + i);
     }
-  bitmap_clear (canon_modify_mem_list_set);
+  bitmap_clear (modify_mem_list_set);
+  bitmap_clear (blocks_with_calls);
 }
 
-/* Release memory used by modify_mem_list_set and canon_modify_mem_list_set.  */
+/* Release memory used by modify_mem_list_set.  */
 
 static void
 free_modify_mem_tables (void)
@@ -2389,7 +2316,6 @@ mark_set (rtx pat, rtx insn)
 
   while (GET_CODE (dest) == SUBREG
         || GET_CODE (dest) == ZERO_EXTRACT
-        || GET_CODE (dest) == SIGN_EXTRACT
         || GET_CODE (dest) == STRICT_LOW_PART)
     dest = XEXP (dest, 0);
 
@@ -2520,7 +2446,7 @@ compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
          else
            {
              for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
-               SET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
+               SET_BIT (bmap[r->bb_index], indx);
            }
        }
       else
@@ -2534,47 +2460,59 @@ compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
          else
            {
              for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
-               RESET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
+               RESET_BIT (bmap[r->bb_index], indx);
            }
        }
 
       return;
 
     case MEM:
-      FOR_EACH_BB (bb)
+      if (! MEM_READONLY_P (x))
        {
-         rtx list_entry = canon_modify_mem_list[bb->index];
+         bitmap_iterator bi;
+         unsigned bb_index;
 
-         while (list_entry)
+         /* First handle all the blocks with calls.  We don't need to
+            do any list walking for them.  */
+         EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi)
            {
-             rtx dest, dest_addr;
+             if (set_p)
+               SET_BIT (bmap[bb_index], indx);
+             else
+               RESET_BIT (bmap[bb_index], indx);
+           }
 
-             if (CALL_P (XEXP (list_entry, 0)))
-               {
-                 if (set_p)
-                   SET_BIT (bmap[bb->index], indx);
-                 else
-                   RESET_BIT (bmap[bb->index], indx);
-                 break;
-               }
-             /* LIST_ENTRY must be an INSN of some kind that sets memory.
-                Examine each hunk of memory that is modified.  */
+           /* Now iterate over the blocks which have memory modifications
+              but which do not have any calls.  */
+           EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set, 
+                                           blocks_with_calls,
+                                           0, bb_index, bi)
+             {
+               rtx list_entry = canon_modify_mem_list[bb_index];
 
-             dest = XEXP (list_entry, 0);
-             list_entry = XEXP (list_entry, 1);
-             dest_addr = XEXP (list_entry, 0);
+               while (list_entry)
+                 {
+                   rtx dest, dest_addr;
 
-             if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
-                                        x, rtx_addr_varies_p))
-               {
-                 if (set_p)
-                   SET_BIT (bmap[bb->index], indx);
-                 else
-                   RESET_BIT (bmap[bb->index], indx);
-                 break;
-               }
-             list_entry = XEXP (list_entry, 1);
-           }
+                   /* LIST_ENTRY must be an INSN of some kind that sets memory.
+                      Examine each hunk of memory that is modified.  */
+
+                   dest = XEXP (list_entry, 0);
+                   list_entry = XEXP (list_entry, 1);
+                   dest_addr = XEXP (list_entry, 0);
+
+                   if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
+                                              x, rtx_addr_varies_p))
+                     {
+                       if (set_p)
+                         SET_BIT (bmap[bb_index], indx);
+                       else
+                         RESET_BIT (bmap[bb_index], indx);
+                       break;
+                     }
+                   list_entry = XEXP (list_entry, 1);
+                 }
+             }
        }
 
       x = XEXP (x, 0);
@@ -2738,8 +2676,7 @@ try_replace_reg (rtx from, rtx to, rtx insn)
         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 (XEXP (set, 0)) != ZERO_EXTRACT
-         && GET_CODE (XEXP (set, 0)) != SIGN_EXTRACT)
+         && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT)
        note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
     }
 
@@ -2927,7 +2864,7 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
 }
 
 static bool
-constprop_register (rtx insn, rtx from, rtx to, int alter_jumps)
+constprop_register (rtx insn, rtx from, rtx to, bool alter_jumps)
 {
   rtx sset;
 
@@ -3105,7 +3042,7 @@ local_cprop_find_used_regs (rtx *xptr, void *data)
    their REG_EQUAL notes need updating.  */
 
 static bool
-do_local_cprop (rtx x, rtx insn, int alter_jumps, rtx *libcall_sp)
+do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
 {
   rtx newreg = NULL, newcnst = NULL;
 
@@ -3223,9 +3160,14 @@ adjust_libcall_notes (rtx oldreg, rtx newval, rtx insn, rtx *libcall_sp)
 
 #define MAX_NESTED_LIBCALLS 9
 
+/* Do local const/copy propagation (i.e. within each basic block).
+   If ALTER_JUMPS is true, allow propagating into jump insns, which
+   could modify the CFG.  */
+
 static void
-local_cprop_pass (int alter_jumps)
+local_cprop_pass (bool alter_jumps)
 {
+  basic_block bb;
   rtx insn;
   struct reg_use *reg_used;
   rtx libcall_stack[MAX_NESTED_LIBCALLS + 1], *libcall_sp;
@@ -3234,51 +3176,62 @@ local_cprop_pass (int alter_jumps)
   cselib_init (false);
   libcall_sp = &libcall_stack[MAX_NESTED_LIBCALLS];
   *libcall_sp = 0;
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+  FOR_EACH_BB (bb)
     {
-      if (INSN_P (insn))
+      FOR_BB_INSNS (bb, insn)
        {
-         rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
-
-         if (note)
-           {
-             gcc_assert (libcall_sp != libcall_stack);
-             *--libcall_sp = XEXP (note, 0);
-           }
-         note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
-         if (note)
-           libcall_sp++;
-         note = find_reg_equal_equiv_note (insn);
-         do
+         if (INSN_P (insn))
            {
-             reg_use_count = 0;
-             note_uses (&PATTERN (insn), local_cprop_find_used_regs, NULL);
-             if (note)
-               local_cprop_find_used_regs (&XEXP (note, 0), NULL);
+             rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
 
-             for (reg_used = &reg_use_table[0]; reg_use_count > 0;
-                  reg_used++, reg_use_count--)
-               if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps,
-                   libcall_sp))
-                 {
-                   changed = true;
+             if (note)
+               {
+                 gcc_assert (libcall_sp != libcall_stack);
+                 *--libcall_sp = XEXP (note, 0);
+               }
+             note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
+             if (note)
+               libcall_sp++;
+             note = find_reg_equal_equiv_note (insn);
+             do
+               {
+                 reg_use_count = 0;
+                 note_uses (&PATTERN (insn), local_cprop_find_used_regs,
+                            NULL);
+                 if (note)
+                   local_cprop_find_used_regs (&XEXP (note, 0), NULL);
+
+                 for (reg_used = &reg_use_table[0]; reg_use_count > 0;
+                      reg_used++, reg_use_count--)
+                   if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps,
+                       libcall_sp))
+                     {
+                       changed = true;
+                       break;
+                     }
+                 if (INSN_DELETED_P (insn))
                    break;
-                 }
-             if (INSN_DELETED_P (insn))
-               break;
+               }
+             while (reg_use_count);
            }
-         while (reg_use_count);
+         cselib_process_insn (insn);
        }
-      cselib_process_insn (insn);
+
+      /* Forget everything at the end of a basic block.  Make sure we are
+        not inside a libcall, they should never cross basic blocks.  */
+      cselib_clear_table ();
+      gcc_assert (libcall_sp == &libcall_stack[MAX_NESTED_LIBCALLS]);
     }
+
   cselib_finish ();
+
   /* Global analysis may get into infinite loops for unreachable blocks.  */
   if (changed && alter_jumps)
     {
       delete_unreachable_blocks ();
       free_reg_set_mem ();
       alloc_reg_set_mem (max_reg_num ());
-      compute_sets (get_insns ());
+      compute_sets ();
     }
 }
 
@@ -3307,9 +3260,7 @@ cprop (int alter_jumps)
         start of the block].  */
       reset_opr_set_tables ();
 
-      for (insn = BB_HEAD (bb);
-          insn != NULL && insn != NEXT_INSN (BB_END (bb));
-          insn = NEXT_INSN (insn))
+      FOR_BB_INSNS (bb, insn)
        if (INSN_P (insn))
          {
            changed |= cprop_insn (insn, alter_jumps);
@@ -3335,7 +3286,7 @@ cprop (int alter_jumps)
    settle for the condition variable in the jump instruction being integral.
    We prefer to be able to record the value of a user variable, rather than
    the value of a temporary used in a condition.  This could be solved by
-   recording the value of *every* register scaned by canonicalize_condition,
+   recording the value of *every* register scanned by canonicalize_condition,
    but this would require some code reorganization.  */
 
 rtx
@@ -3406,7 +3357,7 @@ find_implicit_sets (void)
            dest = GET_CODE (cond) == EQ ? BRANCH_EDGE (bb)->dest
                                         : FALLTHRU_EDGE (bb)->dest;
 
-           if (dest && EDGE_COUNT (dest->preds) == 1
+           if (dest && single_pred_p (dest)
                && dest != EXIT_BLOCK_PTR)
              {
                new = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
@@ -3433,7 +3384,7 @@ find_implicit_sets (void)
    perform conditional jump bypassing optimizations.  */
 
 static int
-one_cprop_pass (int pass, int cprop_jumps, int bypass_jumps)
+one_cprop_pass (int pass, bool cprop_jumps, bool bypass_jumps)
 {
   int changed = 0;
 
@@ -3471,7 +3422,7 @@ one_cprop_pass (int pass, int cprop_jumps, int bypass_jumps)
     {
       fprintf (gcse_file, "CPROP of %s, pass %d: %d bytes needed, ",
               current_function_name (), pass, bytes_used);
-      fprintf (gcse_file, "%d local const props, %d local copy props\n\n",
+      fprintf (gcse_file, "%d local const props, %d local copy props",
               local_const_prop_count, local_copy_prop_count);
       fprintf (gcse_file, "%d global const props, %d global copy props\n\n",
               global_const_prop_count, global_copy_prop_count);
@@ -3656,16 +3607,11 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
            }
          else if (GET_CODE (new) == LABEL_REF)
            {
-             edge_iterator ei2;
-
              dest = BLOCK_FOR_INSN (XEXP (new, 0));
              /* Don't bypass edges containing instructions.  */
-             FOR_EACH_EDGE (edest, ei2, bb->succs)
-               if (edest->dest == dest && edest->insns.r)
-                 {
-                   dest = NULL;
-                   break;
-                 }
+             edest = find_edge (bb, dest);
+             if (edest && edest->insns.r)
+               dest = NULL;
            }
          else
            dest = NULL;
@@ -3674,18 +3620,9 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
             branch.  We would end up emitting the instruction on "both"
             edges.  */
 
-         if (dest && setcc && !CC0_P (SET_DEST (PATTERN (setcc))))
-           {
-             edge e2;
-             edge_iterator ei2;
-
-             FOR_EACH_EDGE (e2, ei2, e->src->succs)
-               if (e2->dest == dest)
-                 {
-                   dest = NULL;
-                   break;
-                 }
-           }
+         if (dest && setcc && !CC0_P (SET_DEST (PATTERN (setcc)))
+             && find_edge (e->src, dest))
+           dest = NULL;
 
          old_dest = e->dest;
          if (dest != NULL
@@ -3751,12 +3688,10 @@ bypass_conditional_jumps (void)
                  EXIT_BLOCK_PTR, next_bb)
     {
       /* Check for more than one predecessor.  */
-      if (EDGE_COUNT (bb->preds) > 1)
+      if (!single_pred_p (bb))
        {
          setcc = NULL_RTX;
-         for (insn = BB_HEAD (bb);
-              insn != NULL && insn != NEXT_INSN (BB_END (bb));
-              insn = NEXT_INSN (insn))
+         FOR_BB_INSNS (bb, insn)
            if (NONJUMP_INSN_P (insn))
              {
                if (setcc)
@@ -4065,8 +4000,8 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre)
 
   if (JUMP_P (insn)
       || (NONJUMP_INSN_P (insn)
-         && (EDGE_COUNT (bb->succs) > 1
-             || EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL)))
+         && (!single_succ_p (bb)
+             || single_succ_edge (bb)->flags & EDGE_ABNORMAL)))
     {
 #ifdef HAVE_cc0
       rtx note;
@@ -4107,7 +4042,8 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre)
   /* Likewise if the last insn is a call, as will happen in the presence
      of exception handling.  */
   else if (CALL_P (insn)
-          && (EDGE_COUNT (bb->succs) > 1 || EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL))
+          && (!single_succ_p (bb)
+              || single_succ_edge (bb)->flags & EDGE_ABNORMAL))
     {
       /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
         we search backward and place the instructions before the first
@@ -4205,7 +4141,7 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map)
                    if (! occr->deleted_p)
                      continue;
 
-                   /* Insert this expression on this edge if if it would
+                   /* Insert this expression on this edge if it would
                       reach the deleted occurrence in BB.  */
                    if (!TEST_BIT (inserted[e], j))
                      {
@@ -4219,7 +4155,7 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map)
                           handling this situation.  This one is easiest for
                           now.  */
 
-                       if ((eg->flags & EDGE_ABNORMAL) == EDGE_ABNORMAL)
+                       if (eg->flags & EDGE_ABNORMAL)
                          insert_insn_end_bb (index_map[j], bb, 0);
                        else
                          {
@@ -4313,7 +4249,6 @@ pre_insert_copy_insn (struct expr *expr, rtx insn)
           new_insn = emit_insn_after (new_insn, insn);
 
           /* Keep register set table up to date.  */
-          replace_one_set (REGNO (old_reg), insn, new_insn);
           record_one_set (regno, insn);
         }
       else
@@ -5310,9 +5245,7 @@ compute_ld_motion_mems (void)
 
   FOR_EACH_BB (bb)
     {
-      for (insn = BB_HEAD (bb);
-          insn && insn != NEXT_INSN (BB_END (bb));
-          insn = NEXT_INSN (insn))
+      FOR_BB_INSNS (bb, insn)
        {
          if (INSN_P (insn))
            {
@@ -5767,9 +5700,7 @@ compute_store_table (void)
       /* First compute the registers set in this block.  */
       regvec = last_set_in;
 
-      for (insn = BB_HEAD (bb);
-          insn != NEXT_INSN (BB_END (bb));
-          insn = NEXT_INSN (insn))
+      FOR_BB_INSNS (bb, insn)
        {
          if (! INSN_P (insn))
            continue;
@@ -5792,9 +5723,7 @@ compute_store_table (void)
       /* Now find the stores.  */
       memset (already_set, 0, sizeof (int) * max_gcse_regno);
       regvec = already_set;
-      for (insn = BB_HEAD (bb);
-          insn != NEXT_INSN (BB_END (bb));
-          insn = NEXT_INSN (insn))
+      FOR_BB_INSNS (bb, insn)
        {
          if (! INSN_P (insn))
            continue;
@@ -5922,7 +5851,7 @@ find_loads (rtx x, rtx store_pattern, int after)
 
 /* Check if INSN kills the store pattern X (is aliased with it).
    AFTER is true if we are checking the case when store X occurs
-   after the insn.  Return true if it it does.  */
+   after the insn.  Return true if it does.  */
 
 static bool
 store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
@@ -5959,8 +5888,7 @@ store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
       rtx pat = PATTERN (insn);
       rtx dest = SET_DEST (pat);
 
-      if (GET_CODE (dest) == SIGN_EXTRACT
-         || GET_CODE (dest) == ZERO_EXTRACT)
+      if (GET_CODE (dest) == ZERO_EXTRACT)
        dest = XEXP (dest, 0);
 
       /* Check for memory stores to aliased objects.  */
@@ -6220,13 +6148,9 @@ insert_store (struct ls_expr * expr, edge e)
       return 0;
     }
 
-  /* We can't insert on this edge, so we'll insert at the head of the
-     successors block.  See Morgan, sec 10.5.  */
-  if ((e->flags & EDGE_ABNORMAL) == EDGE_ABNORMAL)
-    {
-      insert_insn_start_bb (insn, bb);
-      return 0;
-    }
+  /* We can't put stores in the front of blocks pointed to by abnormal
+     edges since that may put a store where one didn't used to be.  */
+  gcc_assert (!(e->flags & EDGE_ABNORMAL));
 
   insert_insn_on_edge (insn, e);
 
@@ -6490,6 +6414,25 @@ store_motion (void)
   /* Now we want to insert the new stores which are going to be needed.  */
   for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
     {
+      /* If any of the edges we have above are abnormal, we can't move this
+        store.  */
+      for (x = NUM_EDGES (edge_list) - 1; x >= 0; x--)
+       if (TEST_BIT (pre_insert_map[x], ptr->index)
+           && (INDEX_EDGE (edge_list, x)->flags & EDGE_ABNORMAL))
+         break;
+
+      if (x >= 0)
+       {
+         if (gcse_file != NULL)
+           fprintf (gcse_file,
+                    "Can't replace store %d: abnormal edge from %d to %d\n",
+                    ptr->index, INDEX_EDGE (edge_list, x)->src->index,
+                    INDEX_EDGE (edge_list, x)->dest->index);
+         continue;
+       }
+                     
+      /* Now we want to insert the new stores which are going to be needed.  */
+
       FOR_EACH_BB (bb)
        if (TEST_BIT (pre_delete_map[bb->index], ptr->index))
          delete_store (ptr, bb);
@@ -6552,11 +6495,11 @@ bypass_jumps (FILE *file)
      information about memory sets when we build the hash tables.  */
 
   alloc_reg_set_mem (max_gcse_regno);
-  compute_sets (get_insns ());
+  compute_sets ();
 
   max_gcse_regno = max_reg_num ();
-  alloc_gcse_mem (get_insns ());
-  changed = one_cprop_pass (MAX_GCSE_PASSES + 2, 1, 1);
+  alloc_gcse_mem ();
+  changed = one_cprop_pass (MAX_GCSE_PASSES + 2, true, true);
   free_gcse_mem ();
 
   if (file)
@@ -6593,9 +6536,9 @@ is_too_expensive (const char *pass)
      graceful degradation.  */
   if (n_edges > 20000 + n_basic_blocks * 4)
     {
-      if (warn_disabled_optimization)
-       warning ("%s: %d basic blocks and %d edges/basic block",
-                pass, n_basic_blocks, n_edges / n_basic_blocks);
+      warning (OPT_Wdisabled_optimization,
+              "%s: %d basic blocks and %d edges/basic block",
+              pass, n_basic_blocks, n_edges / n_basic_blocks);
 
       return true;
     }
@@ -6606,9 +6549,9 @@ is_too_expensive (const char *pass)
        * SBITMAP_SET_SIZE (max_reg_num ())
        * sizeof (SBITMAP_ELT_TYPE)) > MAX_GCSE_MEMORY)
     {
-      if (warn_disabled_optimization)
-       warning ("%s: %d basic blocks and %d registers",
-                pass, n_basic_blocks, max_reg_num ());
+      warning (OPT_Wdisabled_optimization,
+              "%s: %d basic blocks and %d registers",
+              pass, n_basic_blocks, max_reg_num ());
 
       return true;
     }