OSDN Git Service

2009-04-17 Rafael Avila de Espindola <espindola@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / gcse.c
index b18d17a..00f0986 100644 (file)
@@ -1,13 +1,13 @@
 /* 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 Free Software Foundation, Inc.
+   2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* TODO
    - reordering of memory allocation and freeing to be more space efficient
@@ -171,6 +170,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "timevar.h"
 #include "tree-pass.h"
 #include "hashtab.h"
+#include "df.h"
+#include "dbgcnt.h"
 
 /* Propagate flow information through back edges and thus enable PRE's
    moving loop invariant calculations out of loops.
@@ -189,16 +190,18 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 
    We perform the following steps:
 
-   1) Compute basic block information.
+   1) Compute table of places where registers are set.
 
-   2) Compute table of places where registers are set.
+   2) Perform copy/constant propagation.
 
-   3) Perform copy/constant propagation.
-
-   4) Perform global cse using lazy code motion if not optimizing
+   3) Perform global cse using lazy code motion if not optimizing
       for size, or code hoisting if we are.
 
-   5) Perform another pass of copy/constant propagation.
+   4) Perform another pass of copy/constant propagation.  Try to bypass
+      conditional jumps if the condition can be computed from a value of
+      an incoming edge.
+
+   5) Perform store motion.
 
    Two passes of copy/constant propagation are done because the first one
    enables more GCSE and the second one helps to clean up the copies that
@@ -211,6 +214,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
    (set (pseudo-reg) (expression)).
    Function want_to_gcse_p says what these are.
 
+   In addition, expressions in REG_EQUAL notes are candidates for GXSE-ing.
+   This allows PRE to hoist expressions that are expressed in multiple insns,
+   such as comprex address calculations (e.g. for PIC code, or loads with a 
+   high part and as lowe part).
+
    PRE handles moving invariant expressions out of loops (by treating them as
    partially redundant).
 
@@ -234,9 +242,13 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
    It was found doing copy propagation between each pass enables further
    substitutions.
 
+   This study was done before expressions in REG_EQUAL notes were added as
+   candidate expressions for optimization, and before the GIMPLE optimizers
+   were added.  Probably, multiple passes is even less efficient now than
+   at the time when the study was conducted.
+
    PRE is quite expensive in complicated functions because the DFA can take
-   a while to converge.  Hence we only perform one pass.  The parameter
-   max-gcse-passes can be modified if one wants to experiment.
+   a while to converge.  Hence we only perform one pass.
 
    **********************
 
@@ -379,12 +391,6 @@ static int max_uid;
 /* Number of cuids.  */
 static int max_cuid;
 
-/* Mapping of cuids to insns.  */
-static rtx *cuid_insn;
-
-/* Get insn from cuid.  */
-#define CUID_INSN(CUID) (cuid_insn[CUID])
-
 /* Maximum register number in function prior to doing gcse + 1.
    Registers created during this pass have regno >= max_gcse_regno.
    This is named with "gcse" to not collide with global of same name.  */
@@ -522,27 +528,27 @@ 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 record_set_info (rtx, rtx, void *);
+static void record_set_info (rtx, const_rtx, void *);
 static void compute_sets (void);
-static void hash_scan_insn (rtx, struct hash_table *, int);
+static void hash_scan_insn (rtx, struct hash_table *);
 static void hash_scan_set (rtx, rtx, struct hash_table *);
 static void hash_scan_clobber (rtx, rtx, struct hash_table *);
 static void hash_scan_call (rtx, rtx, struct hash_table *);
 static int want_to_gcse_p (rtx);
 static bool can_assign_to_reg_p (rtx);
-static bool gcse_constant_p (rtx);
-static int oprs_unchanged_p (rtx, rtx, int);
-static int oprs_anticipatable_p (rtx, rtx);
-static int oprs_available_p (rtx, rtx);
+static bool gcse_constant_p (const_rtx);
+static int oprs_unchanged_p (const_rtx, const_rtx, int);
+static int oprs_anticipatable_p (const_rtx, const_rtx);
+static int oprs_available_p (const_rtx, const_rtx);
 static void insert_expr_in_table (rtx, enum machine_mode, rtx, int, int,
                                  struct hash_table *);
 static void insert_set_in_table (rtx, rtx, struct hash_table *);
-static unsigned int hash_expr (rtx, enum machine_mode, int *, int);
+static unsigned int hash_expr (const_rtx, enum machine_mode, int *, int);
 static unsigned int hash_set (int, int);
-static int expr_equiv_p (rtx, rtx);
+static int expr_equiv_p (const_rtx, const_rtx);
 static void record_last_reg_set_info (rtx, int);
 static void record_last_mem_set_info (rtx);
-static void record_last_set_info (rtx, rtx, void *);
+static void record_last_set_info (rtx, const_rtx, void *);
 static void compute_hash_table (struct hash_table *);
 static void alloc_hash_table (int, struct hash_table *, int);
 static void free_hash_table (struct hash_table *);
@@ -551,14 +557,14 @@ static void dump_hash_table (FILE *, const char *, struct hash_table *);
 static struct expr *lookup_set (unsigned int, struct hash_table *);
 static struct expr *next_set (unsigned int, struct expr *);
 static void reset_opr_set_tables (void);
-static int oprs_not_set_p (rtx, rtx);
+static int oprs_not_set_p (const_rtx, const_rtx);
 static void mark_call (rtx);
 static void mark_set (rtx, rtx);
 static void mark_clobber (rtx, rtx);
 static void mark_oprs_set (rtx);
 static void alloc_cprop_mem (int, int);
 static void free_cprop_mem (void);
-static void compute_transp (rtx, int, sbitmap *, int);
+static void compute_transp (const_rtx, int, sbitmap *, int);
 static void compute_transpout (void);
 static void compute_local_properties (sbitmap *, sbitmap *, sbitmap *,
                                      struct hash_table *);
@@ -567,16 +573,16 @@ static void find_used_regs (rtx *, void *);
 static int try_replace_reg (rtx, rtx, rtx);
 static struct expr *find_avail_set (int, rtx);
 static int cprop_jump (basic_block, rtx, rtx, rtx, rtx);
-static void mems_conflict_for_gcse_p (rtx, rtx, void *);
-static int load_killed_in_block_p (basic_block, int, rtx, int);
-static void canon_list_insert (rtx, rtx, void *);
+static void mems_conflict_for_gcse_p (rtx, const_rtx, void *);
+static int load_killed_in_block_p (const_basic_block, int, const_rtx, int);
+static void canon_list_insert (rtx, const_rtx, void *);
 static int cprop_insn (rtx, int);
 static int cprop (int);
 static void find_implicit_sets (void);
 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 bool reg_killed_on_edge (const_rtx, const_edge);
 static int bypass_block (basic_block, rtx, rtx);
 static int bypass_conditional_jumps (void);
 static void alloc_pre_mem (int, int);
@@ -584,7 +590,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_bb (struct expr *, basic_block, int);
+static void insert_insn_end_basic_block (struct expr *, basic_block, int);
 static void pre_insert_copy_insn (struct expr *, rtx);
 static void pre_insert_copies (void);
 static int pre_delete (void);
@@ -610,25 +616,25 @@ static struct ls_expr * find_rtx_in_ldst (rtx);
 static int enumerate_ldsts (void);
 static inline struct ls_expr * first_ls_expr (void);
 static inline struct ls_expr * next_ls_expr (struct ls_expr *);
-static int simple_mem (rtx);
+static int simple_mem (const_rtx);
 static void invalidate_any_buried_refs (rtx);
 static void compute_ld_motion_mems (void);
 static void trim_ld_motion_mems (void);
 static void update_ld_motion_stores (struct expr *);
-static void reg_set_info (rtx, rtx, void *);
-static void reg_clear_last_set (rtx, rtx, void *);
-static bool store_ops_ok (rtx, int *);
+static void reg_set_info (rtx, const_rtx, void *);
+static void reg_clear_last_set (rtx, const_rtx, void *);
+static bool store_ops_ok (const_rtx, int *);
 static rtx extract_mentioned_regs (rtx);
 static rtx extract_mentioned_regs_helper (rtx, rtx);
 static void find_moveable_store (rtx, int *, int *);
 static int compute_store_table (void);
-static bool load_kills_store (rtx, rtx, int);
-static bool find_loads (rtx, rtx, int);
-static bool store_killed_in_insn (rtx, rtx, rtx, int);
-static bool store_killed_after (rtx, rtx, rtx, basic_block, int *, rtx *);
-static bool store_killed_before (rtx, rtx, rtx, basic_block, int *);
+static bool load_kills_store (const_rtx, const_rtx, int);
+static bool find_loads (const_rtx, const_rtx, int);
+static bool store_killed_in_insn (const_rtx, const_rtx, const_rtx, int);
+static bool store_killed_after (const_rtx, const_rtx, const_rtx, const_basic_block, int *, rtx *);
+static bool store_killed_before (const_rtx, const_rtx, const_rtx, const_basic_block, int *);
 static void build_store_vectors (void);
-static void insert_insn_start_bb (rtx, basic_block);
+static void insert_insn_start_basic_block (rtx, basic_block);
 static int insert_store (struct ls_expr *, edge);
 static void remove_reachable_equiv_notes (basic_block, struct ls_expr *);
 static void replace_store_insn (rtx, rtx, basic_block, struct ls_expr *);
@@ -640,10 +646,23 @@ 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, bool, rtx*);
-static bool adjust_libcall_notes (rtx, rtx, rtx, rtx*);
+static bool do_local_cprop (rtx, rtx, bool);
 static void local_cprop_pass (bool);
 static bool is_too_expensive (const char *);
+
+#define GNEW(T)                        ((T *) gmalloc (sizeof (T)))
+#define GCNEW(T)               ((T *) gcalloc (1, sizeof (T)))
+
+#define GNEWVEC(T, N)          ((T *) gmalloc (sizeof (T) * (N)))
+#define GCNEWVEC(T, N)         ((T *) gcalloc ((N), sizeof (T)))
+#define GRESIZEVEC(T, P, N)    ((T *) grealloc ((void *) (P), sizeof (T) * (N)))
+
+#define GNEWVAR(T, S)          ((T *) gmalloc ((S)))
+#define GCNEWVAR(T, S)         ((T *) gcalloc (1, (S)))
+#define GRESIZEVAR(T, P, S)    ((T *) grealloc ((P), (S)))
+
+#define GOBNEW(T)              ((T *) gcse_alloc (sizeof (T)))
+#define GOBNEWVAR(T, S)                ((T *) gcse_alloc ((S)))
 \f
 
 /* Entry point for global common subexpression elimination.
@@ -653,17 +672,13 @@ static bool is_too_expensive (const char *);
 static int
 gcse_main (rtx f ATTRIBUTE_UNUSED)
 {
-  int changed, pass;
-  /* Bytes used at start of pass.  */
-  int initial_bytes_used;
-  /* Maximum number of bytes used by a pass.  */
-  int max_pass_bytes;
+  int changed;
   /* Point to release obstack data from for each pass.  */
   char *gcse_obstack_bottom;
 
   /* We do not construct an accurate cfg in functions which call
      setjmp, so just punt to be safe.  */
-  if (current_function_calls_setjmp)
+  if (cfun->calls_setjmp)
     return 0;
 
   /* Assume that we do not need to run jump optimizations after gcse.  */
@@ -673,6 +688,9 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
      successors and predecessors.  */
   max_gcse_regno = max_reg_num ();
 
+  df_note_add_problem ();
+  df_analyze ();
+
   if (dump_file)
     dump_flow_info (dump_file, dump_flags);
 
@@ -686,6 +704,7 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
 
   /* We need alias.  */
   init_alias_analysis ();
+
   /* Record where pseudo-registers are set.  This data is kept accurate
      during each pass.  ??? We could also record hard-reg information here
      [since it's unchanging], however it is currently done during hash table
@@ -693,122 +712,114 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
 
      It may be tempting to compute MEM set information here too, but MEM sets
      will be subject to code motion one day and thus we need to compute
-     information about memory sets when we build the hash tables.  */
+     information about memory sets when we build the hash tables.
+     
+     ??? Actually, we already know the information that compute_sets computes
+     because it is available from DF.  FIXME.  */
 
   alloc_reg_set_mem (max_gcse_regno);
   compute_sets ();
 
-  pass = 0;
-  initial_bytes_used = bytes_used;
-  max_pass_bytes = 0;
-  gcse_obstack_bottom = gcse_alloc (1);
-  changed = 1;
-  while (changed && pass < MAX_GCSE_PASSES)
-    {
-      changed = 0;
-      if (dump_file)
-       fprintf (dump_file, "GCSE pass %d\n\n", pass + 1);
-
-      /* Initialize bytes_used to the space for the pred/succ lists,
-        and the reg_set_table data.  */
-      bytes_used = initial_bytes_used;
+  gcse_obstack_bottom = GOBNEWVAR (char, 1);
+  changed = 0;
+  if (dump_file)
+    fprintf (dump_file, "GCSE pass\n\n");
 
-      /* Each pass may create new registers, so recalculate each time.  */
-      max_gcse_regno = max_reg_num ();
+  max_gcse_regno = max_reg_num ();
 
-      alloc_gcse_mem ();
+  alloc_gcse_mem ();
 
-      /* Don't allow constant propagation to modify jumps
-        during this pass.  */
+  /* Don't allow constant propagation to modify jumps
+     during this pass.  */
+  if (dbg_cnt (cprop1))
+    {
       timevar_push (TV_CPROP1);
-      changed = one_cprop_pass (pass + 1, false, false);
+      changed = one_cprop_pass (1, false, false);
       timevar_pop (TV_CPROP1);
+    }
 
-      if (optimize_size)
-       /* Do nothing.  */ ;
-      else
+  if (optimize_function_for_speed_p (cfun))
+    {
+      timevar_push (TV_PRE);
+      changed |= one_pre_gcse_pass (1);
+      /* We may have just created new basic blocks.  Release and
+        recompute various things which are sized on the number of
+        basic blocks.
+        ??? There would be no need for this if we used a block
+        based Lazy Code Motion variant, with all (or selected)
+        edges split before running the pass.  That would also
+        help find_implicit_sets for cprop.  FIXME.  */
+      if (changed)
        {
-         timevar_push (TV_PRE);
-         changed |= one_pre_gcse_pass (pass + 1);
-         /* We may have just created new basic blocks.  Release and
-            recompute various things which are sized on the number of
-            basic blocks.  */
-         if (changed)
-           {
-             free_modify_mem_tables ();
-             modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
-             canon_modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
-           }
-         free_reg_set_mem ();
-         alloc_reg_set_mem (max_reg_num ());
-         compute_sets ();
-         run_jump_opt_after_gcse = 1;
-         timevar_pop (TV_PRE);
+         free_modify_mem_tables ();
+         modify_mem_list = GCNEWVEC (rtx, last_basic_block);
+         canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block);
        }
 
-      if (max_pass_bytes < bytes_used)
-       max_pass_bytes = bytes_used;
-
-      /* Free up memory, then reallocate for code hoisting.  We can
-        not re-use the existing allocated memory because the tables
-        will not have info for the insns or registers created by
-        partial redundancy elimination.  */
-      free_gcse_mem ();
-
-      /* It does not make sense to run code hoisting unless we are optimizing
+      /* ??? When we allocate this at the start of the function,
+        the comment says that "this data is kept accurate during
+        each pass".  Apparently this is not so?  FIXME.  */
+      free_reg_set_mem ();
+      alloc_reg_set_mem (max_reg_num ());
+      compute_sets ();
+      run_jump_opt_after_gcse = 1;
+      timevar_pop (TV_PRE);
+    }
+  else
+    {
+      /* This function is being optimized for code size.
+        It does not make sense to run code hoisting unless we are optimizing
         for code size -- it rarely makes programs faster, and can make
         them bigger if we did partial redundancy elimination (when optimizing
         for space, we don't run the partial redundancy algorithms).  */
-      if (optimize_size)
-       {
-         timevar_push (TV_HOIST);
-         max_gcse_regno = max_reg_num ();
-         alloc_gcse_mem ();
-         changed |= one_code_hoisting_pass ();
-         free_gcse_mem ();
-
-         if (max_pass_bytes < bytes_used)
-           max_pass_bytes = bytes_used;
-         timevar_pop (TV_HOIST);
-       }
+      timevar_push (TV_HOIST);
+      max_gcse_regno = max_reg_num ();
+      alloc_gcse_mem ();
+      one_code_hoisting_pass ();
+      timevar_pop (TV_HOIST);
+    }
 
-      if (dump_file)
-       {
-         fprintf (dump_file, "\n");
-         fflush (dump_file);
-       }
+  free_gcse_mem ();
 
-      obstack_free (&gcse_obstack, gcse_obstack_bottom);
-      pass++;
+  if (dump_file)
+    {
+      fprintf (dump_file, "\n");
+      fflush (dump_file);
     }
 
-  /* Do one last pass of copy propagation, including cprop into
+  obstack_free (&gcse_obstack, gcse_obstack_bottom);
+
+  /* Do the second const/copy propagation pass, including cprop into
      conditional jumps.  */
+  if (dbg_cnt (cprop2))
+    {
+      max_gcse_regno = max_reg_num ();
+      alloc_gcse_mem ();
 
-  max_gcse_regno = max_reg_num ();
-  alloc_gcse_mem ();
-  /* This time, go ahead and allow cprop to alter jumps.  */
-  timevar_push (TV_CPROP2);
-  one_cprop_pass (pass + 1, true, true);
-  timevar_pop (TV_CPROP2);
-  free_gcse_mem ();
+      /* This time, go ahead and allow cprop to alter jumps.  */
+      timevar_push (TV_CPROP2);
+      one_cprop_pass (2, true, true);
+      timevar_pop (TV_CPROP2);
+      free_gcse_mem ();
+    }
 
   if (dump_file)
     {
       fprintf (dump_file, "GCSE of %s: %d basic blocks, ",
               current_function_name (), n_basic_blocks);
-      fprintf (dump_file, "%d pass%s, %d bytes\n\n",
-              pass, pass > 1 ? "es" : "", max_pass_bytes);
+      fprintf (dump_file, "pass 1, %d bytes\n\n", bytes_used);
     }
 
   obstack_free (&gcse_obstack, NULL);
   free_reg_set_mem ();
 
-  /* We are finished with alias.  */
+  /* We are finished with alias.
+     ??? Actually we recompute alias in store_motion.  */
   end_alias_analysis ();
-  allocate_reg_info (max_reg_num (), FALSE, FALSE);
 
-  if (!optimize_size && flag_gcse_sm)
+  /* Run store motion.  */
+  if (optimize_function_for_speed_p (cfun) && flag_gcse_sm)
     {
       timevar_push (TV_LSM);
       store_motion ();
@@ -928,7 +939,7 @@ alloc_gcse_mem (void)
      but we should never see those anyway, so this is OK.)  */
 
   max_uid = get_max_uid ();
-  uid_cuid = gcalloc (max_uid + 1, sizeof (int));
+  uid_cuid = GCNEWVEC (int, max_uid + 1);
   i = 0;
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
@@ -939,15 +950,7 @@ alloc_gcse_mem (void)
          uid_cuid[INSN_UID (insn)] = i;
       }
 
-  /* Create a table mapping cuids to insns.  */
-
   max_cuid = i;
-  cuid_insn = gcalloc (max_cuid + 1, sizeof (rtx));
-  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_ALLOC (NULL);
@@ -956,8 +959,8 @@ alloc_gcse_mem (void)
   reg_set_in_block = sbitmap_vector_alloc (last_basic_block, max_gcse_regno);
   /* Allocate array to keep a list of insns which modify memory in each
      basic block.  */
-  modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
-  canon_modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
+  modify_mem_list = GCNEWVEC (rtx, last_basic_block);
+  canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block);
   modify_mem_list_set = BITMAP_ALLOC (NULL);
   blocks_with_calls = BITMAP_ALLOC (NULL);
 }
@@ -968,7 +971,6 @@ static void
 free_gcse_mem (void)
 {
   free (uid_cuid);
-  free (cuid_insn);
 
   BITMAP_FREE (reg_set_bitmap);
 
@@ -1082,7 +1084,7 @@ static void
 alloc_reg_set_mem (int n_regs)
 {
   reg_set_table_size = n_regs + REG_SET_TABLE_SLOP;
-  reg_set_table = gcalloc (reg_set_table_size, sizeof (struct reg_set *));
+  reg_set_table = GCNEWVEC (struct reg_set *, reg_set_table_size);
 
   gcc_obstack_init (&reg_set_obstack);
 }
@@ -1107,14 +1109,13 @@ record_one_set (int regno, rtx insn)
     {
       int new_size = regno + REG_SET_TABLE_SLOP;
 
-      reg_set_table = grealloc (reg_set_table,
-                               new_size * sizeof (struct reg_set *));
+      reg_set_table = GRESIZEVEC (struct reg_set *, reg_set_table, new_size);
       memset (reg_set_table + reg_set_table_size, 0,
              (new_size - reg_set_table_size) * sizeof (struct reg_set *));
       reg_set_table_size = new_size;
     }
 
-  new_reg_info = obstack_alloc (&reg_set_obstack, sizeof (struct reg_set));
+  new_reg_info = XOBNEW (&reg_set_obstack, struct reg_set);
   bytes_used += sizeof (struct reg_set);
   new_reg_info->bb_index = BLOCK_NUM (insn);
   new_reg_info->next = reg_set_table[regno];
@@ -1126,7 +1127,7 @@ record_one_set (int regno, rtx insn)
    occurring.  */
 
 static void
-record_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data)
+record_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data)
 {
   rtx record_set_insn = (rtx) data;
 
@@ -1184,6 +1185,7 @@ want_to_gcse_p (rtx x)
     case SUBREG:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case CALL:
       return 0;
@@ -1236,7 +1238,7 @@ can_assign_to_reg_p (rtx x)
    or from INSN to the end of INSN's basic block (if AVAIL_P != 0).  */
 
 static int
-oprs_unchanged_p (rtx x, rtx insn, int avail_p)
+oprs_unchanged_p (const_rtx x, const_rtx insn, int avail_p)
 {
   int i, j;
   enum rtx_code code;
@@ -1280,6 +1282,7 @@ oprs_unchanged_p (rtx x, rtx insn, int avail_p)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -1322,14 +1325,14 @@ static int gcse_mems_conflict_p;
    load_killed_in_block_p.  A memory reference for a load instruction,
    mems_conflict_for_gcse_p will see if a memory store conflicts with
    this memory load.  */
-static rtx gcse_mem_operand;
+static const_rtx gcse_mem_operand;
 
 /* DEST is the output of an instruction.  If it is a memory reference, and
    possibly conflicts with the load found in gcse_mem_operand, then set
    gcse_mems_conflict_p to a nonzero value.  */
 
 static void
-mems_conflict_for_gcse_p (rtx dest, rtx setter ATTRIBUTE_UNUSED,
+mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
                          void *data ATTRIBUTE_UNUSED)
 {
   while (GET_CODE (dest) == SUBREG
@@ -1367,7 +1370,7 @@ mems_conflict_for_gcse_p (rtx dest, rtx setter ATTRIBUTE_UNUSED,
    AVAIL_P to 0.  */
 
 static int
-load_killed_in_block_p (basic_block bb, int uid_limit, rtx x, int avail_p)
+load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int avail_p)
 {
   rtx list_entry = modify_mem_list[bb->index];
 
@@ -1415,7 +1418,7 @@ load_killed_in_block_p (basic_block bb, int uid_limit, rtx x, int avail_p)
    the start of INSN's basic block up to but not including INSN.  */
 
 static int
-oprs_anticipatable_p (rtx x, rtx insn)
+oprs_anticipatable_p (const_rtx x, const_rtx insn)
 {
   return oprs_unchanged_p (x, insn, 0);
 }
@@ -1424,7 +1427,7 @@ oprs_anticipatable_p (rtx x, rtx insn)
    INSN to the end of INSN's basic block.  */
 
 static int
-oprs_available_p (rtx x, rtx insn)
+oprs_available_p (const_rtx x, const_rtx insn)
 {
   return oprs_unchanged_p (x, insn, 1);
 }
@@ -1437,7 +1440,7 @@ oprs_available_p (rtx x, rtx insn)
    the current size of the hash table to be probed.  */
 
 static unsigned int
-hash_expr (rtx x, enum machine_mode mode, int *do_not_record_p,
+hash_expr (const_rtx x, enum machine_mode mode, int *do_not_record_p,
           int hash_table_size)
 {
   unsigned int hash;
@@ -1468,7 +1471,7 @@ hash_set (int regno, int hash_table_size)
 /* Return nonzero if exp1 is equivalent to exp2.  */
 
 static int
-expr_equiv_p (rtx x, rtx y)
+expr_equiv_p (const_rtx x, const_rtx y)
 {
   return exp_equiv_p (x, y, 0, true);
 }
@@ -1513,7 +1516,7 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
 
   if (! found)
     {
-      cur_expr = gcse_alloc (sizeof (struct expr));
+      cur_expr = GOBNEW (struct expr);
       bytes_used += sizeof (struct expr);
       if (table->table[hash] == NULL)
        /* This is the first pattern that hashed to this index.  */
@@ -1546,7 +1549,7 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
       else
        {
          /* First occurrence of this expression in this basic block.  */
-         antic_occr = gcse_alloc (sizeof (struct occr));
+         antic_occr = GOBNEW (struct occr);
          bytes_used += sizeof (struct occr);
          antic_occr->insn = insn;
          antic_occr->next = cur_expr->antic_occr;
@@ -1570,7 +1573,7 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
       else
        {
          /* First occurrence of this expression in this basic block.  */
-         avail_occr = gcse_alloc (sizeof (struct occr));
+         avail_occr = GOBNEW (struct occr);
          bytes_used += sizeof (struct occr);
          avail_occr->insn = insn;
          avail_occr->next = cur_expr->avail_occr;
@@ -1610,7 +1613,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table)
 
   if (! found)
     {
-      cur_expr = gcse_alloc (sizeof (struct expr));
+      cur_expr = GOBNEW (struct expr);
       bytes_used += sizeof (struct expr);
       if (table->table[hash] == NULL)
        /* This is the first pattern that hashed to this index.  */
@@ -1643,7 +1646,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table)
   else
     {
       /* First occurrence of this expression in this basic block.  */
-      cur_occr = gcse_alloc (sizeof (struct occr));
+      cur_occr = GOBNEW (struct occr);
       bytes_used += sizeof (struct occr);
 
          cur_occr->insn = insn;
@@ -1657,7 +1660,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table)
    the purposes of GCSE's constant propagation.  */
 
 static bool
-gcse_constant_p (rtx x)
+gcse_constant_p (const_rtx x)
 {
   /* Consider a COMPARE of two integers constant.  */
   if (GET_CODE (x) == COMPARE
@@ -1695,12 +1698,25 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *table)
       unsigned int regno = REGNO (dest);
       rtx tmp;
 
-      /* See if a REG_NOTE shows this equivalent to a simpler expression.
+      /* See if a REG_EQUAL note shows this equivalent to a simpler expression.
+
         This allows us to do a single GCSE pass and still eliminate
         redundant constants, addresses or other expressions that are
-        constructed with multiple instructions.  */
+        constructed with multiple instructions.
+
+        However, keep the original SRC if INSN is a simple reg-reg move.  In
+        In this case, there will almost always be a REG_EQUAL note on the
+        insn that sets SRC.  By recording the REG_EQUAL value here as SRC
+        for INSN, we miss copy propagation opportunities and we perform the
+        same PRE GCSE operation repeatedly on the same REG_EQUAL value if we
+        do more than one PRE GCSE pass.
+
+        Note that this does not impede profitable constant propagations.  We
+        "look through" reg-reg sets in lookup_avail_set.  */
       note = find_reg_equal_equiv_note (insn);
       if (note != 0
+         && REG_NOTE_KIND (note) == REG_EQUAL
+         && !REG_P (src)
          && (table->set_p
              ? gcse_constant_p (XEXP (note, 0))
              : want_to_gcse_p (XEXP (note, 0))))
@@ -1728,8 +1744,11 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *table)
        {
          /* An expression is not anticipatable if its operands are
             modified before this insn or if this is not the only SET in
-            this insn.  */
-         int antic_p = oprs_anticipatable_p (src, insn) && single_set (insn);
+            this insn.  The latter condition does not have to mean that
+            SRC itself is not anticipatable, but we just will not be
+            able to handle code motion of insns with multiple sets.  */
+         int antic_p = oprs_anticipatable_p (src, insn)
+                       && !multiple_sets (insn);
          /* An expression is not available if its operands are
             subsequently modified, including this insn.  It's also not
             available if this is a branch, because we can't insert
@@ -1752,8 +1771,9 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *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
-                      && oprs_available_p (pat, tmp))))
+                  || (tmp = next_nonnote_insn (insn)) == NULL_RTX
+                  || BLOCK_FOR_INSN (tmp) != BLOCK_FOR_INSN (insn)
+                  || oprs_available_p (pat, tmp)))
        insert_set_in_table (pat, insn, table);
     }
   /* In case of store we want to consider the memory value as available in
@@ -1824,19 +1844,14 @@ hash_scan_call (rtx x ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED,
    are also in the PARALLEL.  Later.
 
    If SET_P is nonzero, this is for the assignment hash table,
-   otherwise it is for the expression hash table.
-   If IN_LIBCALL_BLOCK nonzero, we are in a libcall block, and should
-   not record any expressions.  */
+   otherwise it is for the expression hash table.  */
 
 static void
-hash_scan_insn (rtx insn, struct hash_table *table, int in_libcall_block)
+hash_scan_insn (rtx insn, struct hash_table *table)
 {
   rtx pat = PATTERN (insn);
   int i;
 
-  if (in_libcall_block)
-    return;
-
   /* Pick out the sets of INSN and for other forms of instructions record
      what's been modified.  */
 
@@ -1870,8 +1885,8 @@ dump_hash_table (FILE *file, const char *name, struct hash_table *table)
   unsigned int *hash_val;
   struct expr *expr;
 
-  flat_table = xcalloc (table->n_elems, sizeof (struct expr *));
-  hash_val = xmalloc (table->n_elems * sizeof (unsigned int));
+  flat_table = XCNEWVEC (struct expr *, table->n_elems);
+  hash_val = XNEWVEC (unsigned int, table->n_elems);
 
   for (i = 0; i < (int) table->size; i++)
     for (expr = table->table[i]; expr != NULL; expr = expr->next_same_hash)
@@ -1934,7 +1949,7 @@ record_last_reg_set_info (rtx insn, int regno)
    taken off pairwise.  */
 
 static void
-canon_list_insert (rtx dest ATTRIBUTE_UNUSED, rtx unused1 ATTRIBUTE_UNUSED,
+canon_list_insert (rtx dest ATTRIBUTE_UNUSED, const_rtx unused1 ATTRIBUTE_UNUSED,
                   void * v_insn)
 {
   rtx dest_addr, insn;
@@ -1995,7 +2010,7 @@ record_last_mem_set_info (rtx insn)
    the SET is taking place.  */
 
 static void
-record_last_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data)
+record_last_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data)
 {
   rtx last_set_insn = (rtx) data;
 
@@ -2040,7 +2055,7 @@ compute_hash_table_work (struct hash_table *table)
   /* re-Cache any INSN_LIST nodes we have allocated.  */
   clear_modify_mem_tables ();
   /* Some working arrays used to track first and last set in each block.  */
-  reg_avail_info = gmalloc (max_gcse_regno * sizeof (struct reg_avail_info));
+  reg_avail_info = GNEWVEC (struct reg_avail_info, max_gcse_regno);
 
   for (i = 0; i < max_gcse_regno; ++i)
     reg_avail_info[i].last_bb = NULL;
@@ -2049,7 +2064,6 @@ compute_hash_table_work (struct hash_table *table)
     {
       rtx insn;
       unsigned int regno;
-      int in_libcall_block;
 
       /* First pass over the instructions records information used to
         determine when registers and memory are first and last set.
@@ -2080,18 +2094,9 @@ compute_hash_table_work (struct hash_table *table)
                       BB_HEAD (current_bb), table);
 
       /* The next pass builds the hash table.  */
-      in_libcall_block = 0;
       FOR_BB_INSNS (current_bb, insn)
        if (INSN_P (insn))
-         {
-           if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-             in_libcall_block = 1;
-           else if (table->set_p && find_reg_note (insn, REG_RETVAL, NULL_RTX))
-             in_libcall_block = 0;
-           hash_scan_insn (insn, table, in_libcall_block);
-           if (!table->set_p && find_reg_note (insn, REG_RETVAL, NULL_RTX))
-             in_libcall_block = 0;
-         }
+         hash_scan_insn (insn, table);
     }
 
   free (reg_avail_info);
@@ -2118,7 +2123,7 @@ alloc_hash_table (int n_insns, struct hash_table *table, int set_p)
      ??? Later take some measurements.  */
   table->size |= 1;
   n = table->size * sizeof (struct expr *);
-  table->table = gmalloc (n);
+  table->table = GNEWVAR (struct expr *, n);
   table->set_p = set_p;
 }
 
@@ -2242,7 +2247,7 @@ reset_opr_set_tables (void)
    INSN's basic block.  */
 
 static int
-oprs_not_set_p (rtx x, rtx insn)
+oprs_not_set_p (const_rtx x, const_rtx insn)
 {
   int i, j;
   enum rtx_code code;
@@ -2259,6 +2264,7 @@ oprs_not_set_p (rtx x, rtx insn)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -2307,7 +2313,7 @@ oprs_not_set_p (rtx x, rtx insn)
 static void
 mark_call (rtx insn)
 {
-  if (! CONST_OR_PURE_CALL_P (insn))
+  if (! RTL_CONST_OR_PURE_CALL_P (insn))
     record_last_mem_set_info (insn);
 }
 
@@ -2420,7 +2426,7 @@ free_cprop_mem (void)
    bit in BMAP.  */
 
 static void
-compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
+compute_transp (const_rtx x, int indx, sbitmap *bmap, int set_p)
 {
   int i, j;
   basic_block bb;
@@ -2527,6 +2533,7 @@ compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -2669,8 +2676,8 @@ try_replace_reg (rtx from, rtx to, rtx insn)
      with our replacement.  */
   if (note != 0 && REG_NOTE_KIND (note) == REG_EQUAL)
     set_unique_reg_note (insn, REG_EQUAL,
-                        simplify_replace_rtx (XEXP (note, 0), from, to));
-
+                        simplify_replace_rtx (XEXP (note, 0), from,
+                        copy_rtx (to)));
   if (!success && set && reg_mentioned_p (from, SET_SRC (set)))
     {
       /* If above failed and this is a single set, try to simplify the source of
@@ -2778,7 +2785,7 @@ find_avail_set (int regno, rtx insn)
 static int
 cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
 {
-  rtx new, set_src, note_src;
+  rtx new_rtx, set_src, note_src;
   rtx set = pc_set (jump);
   rtx note = find_reg_equal_equiv_note (jump);
 
@@ -2810,22 +2817,22 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
   else
     setcc = NULL_RTX;
 
-  new = simplify_replace_rtx (set_src, from, src);
+  new_rtx = simplify_replace_rtx (set_src, from, src);
 
   /* If no simplification can be made, then try the next register.  */
-  if (rtx_equal_p (new, SET_SRC (set)))
+  if (rtx_equal_p (new_rtx, SET_SRC (set)))
     return 0;
 
   /* If this is now a no-op delete it, otherwise this must be a valid insn.  */
-  if (new == pc_rtx)
+  if (new_rtx == pc_rtx)
     delete_insn (jump);
   else
     {
       /* Ensure the value computed inside the jump insn to be equivalent
          to one computed by setcc.  */
-      if (setcc && modified_in_p (new, setcc))
+      if (setcc && modified_in_p (new_rtx, setcc))
        return 0;
-      if (! validate_change (jump, &SET_SRC (set), new, 0))
+      if (! validate_unshare_change (jump, &SET_SRC (set), new_rtx, 0))
        {
          /* When (some) constants are not valid in a comparison, and there
             are two registers to be replaced by constants before the entire
@@ -2836,20 +2843,14 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
             we need to attach a note to the branch itself to make this
             optimization work.  */
 
-         if (!rtx_equal_p (new, note_src))
-           set_unique_reg_note (jump, REG_EQUAL, copy_rtx (new));
+         if (!rtx_equal_p (new_rtx, note_src))
+           set_unique_reg_note (jump, REG_EQUAL, copy_rtx (new_rtx));
          return 0;
        }
 
       /* Remove REG_EQUAL note after simplification.  */
       if (note_src)
        remove_note (jump, note);
-
-      /* If this has turned into an unconditional jump,
-        then put a barrier after it so that the unreachable
-        code will be deleted.  */
-      if (GET_CODE (SET_SRC (set)) == LABEL_REF)
-       emit_barrier_after (jump);
      }
 
 #ifdef HAVE_cc0
@@ -2871,6 +2872,24 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
     }
   purge_dead_edges (bb);
 
+  /* If a conditional jump has been changed into unconditional jump, remove
+     the jump and make the edge fallthru - this is always called in
+     cfglayout mode.  */
+  if (new_rtx != pc_rtx && simplejump_p (jump))
+    {
+      edge e;
+      edge_iterator ei;
+
+      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ei_next (&ei))
+       if (e->dest != EXIT_BLOCK_PTR
+           && BB_HEAD (e->dest) == JUMP_LABEL (jump))
+         {
+           e->flags |= EDGE_FALLTHRU;
+           break;
+         }
+      delete_insn (jump);
+    }
+
   return 1;
 }
 
@@ -3049,11 +3068,11 @@ local_cprop_find_used_regs (rtx *xptr, void *data)
   find_used_regs (xptr, data);
 }
 
-/* LIBCALL_SP is a zero-terminated array of insns at the end of a libcall;
-   their REG_EQUAL notes need updating.  */
+/* Try to perform local const/copy propagation on X in INSN.
+   If ALTER_JUMPS is false, changing jump insns is not allowed.  */
 
 static bool
-do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
+do_local_cprop (rtx x, rtx insn, bool alter_jumps)
 {
   rtx newreg = NULL, newcnst = NULL;
 
@@ -3074,10 +3093,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
          rtx this_rtx = l->loc;
          rtx note;
 
-         /* Don't CSE non-constant values out of libcall blocks.  */
-         if (l->in_libcall && ! CONSTANT_P (this_rtx))
-           continue;
-
          if (gcse_constant_p (this_rtx))
            newcnst = this_rtx;
          if (REG_P (this_rtx) && REGNO (this_rtx) >= FIRST_PSEUDO_REGISTER
@@ -3092,16 +3107,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
        }
       if (newcnst && constprop_register (insn, x, newcnst, alter_jumps))
        {
-         /* If we find a case where we can't fix the retval REG_EQUAL notes
-            match the new register, we either have to abandon this replacement
-            or fix delete_trivially_dead_insns to preserve the setting insn,
-            or make it delete the REG_EUAQL note, and fix up all passes that
-            require the REG_EQUAL note there.  */
-         bool adjusted;
-
-         adjusted = adjust_libcall_notes (x, newcnst, insn, libcall_sp);
-         gcc_assert (adjusted);
-         
          if (dump_file != NULL)
            {
              fprintf (dump_file, "LOCAL CONST-PROP: Replacing reg %d in ",
@@ -3116,7 +3121,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
        }
       else if (newreg && newreg != x && try_replace_reg (x, newreg, insn))
        {
-         adjust_libcall_notes (x, newreg, insn, libcall_sp);
          if (dump_file != NULL)
            {
              fprintf (dump_file,
@@ -3131,46 +3135,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
   return false;
 }
 
-/* LIBCALL_SP is a zero-terminated array of insns at the end of a libcall;
-   their REG_EQUAL notes need updating to reflect that OLDREG has been
-   replaced with NEWVAL in INSN.  Return true if all substitutions could
-   be made.  */
-static bool
-adjust_libcall_notes (rtx oldreg, rtx newval, rtx insn, rtx *libcall_sp)
-{
-  rtx end;
-
-  while ((end = *libcall_sp++))
-    {
-      rtx note = find_reg_equal_equiv_note (end);
-
-      if (! note)
-       continue;
-
-      if (REG_P (newval))
-       {
-         if (reg_set_between_p (newval, PREV_INSN (insn), end))
-           {
-             do
-               {
-                 note = find_reg_equal_equiv_note (end);
-                 if (! note)
-                   continue;
-                 if (reg_mentioned_p (newval, XEXP (note, 0)))
-                   return false;
-               }
-             while ((end = *libcall_sp++));
-             return true;
-           }
-       }
-      XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), oldreg, newval);
-      insn = end;
-    }
-  return true;
-}
-
-#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.  */
@@ -3181,29 +3145,16 @@ 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;
   bool changed = false;
 
   cselib_init (false);
-  libcall_sp = &libcall_stack[MAX_NESTED_LIBCALLS];
-  *libcall_sp = 0;
   FOR_EACH_BB (bb)
     {
       FOR_BB_INSNS (bb, insn)
        {
          if (INSN_P (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);
+             rtx note = find_reg_equal_equiv_note (insn);
              do
                {
                  reg_use_count = 0;
@@ -3214,12 +3165,13 @@ local_cprop_pass (bool alter_jumps)
 
                  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 (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps))
+                       {
+                         changed = true;
+                         break;
+                       }
+                   }
                  if (INSN_DELETED_P (insn))
                    break;
                }
@@ -3228,10 +3180,8 @@ local_cprop_pass (bool alter_jumps)
          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.  */
+      /* Forget everything at the end of a basic block.  */
       cselib_clear_table ();
-      gcc_assert (libcall_sp == &libcall_stack[MAX_NESTED_LIBCALLS]);
     }
 
   cselib_finish ();
@@ -3310,10 +3260,10 @@ fis_get_condition (rtx jump)
    it.  COND is either an EQ or NE comparison.  */
 
 static bool
-implicit_set_cond_p (rtx cond)
+implicit_set_cond_p (const_rtx cond)
 {
-  enum machine_mode mode = GET_MODE (XEXP (cond, 0));
-  rtx cst = XEXP (cond, 1);
+  const enum machine_mode mode = GET_MODE (XEXP (cond, 0));
+  const_rtx cst = XEXP (cond, 1);
 
   /* We can't perform this optimization if either operand might be or might
      contain a signed zero.  */
@@ -3350,7 +3300,7 @@ find_implicit_sets (void)
 {
   basic_block bb, dest;
   unsigned int count;
-  rtx cond, new;
+  rtx cond, new_rtx;
 
   count = 0;
   FOR_EACH_BB (bb)
@@ -3371,9 +3321,9 @@ find_implicit_sets (void)
            if (dest && single_pred_p (dest)
                && dest != EXIT_BLOCK_PTR)
              {
-               new = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
+               new_rtx = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
                                             XEXP (cond, 1));
-               implicit_sets[dest->index] = new;
+               implicit_sets[dest->index] = new_rtx;
                if (dump_file)
                  {
                    fprintf(dump_file, "Implicit set of reg %d in ",
@@ -3501,7 +3451,7 @@ find_bypass_set (int regno, int bb)
    valid prior to commit_edge_insertions.  */
 
 static bool
-reg_killed_on_edge (rtx reg, edge e)
+reg_killed_on_edge (const_rtx reg, const_edge e)
 {
   rtx insn;
 
@@ -3583,7 +3533,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
          unsigned int regno = REGNO (reg_used->reg_rtx);
          basic_block dest, old_dest;
          struct expr *set;
-         rtx src, new;
+         rtx src, new_rtx;
 
          if (regno >= max_gcse_regno)
            continue;
@@ -3604,7 +3554,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
                                          SET_DEST (PATTERN (setcc)),
                                          SET_SRC (PATTERN (setcc)));
 
-         new = simplify_replace_rtx (src, reg_used->reg_rtx,
+         new_rtx = simplify_replace_rtx (src, reg_used->reg_rtx,
                                      SET_SRC (set->expr));
 
          /* Jump bypassing may have already placed instructions on
@@ -3612,14 +3562,14 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
             has instructions associated with it, as these insns won't
             get executed if the incoming edge is redirected.  */
 
-         if (new == pc_rtx)
+         if (new_rtx == pc_rtx)
            {
              edest = FALLTHRU_EDGE (bb);
              dest = edest->insns.r ? NULL : edest->dest;
            }
-         else if (GET_CODE (new) == LABEL_REF)
+         else if (GET_CODE (new_rtx) == LABEL_REF)
            {
-             dest = BLOCK_FOR_INSN (XEXP (new, 0));
+             dest = BLOCK_FOR_INSN (XEXP (new_rtx, 0));
              /* Don't bypass edges containing instructions.  */
              edest = find_edge (bb, dest);
              if (edest && edest->insns.r)
@@ -3991,7 +3941,7 @@ process_insert_insn (struct expr *expr)
    no sense for code hoisting.  */
 
 static void
-insert_insn_end_bb (struct expr *expr, basic_block bb, int pre)
+insert_insn_end_basic_block (struct expr *expr, basic_block bb, int pre)
 {
   rtx insn = BB_END (bb);
   rtx new_insn;
@@ -4048,7 +3998,7 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre)
        }
 #endif
       /* FIXME: What if something in cc0/jump uses value set in new insn?  */
-      new_insn = emit_insn_before_noloc (pat, insn);
+      new_insn = emit_insn_before_noloc (pat, insn, bb);
     }
 
   /* Likewise if the last insn is a call, as will happen in the presence
@@ -4087,10 +4037,10 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre)
             || NOTE_INSN_BASIC_BLOCK_P (insn))
        insn = NEXT_INSN (insn);
 
-      new_insn = emit_insn_before_noloc (pat, insn);
+      new_insn = emit_insn_before_noloc (pat, insn, bb);
     }
   else
-    new_insn = emit_insn_after_noloc (pat, insn);
+    new_insn = emit_insn_after_noloc (pat, insn, bb);
 
   while (1)
     {
@@ -4168,7 +4118,7 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map)
                           now.  */
 
                        if (eg->flags & EDGE_ABNORMAL)
-                         insert_insn_end_bb (index_map[j], bb, 0);
+                         insert_insn_end_basic_block (index_map[j], bb, 0);
                        else
                          {
                            insn = process_insert_insn (index_map[j]);
@@ -4380,7 +4330,7 @@ pre_insert_copies (void)
 static rtx
 gcse_emit_move_after (rtx src, rtx dest, rtx insn)
 {
-  rtx new;
+  rtx new_rtx;
   rtx set = single_set (insn), set2;
   rtx note;
   rtx eqv;
@@ -4388,20 +4338,20 @@ gcse_emit_move_after (rtx src, rtx dest, rtx insn)
   /* This should never fail since we're creating a reg->reg copy
      we've verified to be valid.  */
 
-  new = emit_insn_after (gen_move_insn (dest, src), insn);
+  new_rtx = emit_insn_after (gen_move_insn (dest, src), insn);
 
   /* Note the equivalence for local CSE pass.  */
-  set2 = single_set (new);
+  set2 = single_set (new_rtx);
   if (!set2 || !rtx_equal_p (SET_DEST (set2), dest))
-    return new;
+    return new_rtx;
   if ((note = find_reg_equal_equiv_note (insn)))
     eqv = XEXP (note, 0);
   else
     eqv = SET_SRC (set);
 
-  set_unique_reg_note (new, REG_EQUAL, copy_insn_1 (eqv));
+  set_unique_reg_note (new_rtx, REG_EQUAL, copy_insn_1 (eqv));
 
-  return new;
+  return new_rtx;
 }
 
 /* Delete redundant computations.
@@ -4438,14 +4388,14 @@ pre_delete (void)
 
            /* We only delete insns that have a single_set.  */
            if (TEST_BIT (pre_delete_map[bb->index], indx)
-               && (set = single_set (insn)) != 0)
+               && (set = single_set (insn)) != 0
+                && dbg_cnt (pre_insn))
              {
                /* 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.  */
                if (expr->reaching_reg == NULL)
-                 expr->reaching_reg
-                   = gen_reg_rtx (GET_MODE (SET_DEST (set)));
+                 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);
@@ -4515,7 +4465,6 @@ pre_gcse (void)
      - we know which insns are redundant when we go to create copies  */
 
   changed = pre_delete ();
-
   did_insert = pre_edge_insert (edge_list, index_map);
 
   /* In other places with reaching expressions, copy the expression to the
@@ -4578,14 +4527,15 @@ one_pre_gcse_pass (int pass)
   return changed;
 }
 \f
-/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN.
-   If notes are added to an insn which references a CODE_LABEL, the
-   LABEL_NUSES count is incremented.  We have to add REG_LABEL notes,
-   because the following loop optimization pass requires them.  */
+/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them
+   to INSN.  If such notes are added to an insn which references a
+   CODE_LABEL, the LABEL_NUSES count is incremented.  We have to add
+   that note, because the following loop optimization pass requires
+   them.  */
 
 /* ??? If there was a jump optimization pass after gcse and before loop,
    then we would not need to do this here, because jump would add the
-   necessary REG_LABEL notes.  */
+   necessary REG_LABEL_OPERAND and REG_LABEL_TARGET notes.  */
 
 static void
 add_label_notes (rtx x, rtx insn)
@@ -4602,10 +4552,15 @@ add_label_notes (rtx x, rtx insn)
         We no longer ignore such label references (see LABEL_REF handling in
         mark_jump_label for additional information).  */
 
-      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
-                                           REG_NOTES (insn));
+      /* There's no reason for current users to emit jump-insns with
+        such a LABEL_REF, so we don't have to handle REG_LABEL_TARGET
+        notes.  */
+      gcc_assert (!JUMP_P (insn));
+      add_reg_note (insn, REG_LABEL_OPERAND, XEXP (x, 0));
+
       if (LABEL_P (XEXP (x, 0)))
        LABEL_NUSES (XEXP (x, 0))++;
+
       return;
     }
 
@@ -4643,7 +4598,7 @@ compute_transpout (void)
 
   FOR_EACH_BB (bb)
     {
-      /* Note that flow inserted a nop a the end of basic blocks that
+      /* Note that flow inserted a nop at the end of basic blocks that
         end in call instructions for reasons other than abnormal
         control flow.  */
       if (! CALL_P (BB_END (bb)))
@@ -4738,10 +4693,14 @@ compute_code_hoist_vbeinout (void)
         the convergence.  */
       FOR_EACH_BB_REVERSE (bb)
        {
-         changed |= sbitmap_a_or_b_and_c_cg (hoist_vbein[bb->index], antloc[bb->index],
-                                             hoist_vbeout[bb->index], transp[bb->index]);
          if (bb->next_bb != EXIT_BLOCK_PTR)
-           sbitmap_intersection_of_succs (hoist_vbeout[bb->index], hoist_vbein, bb->index);
+           sbitmap_intersection_of_succs (hoist_vbeout[bb->index],
+                                          hoist_vbein, bb->index);
+
+         changed |= sbitmap_a_or_b_and_c_cg (hoist_vbein[bb->index],
+                                             antloc[bb->index],
+                                             hoist_vbeout[bb->index],
+                                             transp[bb->index]);
        }
 
       passes++;
@@ -4829,8 +4788,7 @@ static void
 hoist_code (void)
 {
   basic_block bb, dominated;
-  basic_block *domby;
-  unsigned int domby_len;
+  VEC (basic_block, heap) *domby;
   unsigned int i,j;
   struct expr **index_map;
   struct expr *expr;
@@ -4852,7 +4810,7 @@ hoist_code (void)
       int found = 0;
       int insn_inserted_p;
 
-      domby_len = get_dominated_by (CDI_DOMINATORS, bb, &domby);
+      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++)
@@ -4865,9 +4823,8 @@ hoist_code (void)
              /* 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; j < domby_len; j++)
+             for (j = 0; VEC_iterate (basic_block, domby, j, dominated); j++)
                {
-                 dominated = domby[j];
                  /* Ignore self dominance.  */
                  if (bb == dominated)
                    continue;
@@ -4906,8 +4863,8 @@ hoist_code (void)
       /* If we found nothing to hoist, then quit now.  */
       if (! found)
         {
-         free (domby);
-       continue;
+         VEC_free (basic_block, heap, domby);
+         continue;
        }
 
       /* Loop over all the hoistable expressions.  */
@@ -4923,9 +4880,8 @@ hoist_code (void)
              /* 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; j < domby_len; j++)
+             for (j = 0; VEC_iterate (basic_block, domby, j, dominated); j++)
                {
-                 dominated = domby[j];
                  /* Ignore self dominance.  */
                  if (bb == dominated)
                    continue;
@@ -4962,21 +4918,21 @@ hoist_code (void)
                         from the mode of the original destination pseudo.  */
                      if (expr->reaching_reg == NULL)
                        expr->reaching_reg
-                         = gen_reg_rtx (GET_MODE (SET_DEST (set)));
+                         = 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;
                      if (!insn_inserted_p)
                        {
-                         insert_insn_end_bb (index_map[i], bb, 0);
+                         insert_insn_end_basic_block (index_map[i], bb, 0);
                          insn_inserted_p = 1;
                        }
                    }
                }
            }
        }
-      free (domby);
+      VEC_free (basic_block, heap, domby);
     }
 
   free (index_map);
@@ -5038,14 +4994,15 @@ static hashval_t
 pre_ldst_expr_hash (const void *p)
 {
   int do_not_record_p = 0;
-  const struct ls_expr *x = p;
+  const struct ls_expr *const x = (const struct ls_expr *) p;
   return hash_rtx (x->pattern, GET_MODE (x->pattern), &do_not_record_p, NULL, false);
 }
 
 static int
 pre_ldst_expr_eq (const void *p1, const void *p2)
 {
-  const struct ls_expr *ptr1 = p1, *ptr2 = p2;
+  const struct ls_expr *const ptr1 = (const struct ls_expr *) p1,
+    *const ptr2 = (const struct ls_expr *) p2;
   return expr_equiv_p (ptr1->pattern, ptr2->pattern);
 }
 
@@ -5167,7 +5124,7 @@ find_rtx_in_ldst (rtx x)
   slot = htab_find_slot (pre_ldst_table, &e, NO_INSERT);
   if (!slot || ((struct ls_expr *)*slot)->invalid)
     return NULL;
-  return *slot;
+  return (struct ls_expr *) *slot;
 }
 
 /* Assign each element of the list of mems a monotonically increasing value.  */
@@ -5207,7 +5164,7 @@ next_ls_expr (struct ls_expr * ptr)
    ld_motion list, otherwise we let the usual aliasing take care of it.  */
 
 static int
-simple_mem (rtx x)
+simple_mem (const_rtx x)
 {
   if (! MEM_P (x))
     return 0;
@@ -5421,7 +5378,7 @@ update_ld_motion_stores (struct expr * expr)
          rtx pat = PATTERN (insn);
          rtx src = SET_SRC (pat);
          rtx reg = expr->reaching_reg;
-         rtx copy, new;
+         rtx copy, new_rtx;
 
          /* If we've already copied it, continue.  */
          if (expr->reaching_reg == src)
@@ -5437,9 +5394,10 @@ update_ld_motion_stores (struct expr * expr)
            }
 
          copy = gen_move_insn ( reg, copy_rtx (SET_SRC (pat)));
-         new = emit_insn_before (copy, insn);
-         record_one_set (REGNO (reg), new);
+         new_rtx = emit_insn_before (copy, insn);
+         record_one_set (REGNO (reg), new_rtx);
          SET_SRC (pat) = reg;
+         df_insn_rescan (insn);
 
          /* un-recognize this pattern since it's probably different now.  */
          INSN_CODE (insn) = -1;
@@ -5471,10 +5429,10 @@ static int num_stores;
    note_stores.  */
 
 static void
-reg_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED,
+reg_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
              void *data)
 {
-  sbitmap bb_reg = data;
+  sbitmap bb_reg = (sbitmap) data;
 
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
@@ -5491,10 +5449,10 @@ reg_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED,
    note_stores.  */
 
 static void
-reg_clear_last_set (rtx dest, rtx setter ATTRIBUTE_UNUSED,
+reg_clear_last_set (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
              void *data)
 {
-  int *dead_vec = data;
+  int *dead_vec = (int *) data;
 
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
@@ -5508,9 +5466,9 @@ reg_clear_last_set (rtx dest, rtx setter ATTRIBUTE_UNUSED,
    due to set of registers in bitmap REGS_SET.  */
 
 static bool
-store_ops_ok (rtx x, int *regs_set)
+store_ops_ok (const_rtx x, int *regs_set)
 {
-  rtx reg;
+  const_rtx reg;
 
   for (; x; x = XEXP (x, 1))
     {
@@ -5556,8 +5514,10 @@ extract_mentioned_regs_helper (rtx x, rtx accum)
 
     case PRE_DEC:
     case PRE_INC:
+    case PRE_MODIFY:
     case POST_DEC:
     case POST_INC:
+    case POST_MODIFY:
       /* We do not run this function with arguments having side effects.  */
       gcc_unreachable ();
 
@@ -5566,6 +5526,7 @@ extract_mentioned_regs_helper (rtx x, rtx accum)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -5862,7 +5823,7 @@ compute_store_table (void)
    after the X.  */
 
 static bool
-load_kills_store (rtx x, rtx store_pattern, int after)
+load_kills_store (const_rtx x, const_rtx store_pattern, int after)
 {
   if (after)
     return anti_dependence (x, store_pattern);
@@ -5877,7 +5838,7 @@ load_kills_store (rtx x, rtx store_pattern, int after)
    after the insn X.  */
 
 static bool
-find_loads (rtx x, rtx store_pattern, int after)
+find_loads (const_rtx x, const_rtx store_pattern, int after)
 {
   const char * fmt;
   int i, j;
@@ -5910,7 +5871,7 @@ find_loads (rtx x, rtx store_pattern, int after)
 }
 
 static inline bool
-store_killed_in_pat (rtx x, rtx pat, int after)
+store_killed_in_pat (const_rtx x, const_rtx pat, int after)
 {
   if (GET_CODE (pat) == SET)
     {
@@ -5947,9 +5908,9 @@ store_killed_in_pat (rtx x, rtx pat, int after)
    after the insn.  Return true if it does.  */
 
 static bool
-store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
+store_killed_in_insn (const_rtx x, const_rtx x_regs, const_rtx insn, int after)
 {
-  rtx reg, base, note, pat;
+  const_rtx reg, base, note, pat;
 
   if (!INSN_P (insn))
     return false;
@@ -5958,7 +5919,7 @@ store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
     {
       /* A normal or pure call might read from pattern,
         but a const call will not.  */
-      if (! CONST_OR_PURE_CALL_P (insn) || pure_call_p (insn))
+      if (!RTL_CONST_CALL_P (insn))
        return true;
 
       /* But even a const call reads its parameters.  Check whether the
@@ -6015,7 +5976,7 @@ store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
    is killed, return the last insn in that it occurs in FAIL_INSN.  */
 
 static bool
-store_killed_after (rtx x, rtx x_regs, rtx insn, basic_block bb,
+store_killed_after (const_rtx x, const_rtx x_regs, const_rtx insn, const_basic_block bb,
                    int *regs_set_after, rtx *fail_insn)
 {
   rtx last = BB_END (bb), act;
@@ -6044,7 +6005,7 @@ store_killed_after (rtx x, rtx x_regs, rtx insn, basic_block bb,
    within basic block BB. X_REGS is list of registers mentioned in X.
    REGS_SET_BEFORE is bitmap of registers set before or in this insn.  */
 static bool
-store_killed_before (rtx x, rtx x_regs, rtx insn, basic_block bb,
+store_killed_before (const_rtx x, const_rtx x_regs, const_rtx insn, const_basic_block bb,
                     int *regs_set_before)
 {
   rtx first = BB_HEAD (bb);
@@ -6091,7 +6052,7 @@ build_store_vectors (void)
             are any side effects.  */
          if (TEST_BIT (ae_gen[bb->index], ptr->index))
            {
-             rtx r = gen_reg_rtx (GET_MODE (ptr->pattern));
+             rtx r = gen_reg_rtx_and_attrs (ptr->pattern);
              if (dump_file)
                fprintf (dump_file, "Removing redundant store:\n");
              replace_store_insn (r, XEXP (st, 0), bb, ptr);
@@ -6151,7 +6112,7 @@ build_store_vectors (void)
    the BB_HEAD if needed.  */
 
 static void
-insert_insn_start_bb (rtx insn, basic_block bb)
+insert_insn_start_basic_block (rtx insn, basic_block bb)
 {
   /* Insert at start of successor block.  */
   rtx prev = PREV_INSN (BB_HEAD (bb));
@@ -6159,8 +6120,7 @@ insert_insn_start_bb (rtx insn, basic_block bb)
   while (before != 0)
     {
       if (! LABEL_P (before)
-         && (! NOTE_P (before)
-             || NOTE_LINE_NUMBER (before) != NOTE_INSN_BASIC_BLOCK))
+         && !NOTE_INSN_BASIC_BLOCK_P (before))
        break;
       prev = before;
       if (prev == BB_END (bb))
@@ -6168,7 +6128,7 @@ insert_insn_start_bb (rtx insn, basic_block bb)
       before = NEXT_INSN (before);
     }
 
-  insn = emit_insn_after_noloc (insn, prev);
+  insn = emit_insn_after_noloc (insn, prev, bb);
 
   if (dump_file)
     {
@@ -6225,7 +6185,7 @@ insert_store (struct ls_expr * expr, edge e)
          int index = EDGE_INDEX (edge_list, tmp->src, tmp->dest);
          RESET_BIT (pre_insert_map[index], expr->index);
        }
-      insert_insn_start_bb (insn, bb);
+      insert_insn_start_basic_block (insn, bb);
       return 0;
     }
 
@@ -6335,21 +6295,10 @@ remove_reachable_equiv_notes (basic_block bb, struct ls_expr *smexpr)
 static void
 replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr)
 {
-  rtx insn, mem, note, set, ptr, pair;
+  rtx insn, mem, note, set, ptr;
 
   mem = smexpr->pattern;
   insn = gen_move_insn (reg, SET_SRC (single_set (del)));
-  insn = emit_insn_after (insn, del);
-
-  if (dump_file)
-    {
-      fprintf (dump_file,
-              "STORE_MOTION  delete insn in BB %d:\n      ", bb->index);
-      print_inline_rtx (dump_file, del, 6);
-      fprintf (dump_file, "\nSTORE MOTION  replaced with insn:\n      ");
-      print_inline_rtx (dump_file, insn, 6);
-      fprintf (dump_file, "\n");
-    }
 
   for (ptr = ANTIC_STORE_LIST (smexpr); ptr; ptr = XEXP (ptr, 1))
     if (XEXP (ptr, 0) == del)
@@ -6358,23 +6307,21 @@ replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr)
        break;
       }
 
-  /* Move the notes from the deleted insn to its replacement, and patch
-     up the LIBCALL notes.  */
+  /* Move the notes from the deleted insn to its replacement.  */
   REG_NOTES (insn) = REG_NOTES (del);
 
-  note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
-  if (note)
-    {
-      pair = XEXP (note, 0);
-      note = find_reg_note (pair, REG_LIBCALL, NULL_RTX);
-      XEXP (note, 0) = insn;
-    }
-  note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
-  if (note)
+  /* Emit the insn AFTER all the notes are transferred.
+     This is cheaper since we avoid df rescanning for the note change.  */
+  insn = emit_insn_after (insn, del);
+
+  if (dump_file)
     {
-      pair = XEXP (note, 0);
-      note = find_reg_note (pair, REG_RETVAL, NULL_RTX);
-      XEXP (note, 0) = insn;
+      fprintf (dump_file,
+              "STORE_MOTION  delete insn in BB %d:\n      ", bb->index);
+      print_inline_rtx (dump_file, del, 6);
+      fprintf (dump_file, "\nSTORE MOTION  replaced with insn:\n      ");
+      print_inline_rtx (dump_file, insn, 6);
+      fprintf (dump_file, "\n");
     }
 
   delete_insn (del);
@@ -6412,7 +6359,7 @@ delete_store (struct ls_expr * expr, basic_block bb)
   rtx reg, i, del;
 
   if (expr->reaching_reg == NULL_RTX)
-    expr->reaching_reg = gen_reg_rtx (GET_MODE (expr->pattern));
+    expr->reaching_reg = gen_reg_rtx_and_attrs (expr->pattern);
 
   reg = expr->reaching_reg;
 
@@ -6544,7 +6491,7 @@ bypass_jumps (void)
 
   /* We do not construct an accurate cfg in functions which call
      setjmp, so just punt to be safe.  */
-  if (current_function_calls_setjmp)
+  if (cfun->calls_setjmp)
     return 0;
 
   /* Identify the basic block information for this function, including
@@ -6579,7 +6526,7 @@ bypass_jumps (void)
 
   max_gcse_regno = max_reg_num ();
   alloc_gcse_mem ();
-  changed = one_cprop_pass (MAX_GCSE_PASSES + 2, true, true);
+  changed = one_cprop_pass (3, true, true);
   free_gcse_mem ();
 
   if (dump_file)
@@ -6594,7 +6541,6 @@ bypass_jumps (void)
 
   /* We are finished with alias.  */
   end_alias_analysis ();
-  allocate_reg_info (max_reg_num (), FALSE, FALSE);
 
   return changed;
 }
@@ -6642,27 +6588,28 @@ is_too_expensive (const char *pass)
 static bool
 gate_handle_jump_bypass (void)
 {
-  return optimize > 0 && flag_gcse;
+  return optimize > 0 && flag_gcse
+    && dbg_cnt (jump_bypass);
 }
 
 /* Perform jump bypassing and control flow optimizations.  */
 static unsigned int
 rest_of_handle_jump_bypass (void)
 {
-  cleanup_cfg (CLEANUP_EXPENSIVE);
-  reg_scan (get_insns (), max_reg_num ());
-
+  delete_unreachable_blocks ();
   if (bypass_jumps ())
     {
-      rebuild_jump_labels (get_insns ());
-      cleanup_cfg (CLEANUP_EXPENSIVE);
       delete_trivially_dead_insns (get_insns (), max_reg_num ());
+      rebuild_jump_labels (get_insns ());
+      cleanup_cfg (0);
     }
   return 0;
 }
 
-struct tree_opt_pass pass_jump_bypass =
+struct rtl_opt_pass pass_jump_bypass =
 {
+ {
+  RTL_PASS,
   "bypass",                             /* name */
   gate_handle_jump_bypass,              /* gate */   
   rest_of_handle_jump_bypass,           /* execute */       
@@ -6670,20 +6617,21 @@ struct tree_opt_pass pass_jump_bypass =
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   TV_BYPASS,                            /* tv_id */
-  0,                                    /* properties_required */
+  PROP_cfglayout,                       /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func |
-  TODO_ggc_collect | TODO_verify_flow,  /* todo_flags_finish */
-  'G'                                   /* letter */
+  TODO_ggc_collect | TODO_verify_flow   /* todo_flags_finish */
+ }
 };
 
 
 static bool
 gate_handle_gcse (void)
 {
-  return optimize > 0 && flag_gcse;
+  return optimize > 0 && flag_gcse
+    && dbg_cnt (gcse);
 }
 
 
@@ -6692,11 +6640,9 @@ rest_of_handle_gcse (void)
 {
   int save_csb, save_cfj;
   int tem2 = 0, tem;
-
   tem = gcse_main (get_insns ());
-  rebuild_jump_labels (get_insns ());
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
+  rebuild_jump_labels (get_insns ());
   save_csb = flag_cse_skip_blocks;
   save_cfj = flag_cse_follow_jumps;
   flag_cse_skip_blocks = flag_cse_follow_jumps = 0;
@@ -6706,8 +6652,8 @@ rest_of_handle_gcse (void)
   if (flag_expensive_optimizations)
     {
       timevar_push (TV_CSE);
-      reg_scan (get_insns (), max_reg_num ());
       tem2 = cse_main (get_insns (), max_reg_num ());
+      df_finish_pass (false);
       purge_all_dead_edges ();
       delete_trivially_dead_insns (get_insns (), max_reg_num ());
       timevar_pop (TV_CSE);
@@ -6716,22 +6662,25 @@ rest_of_handle_gcse (void)
 
   /* If gcse or cse altered any jumps, rerun jump optimizations to clean
      things up.  */
-  if (tem || tem2)
+  if (tem || tem2 == 2)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      delete_dead_jumptables ();
-      cleanup_cfg (CLEANUP_EXPENSIVE);
+      cleanup_cfg (0);
       timevar_pop (TV_JUMP);
     }
+  else if (tem2 == 1)
+    cleanup_cfg (0);
 
   flag_cse_skip_blocks = save_csb;
   flag_cse_follow_jumps = save_cfj;
   return 0;
 }
 
-struct tree_opt_pass pass_gcse =
+struct rtl_opt_pass pass_gcse =
 {
+ {
+  RTL_PASS,
   "gcse1",                              /* name */
   gate_handle_gcse,                     /* gate */   
   rest_of_handle_gcse,                 /* execute */       
@@ -6739,13 +6688,14 @@ struct tree_opt_pass pass_gcse =
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   TV_GCSE,                              /* tv_id */
-  0,                                    /* properties_required */
+  PROP_cfglayout,                       /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
-  TODO_verify_flow | TODO_ggc_collect,  /* todo_flags_finish */
-  'G'                                   /* letter */
+  TODO_verify_flow | TODO_ggc_collect   /* todo_flags_finish */
+ }
 };