re PR rtl-optimization/62078 (ICE: verify_flow_info failed: missing REG_EH_REGION...
[gcc.git] / gcc / dse.c
index ca227ea15dd5e0d3f3d5a3e1dec0991050f42ad6..ea6f24585c532abe24944f75023d4f7ac975275e 100644 (file)
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -1,5 +1,5 @@
 /* RTL dead store elimination.
-   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
 
    Contributed by Richard Sandiford <rsandifor@codesourcery.com>
    and Kenneth Zadeck <zadeck@naturalbridge.com>
@@ -25,36 +25,72 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "hashtab.h"
+#include "hash-table.h"
 #include "tm.h"
 #include "rtl.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "real.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
 #include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
+#include "regset.h"
 #include "flags.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "predict.h"
+#include "basic-block.h"
 #include "df.h"
 #include "cselib.h"
-#include "timevar.h"
 #include "tree-pass.h"
 #include "alloc-pool.h"
-#include "alias.h"
 #include "insn-config.h"
+#include "hashtab.h"
+#include "function.h"
+#include "statistics.h"
+#include "fixed-value.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "recog.h"
-#include "dse.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "dbgcnt.h"
 #include "target.h"
+#include "params.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "gimple-ssa.h"
+#include "rtl-iter.h"
+#include "cfgcleanup.h"
 
 /* This file contains three techniques for performing Dead Store
-   Elimination (dse).  
+   Elimination (dse).
 
    * The first technique performs dse locally on any base address.  It
    is based on the cselib which is a local value numbering technique.
    This technique is local to a basic block but deals with a fairly
    general addresses.
+
    * The second technique performs dse globally but is restricted to
    base addresses that are either constant or are relative to the
    frame_pointer.
@@ -84,7 +120,7 @@ along with GCC; see the file COPYING3.  If not see
    stores, only one store to an address is necessary because those
    stores die at the end of the function.
 
-   3) Set up the global dataflow equations based on processing the 
+   3) Set up the global dataflow equations based on processing the
    info parsed in the first step.
 
    4) Solve the dataflow equations.
@@ -92,7 +128,7 @@ along with GCC; see the file COPYING3.  If not see
    5) Delete the insns that the global analysis has indicated are
    unnecessary.
 
-   6) Delete insns that store the same value as preceeding store
+   6) Delete insns that store the same value as preceding store
    where the earlier store couldn't be eliminated.
 
    7) Cleanup.
@@ -103,7 +139,7 @@ along with GCC; see the file COPYING3.  If not see
    the first pass could examine a block in either direction.  The
    forwards ordering is to accommodate cselib.
 
-   We a simplifying assumption: addresses fall into four broad
+   We make a simplifying assumption: addresses fall into four broad
    categories:
 
    1) base has rtx_varies_p == false, offset is constant.
@@ -112,18 +148,18 @@ along with GCC; see the file COPYING3.  If not see
    4) base has rtx_varies_p == true, offset variable.
 
    The local passes are able to process all 4 kinds of addresses.  The
-   global pass only handles (1).
+   global pass only handles 1).
 
    The global problem is formulated as follows:
 
      A store, S1, to address A, where A is not relative to the stack
      frame, can be eliminated if all paths from S1 to the end of the
-     of the function contain another store to A before a read to A.
+     function contain another store to A before a read to A.
 
      If the address A is relative to the stack frame, a store S2 to A
-     can be eliminated if there are no paths from S1 that reach the
+     can be eliminated if there are no paths from S2 that reach the
      end of the function that read A before another store to A.  In
-     this case S2 can be deleted if there are paths to from S2 to the
+     this case S2 can be deleted if there are paths from S2 to the
      end of the function that have no reads or writes to A.  This
      second case allows stores to the stack frame to be deleted that
      would otherwise die when the function returns.  This cannot be
@@ -134,14 +170,14 @@ along with GCC; see the file COPYING3.  If not see
      dataflow problem where the stores are the gens and reads are the
      kills.  Set union problems are rare and require some special
      handling given our representation of bitmaps.  A straightforward
-     implementation of requires a lot of bitmaps filled with 1s.
+     implementation requires a lot of bitmaps filled with 1s.
      These are expensive and cumbersome in our bitmap formulation so
      care has been taken to avoid large vectors filled with 1s.  See
      the comments in bb_info and in the dataflow confluence functions
-     for details.  
+     for details.
 
    There are two places for further enhancements to this algorithm:
-   
+
    1) The original dse which was embedded in a pass called flow also
    did local address forwarding.  For example in
 
@@ -183,7 +219,7 @@ along with GCC; see the file COPYING3.  If not see
      with the same mode and alias set.  The backout in this case is a
      little more graceful than (a).  In this case the slot is unmarked
      as being a spill slot and if final address comes out to be based
-     off the frame pointer, the global algorithm handles this slot.  
+     off the frame pointer, the global algorithm handles this slot.
 
      c) For any pass that may prespill, there is currently no
      mechanism to tell the dse pass that the slot being used has the
@@ -198,12 +234,25 @@ along with GCC; see the file COPYING3.  If not see
    that really have constant offsets this size.  */
 #define MAX_OFFSET (64 * 1024)
 
+/* Obstack for the DSE dataflow bitmaps.  We don't want to put these
+   on the default obstack because these bitmaps can grow quite large
+   (~2GB for the small (!) test case of PR54146) and we'll hold on to
+   all that memory until the end of the compiler run.
+   As a bonus, delete_tree_live_info can destroy all the bitmaps by just
+   releasing the whole obstack.  */
+static bitmap_obstack dse_bitmap_obstack;
+
+/* Obstack for other data.  As for above: Kinda nice to be able to
+   throw it all away at the end in one big sweep.  */
+static struct obstack dse_obstack;
 
+/* Scratch bitmap for cselib's cselib_expand_value_rtx.  */
 static bitmap scratch = NULL;
+
 struct insn_info;
 
 /* This structure holds information about a candidate store.  */
-struct store_info 
+struct store_info
 {
 
   /* False means this is a clobber.  */
@@ -216,7 +265,7 @@ struct store_info
      true, this is -1.  Otherwise, it is the index into the group
      table.  */
   int group_id;
-  
+
   /* This is the cselib value.  */
   cselib_val *cse_base;
 
@@ -285,7 +334,7 @@ static alloc_pool rtx_store_info_pool;
 
 /* This structure holds information about a load.  These are only
    built for rtx bases.  */
-struct read_info 
+struct read_info
 {
   /* The id of the mem group of the base address.  */
   int group_id;
@@ -310,7 +359,7 @@ static alloc_pool read_info_pool;
 
 /* One of these records is created for each insn.  */
 
-struct insn_info 
+struct insn_info
 {
   /* Set true if the insn contains a store but the insn itself cannot
      be deleted.  This is set if the insn is a parallel and there is
@@ -324,6 +373,11 @@ struct insn_info
      contains a wild read, the use_rec will be null.  */
   bool wild_read;
 
+  /* This is true only for CALL instructions which could potentially read
+     any non-frame memory location. This field is used by the global
+     algorithm.  */
+  bool non_frame_wild_read;
+
   /* This field is only used for the processing of const functions.
      These functions cannot read memory, but they can read the stack
      because that is where they may get their parms.  We need to be
@@ -339,9 +393,11 @@ struct insn_info
        either stack pointer or hard frame pointer based.  This means
        that we have no other choice than also killing all the frame
        pointer based stores upon encountering a const function call.
-     This field is set after reload for const function calls.  Having
-     this set is less severe than a wild read, it just means that all
-     the frame related stores are killed rather than all the stores.  */
+     This field is set after reload for const function calls and before
+     reload for const tail function calls on targets where arg pointer
+     is the frame pointer.  Having this set is less severe than a wild
+     read, it just means that all the frame related stores are killed
+     rather than all the stores.  */
   bool frame_read;
 
   /* This field is only used for the processing of const functions.
@@ -354,7 +410,7 @@ struct insn_info
   bool contains_cselib_groups;
 
   /* The insn. */
-  rtx insn;
+  rtx_insn *insn;
 
   /* The list of mem sets or mem clobbers that are contained in this
      insn.  If the insn is deletable, it contains only one mem set.
@@ -369,11 +425,18 @@ struct insn_info
      created.  */
   read_info_t read_rec;
 
+  /* The live fixed registers.  We assume only fixed registers can
+     cause trouble by being clobbered from an expanded pattern;
+     storing only the live fixed registers (rather than all registers)
+     means less memory needs to be allocated / copied for the individual
+     stores.  */
+  regset fixed_regs_live;
+
   /* The prev insn in the basic block.  */
   struct insn_info * prev_insn;
 
   /* The linked list of insns that are in consideration for removal in
-     the forwards pass thru the basic block.  This pointer may be
+     the forwards pass through the basic block.  This pointer may be
      trash as it is not cleared when a wild read occurs.  The only
      time it is guaranteed to be correct is when the traversal starts
      at active_local_stores.  */
@@ -384,10 +447,11 @@ typedef struct insn_info *insn_info_t;
 static alloc_pool insn_info_pool;
 
 /* The linked list of stores that are under consideration in this
-   basic block.  */   
+   basic block.  */
 static insn_info_t active_local_stores;
+static int active_local_stores_len;
 
-struct bb_info 
+struct dse_bb_info
 {
 
   /* Pointer to the insn info for the last insn in the block.  These
@@ -410,7 +474,7 @@ struct bb_info
 
   /* The set of store positions that exist in this block before a wild read.  */
   bitmap gen;
-  
+
   /* The set of load positions that exist in this block above the
      same position of a store.  */
   bitmap kill;
@@ -439,13 +503,13 @@ struct bb_info
   /* The following bitvector is indexed by the reg number.  It
      contains the set of regs that are live at the current instruction
      being processed.  While it contains info for all of the
-     registers, only the pseudos are actually examined.  It is used to
-     assure that shift sequences that are inserted do not accidently
-     clobber live hard regs.  */
+     registers, only the hard registers are actually examined.  It is used
+     to assure that shift and/or add sequences that are inserted do not
+     accidentally clobber live hard regs.  */
   bitmap regs_live;
 };
 
-typedef struct bb_info *bb_info_t;
+typedef struct dse_bb_info *bb_info_t;
 static alloc_pool bb_info_pool;
 
 /* Table to hold all bb_infos.  */
@@ -455,7 +519,7 @@ static bb_info_t *bb_table;
    memory.  There are also not many of the rtx bases because they are
    very limited in scope.  */
 
-struct group_info 
+struct group_info
 {
   /* The actual base of the address.  */
   rtx rtx_base;
@@ -472,10 +536,11 @@ struct group_info
      hard_frame_pointer.  */
   bool frame_related;
 
-  /* A mem wrapped around the base pointer for the group in order to
-     do read dependency.  */
+  /* A mem wrapped around the base pointer for the group in order to do
+     read dependency.  It must be given BLKmode in order to encompass all
+     the possible offsets from the base.  */
   rtx base_mem;
-  
+
   /* Canonized version of base_mem's address.  */
   rtx canon_base_addr;
 
@@ -497,6 +562,11 @@ struct group_info
      deleted.  */
   bitmap store1_n, store1_p, store2_n, store2_p;
 
+  /* These bitmaps keep track of offsets in this group escape this function.
+     An offset escapes if it corresponds to a named variable whose
+     addressable flag is set.  */
+  bitmap escaped_n, escaped_p;
+
   /* The positions in this bitmap have the same assignments as the in,
      out, gen and kill bitmaps.  This bitmap is all zeros except for
      the positions that are occupied by stores for this group.  */
@@ -506,28 +576,23 @@ struct group_info
      positions in the global bitmaps.  It is only created after all of
      the all of stores have been scanned and we know which ones we
      care about.  */
-  int *offset_map_n, *offset_map_p; 
-  int offset_map_size_n, offset_map_size_p; 
+  int *offset_map_n, *offset_map_p;
+  int offset_map_size_n, offset_map_size_p;
 };
 typedef struct group_info *group_info_t;
 typedef const struct group_info *const_group_info_t;
 static alloc_pool rtx_group_info_pool;
 
-/* Tables of group_info structures, hashed by base value.  */
-static htab_t rtx_group_table;
-
 /* Index into the rtx_group_vec.  */
 static int rtx_group_next_id;
 
-DEF_VEC_P(group_info_t);
-DEF_VEC_ALLOC_P(group_info_t,heap);
 
-static VEC(group_info_t,heap) *rtx_group_vec;
+static vec<group_info_t> rtx_group_vec;
 
 
 /* This structure holds the set of changes that are being deferred
    when removing read operation.  See replace_read.  */
-struct deferred_change 
+struct deferred_change
 {
 
   /* The mem that is being replaced.  */
@@ -544,20 +609,6 @@ static alloc_pool deferred_change_pool;
 
 static deferred_change_t deferred_change_list = NULL;
 
-/* This are used to hold the alias sets of spill variables.  Since
-   these are never aliased and there may be a lot of them, it makes
-   sense to treat them specially.  This bitvector is only allocated in
-   calls from dse_record_singleton_alias_set which currently is only
-   made during reload1.  So when dse is called before reload this
-   mechanism does nothing.  */
-
-static bitmap clear_alias_sets = NULL;
-
-/* The set of clear_alias_sets that have been disqualified because
-   there are loads or stores using a different mode than the alias set
-   was registered with.  */ 
-static bitmap disqualified_clear_alias_sets = NULL;
-
 /* The group that holds all of the clear_alias_sets.  */
 static group_info_t clear_alias_group;
 
@@ -568,59 +619,32 @@ static htab_t clear_alias_mode_table;
 struct clear_alias_mode_holder
 {
   alias_set_type alias_set;
-  enum machine_mode mode;
+  machine_mode mode;
 };
 
-static alloc_pool clear_alias_mode_pool;
-
 /* This is true except if cfun->stdarg -- i.e. we cannot do
    this for vararg functions because they play games with the frame.  */
 static bool stores_off_frame_dead_at_return;
 
 /* Counter for stats.  */
-static int globally_deleted; 
-static int locally_deleted; 
-static int spill_deleted; 
-      
+static int globally_deleted;
+static int locally_deleted;
+static int spill_deleted;
+
 static bitmap all_blocks;
 
+/* Locations that are killed by calls in the global phase.  */
+static bitmap kill_on_calls;
+
 /* The number of bits used in the global bitmaps.  */
 static unsigned int current_position;
-
-
-static bool gate_dse (void);
-static bool gate_dse1 (void);
-static bool gate_dse2 (void);
-
 \f
 /*----------------------------------------------------------------------------
    Zeroth step.
 
-   Initialization.  
+   Initialization.
 ----------------------------------------------------------------------------*/
 
-/* Hashtable callbacks for maintaining the "bases" field of
-   store_group_info, given that the addresses are function invariants.  */
-
-static int
-clear_alias_mode_eq (const void *p1, const void *p2)
-{
-  const struct clear_alias_mode_holder * h1 
-    = (const struct clear_alias_mode_holder *) p1;
-  const struct clear_alias_mode_holder * h2 
-    = (const struct clear_alias_mode_holder *) p2;
-  return h1->alias_set == h2->alias_set;
-}
-
-
-static hashval_t
-clear_alias_mode_hash (const void *p)
-{
-  const struct clear_alias_mode_holder *holder 
-    = (const struct clear_alias_mode_holder *) p;
-  return holder->alias_set;
-}
-
 
 /* Find the entry associated with ALIAS_SET.  */
 
@@ -629,11 +653,11 @@ clear_alias_set_lookup (alias_set_type alias_set)
 {
   struct clear_alias_mode_holder tmp_holder;
   void **slot;
-  
+
   tmp_holder.alias_set = alias_set;
   slot = htab_find_slot (clear_alias_mode_table, &tmp_holder, NO_INSERT);
   gcc_assert (*slot);
-  
+
   return (struct clear_alias_mode_holder *) *slot;
 }
 
@@ -641,39 +665,47 @@ clear_alias_set_lookup (alias_set_type alias_set)
 /* Hashtable callbacks for maintaining the "bases" field of
    store_group_info, given that the addresses are function invariants.  */
 
-static int
-invariant_group_base_eq (const void *p1, const void *p2)
+struct invariant_group_base_hasher : typed_noop_remove <group_info>
+{
+  typedef group_info value_type;
+  typedef group_info compare_type;
+  static inline hashval_t hash (const value_type *);
+  static inline bool equal (const value_type *, const compare_type *);
+};
+
+inline bool
+invariant_group_base_hasher::equal (const value_type *gi1,
+                                   const compare_type *gi2)
 {
-  const_group_info_t gi1 = (const_group_info_t) p1;
-  const_group_info_t gi2 = (const_group_info_t) p2;
   return rtx_equal_p (gi1->rtx_base, gi2->rtx_base);
 }
 
-
-static hashval_t
-invariant_group_base_hash (const void *p)
+inline hashval_t
+invariant_group_base_hasher::hash (const value_type *gi)
 {
-  const_group_info_t gi = (const_group_info_t) p;
   int do_not_record;
   return hash_rtx (gi->rtx_base, Pmode, &do_not_record, NULL, false);
 }
 
+/* Tables of group_info structures, hashed by base value.  */
+static hash_table<invariant_group_base_hasher> *rtx_group_table;
+
 
 /* Get the GROUP for BASE.  Add a new group if it is not there.  */
 
 static group_info_t
 get_group_info (rtx base)
 {
-  struct group_info tmp_gi; 
-  group_info_t gi; 
-  void **slot;
+  struct group_info tmp_gi;
+  group_info_t gi;
+  group_info **slot;
 
   if (base)
     {
       /* Find the store_base_info structure for BASE, creating a new one
         if necessary.  */
       tmp_gi.rtx_base = base;
-      slot = htab_find_slot (rtx_group_table, &tmp_gi, INSERT);
+      slot = rtx_group_table->find_slot (&tmp_gi, INSERT);
       gi = (group_info_t) *slot;
     }
   else
@@ -684,17 +716,19 @@ get_group_info (rtx base)
            (group_info_t) pool_alloc (rtx_group_info_pool);
          memset (gi, 0, sizeof (struct group_info));
          gi->id = rtx_group_next_id++;
-         gi->store1_n = BITMAP_ALLOC (NULL);
-         gi->store1_p = BITMAP_ALLOC (NULL);
-         gi->store2_n = BITMAP_ALLOC (NULL);
-         gi->store2_p = BITMAP_ALLOC (NULL);
-         gi->group_kill = BITMAP_ALLOC (NULL);
+         gi->store1_n = BITMAP_ALLOC (&dse_bitmap_obstack);
+         gi->store1_p = BITMAP_ALLOC (&dse_bitmap_obstack);
+         gi->store2_n = BITMAP_ALLOC (&dse_bitmap_obstack);
+         gi->store2_p = BITMAP_ALLOC (&dse_bitmap_obstack);
+         gi->escaped_p = BITMAP_ALLOC (&dse_bitmap_obstack);
+         gi->escaped_n = BITMAP_ALLOC (&dse_bitmap_obstack);
+         gi->group_kill = BITMAP_ALLOC (&dse_bitmap_obstack);
          gi->process_globally = false;
          gi->offset_map_size_n = 0;
          gi->offset_map_size_p = 0;
          gi->offset_map_n = NULL;
          gi->offset_map_p = NULL;
-         VEC_safe_push (group_info_t, heap, rtx_group_vec, gi);
+         rtx_group_vec.safe_push (gi);
        }
       return clear_alias_group;
     }
@@ -704,21 +738,23 @@ get_group_info (rtx base)
       *slot = gi = (group_info_t) pool_alloc (rtx_group_info_pool);
       gi->rtx_base = base;
       gi->id = rtx_group_next_id++;
-      gi->base_mem = gen_rtx_MEM (QImode, base);
+      gi->base_mem = gen_rtx_MEM (BLKmode, base);
       gi->canon_base_addr = canon_rtx (base);
-      gi->store1_n = BITMAP_ALLOC (NULL);
-      gi->store1_p = BITMAP_ALLOC (NULL);
-      gi->store2_n = BITMAP_ALLOC (NULL);
-      gi->store2_p = BITMAP_ALLOC (NULL);
-      gi->group_kill = BITMAP_ALLOC (NULL);
+      gi->store1_n = BITMAP_ALLOC (&dse_bitmap_obstack);
+      gi->store1_p = BITMAP_ALLOC (&dse_bitmap_obstack);
+      gi->store2_n = BITMAP_ALLOC (&dse_bitmap_obstack);
+      gi->store2_p = BITMAP_ALLOC (&dse_bitmap_obstack);
+      gi->escaped_p = BITMAP_ALLOC (&dse_bitmap_obstack);
+      gi->escaped_n = BITMAP_ALLOC (&dse_bitmap_obstack);
+      gi->group_kill = BITMAP_ALLOC (&dse_bitmap_obstack);
       gi->process_globally = false;
-      gi->frame_related = 
+      gi->frame_related =
        (base == frame_pointer_rtx) || (base == hard_frame_pointer_rtx);
       gi->offset_map_size_n = 0;
       gi->offset_map_size_p = 0;
       gi->offset_map_n = NULL;
       gi->offset_map_p = NULL;
-      VEC_safe_push (group_info_t, heap, rtx_group_vec, gi);
+      rtx_group_vec.safe_push (gi);
     }
 
   return gi;
@@ -734,41 +770,41 @@ dse_step0 (void)
   globally_deleted = 0;
   spill_deleted = 0;
 
-  scratch = BITMAP_ALLOC (NULL);
+  bitmap_obstack_initialize (&dse_bitmap_obstack);
+  gcc_obstack_init (&dse_obstack);
+
+  scratch = BITMAP_ALLOC (&reg_obstack);
+  kill_on_calls = BITMAP_ALLOC (&dse_bitmap_obstack);
 
   rtx_store_info_pool
-    = create_alloc_pool ("rtx_store_info_pool", 
+    = create_alloc_pool ("rtx_store_info_pool",
                         sizeof (struct store_info), 100);
   read_info_pool
-    = create_alloc_pool ("read_info_pool", 
+    = create_alloc_pool ("read_info_pool",
                         sizeof (struct read_info), 100);
   insn_info_pool
-    = create_alloc_pool ("insn_info_pool", 
+    = create_alloc_pool ("insn_info_pool",
                         sizeof (struct insn_info), 100);
   bb_info_pool
-    = create_alloc_pool ("bb_info_pool", 
-                        sizeof (struct bb_info), 100);
+    = create_alloc_pool ("bb_info_pool",
+                        sizeof (struct dse_bb_info), 100);
   rtx_group_info_pool
-    = create_alloc_pool ("rtx_group_info_pool", 
+    = create_alloc_pool ("rtx_group_info_pool",
                         sizeof (struct group_info), 100);
   deferred_change_pool
-    = create_alloc_pool ("deferred_change_pool", 
+    = create_alloc_pool ("deferred_change_pool",
                         sizeof (struct deferred_change), 10);
 
-  rtx_group_table = htab_create (11, invariant_group_base_hash,
-                                invariant_group_base_eq, NULL);
+  rtx_group_table = new hash_table<invariant_group_base_hasher> (11);
 
-  bb_table = XCNEWVEC (bb_info_t, last_basic_block);
+  bb_table = XNEWVEC (bb_info_t, last_basic_block_for_fn (cfun));
   rtx_group_next_id = 0;
 
   stores_off_frame_dead_at_return = !cfun->stdarg;
 
   init_alias_analysis ();
-  
-  if (clear_alias_sets)
-    clear_alias_group = get_group_info (NULL);
-  else
-    clear_alias_group = NULL;
+
+  clear_alias_group = NULL;
 }
 
 
@@ -783,7 +819,7 @@ dse_step0 (void)
 
 /* Delete all of the store_info recs from INSN_INFO.  */
 
-static void 
+static void
 free_store_info (insn_info_t insn_info)
 {
   store_info_t store_info = insn_info->store_rec;
@@ -804,97 +840,129 @@ free_store_info (insn_info_t insn_info)
   insn_info->store_rec = NULL;
 }
 
+typedef struct
+{
+  rtx_insn *first, *current;
+  regset fixed_regs_live;
+  bool failure;
+} note_add_store_info;
 
-struct insn_size {
-  int size;
-  rtx insn;
-};
+/* Callback for emit_inc_dec_insn_before via note_stores.
+   Check if a register is clobbered which is live afterwards.  */
 
+static void
+note_add_store (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *data)
+{
+  rtx_insn *insn;
+  note_add_store_info *info = (note_add_store_info *) data;
+  int r, n;
 
-/* Add an insn to do the add inside a x if it is a
-   PRE/POST-INC/DEC/MODIFY.  D is an structure containing the insn and
-   the size of the mode of the MEM that this is inside of.  */
+  if (!REG_P (loc))
+    return;
 
-static int
-replace_inc_dec (rtx *r, void *d)
-{
-  rtx x = *r;
-  struct insn_size *data = (struct insn_size *)d;
-  switch (GET_CODE (x))
-    {
-    case PRE_INC:
-    case POST_INC:
-      {
-       rtx r1 = XEXP (x, 0);
-       rtx c = gen_int_mode (data->size, Pmode);
-       emit_insn_before (gen_rtx_SET (Pmode, r1, 
-                                      gen_rtx_PLUS (Pmode, r1, c)),
-                         data->insn);
-       return -1;
-      }
-                
-    case PRE_DEC:
-    case POST_DEC:
-      {
-       rtx r1 = XEXP (x, 0);
-       rtx c = gen_int_mode (-data->size, Pmode);
-       emit_insn_before (gen_rtx_SET (Pmode, r1, 
-                                      gen_rtx_PLUS (Pmode, r1, c)),
-                         data->insn);
-       return -1;
-      }
-       
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      {
-       /* We can reuse the add because we are about to delete the
-          insn that contained it.  */
-       rtx add = XEXP (x, 0);
-       rtx r1 = XEXP (add, 0);
-       emit_insn_before (gen_rtx_SET (Pmode, r1, add), data->insn);
-       return -1;
-      }
+  /* If this register is referenced by the current or an earlier insn,
+     that's OK.  E.g. this applies to the register that is being incremented
+     with this addition.  */
+  for (insn = info->first;
+       insn != NEXT_INSN (info->current);
+       insn = NEXT_INSN (insn))
+    if (reg_referenced_p (loc, PATTERN (insn)))
+      return;
 
-    default:
-      return 0;
+  /* If we come here, we have a clobber of a register that's only OK
+     if that register is not live.  If we don't have liveness information
+     available, fail now.  */
+  if (!info->fixed_regs_live)
+    {
+      info->failure =  true;
+      return;
     }
+  /* Now check if this is a live fixed register.  */
+  r = REGNO (loc);
+  n = hard_regno_nregs[r][GET_MODE (loc)];
+  while (--n >=  0)
+    if (REGNO_REG_SET_P (info->fixed_regs_live, r+n))
+      info->failure =  true;
 }
-                        
 
-/* If X is a MEM, check the address to see if it is PRE/POST-INC/DEC/MODIFY
-   and generate an add to replace that.  */
+/* Callback for for_each_inc_dec that emits an INSN that sets DEST to
+   SRC + SRCOFF before insn ARG.  */
 
 static int
-replace_inc_dec_mem (rtx *r, void *d)
+emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
+                         rtx op ATTRIBUTE_UNUSED,
+                         rtx dest, rtx src, rtx srcoff, void *arg)
 {
-  rtx x = *r;
-  if (x != NULL_RTX && MEM_P (x))
+  insn_info_t insn_info = (insn_info_t) arg;
+  rtx_insn *insn = insn_info->insn, *new_insn, *cur;
+  note_add_store_info info;
+
+  /* We can reuse all operands without copying, because we are about
+     to delete the insn that contained it.  */
+  if (srcoff)
+    {
+      start_sequence ();
+      emit_insn (gen_add3_insn (dest, src, srcoff));
+      new_insn = get_insns ();
+      end_sequence ();
+    }
+  else
+    new_insn = as_a <rtx_insn *> (gen_move_insn (dest, src));
+  info.first = new_insn;
+  info.fixed_regs_live = insn_info->fixed_regs_live;
+  info.failure = false;
+  for (cur = new_insn; cur; cur = NEXT_INSN (cur))
     {
-      struct insn_size data;
+      info.current = cur;
+      note_stores (PATTERN (cur), note_add_store, &info);
+    }
 
-      data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx) d;
+  /* If a failure was flagged above, return 1 so that for_each_inc_dec will
+     return it immediately, communicating the failure to its caller.  */
+  if (info.failure)
+    return 1;
+
+  emit_insn_before (new_insn, insn);
 
-      for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
-       
-      return -1;
-    }
   return 0;
 }
 
-/* Before we delete INSN, make sure that the auto inc/dec, if it is
-   there, is split into a separate insn.  */
+/* Before we delete INSN_INFO->INSN, make sure that the auto inc/dec, if it
+   is there, is split into a separate insn.
+   Return true on success (or if there was nothing to do), false on failure.  */
 
-static void
-check_for_inc_dec (rtx insn)
+static bool
+check_for_inc_dec_1 (insn_info_t insn_info)
 {
+  rtx_insn *insn = insn_info->insn;
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    for_each_rtx (&insn, replace_inc_dec_mem, insn);
+    return for_each_inc_dec (PATTERN (insn), emit_inc_dec_insn_before,
+                            insn_info) == 0;
+  return true;
 }
 
 
-/* Delete the insn and free all of the fields inside INSN_INFO.  */ 
+/* Entry point for postreload.  If you work on reload_cse, or you need this
+   anywhere else, consider if you can provide register liveness information
+   and add a parameter to this function so that it can be passed down in
+   insn_info.fixed_regs_live.  */
+bool
+check_for_inc_dec (rtx_insn *insn)
+{
+  struct insn_info insn_info;
+  rtx note;
+
+  insn_info.insn = insn;
+  insn_info.fixed_regs_live = NULL;
+  note = find_reg_note (insn, REG_INC, NULL_RTX);
+  if (note)
+    return for_each_inc_dec (PATTERN (insn), emit_inc_dec_insn_before,
+                            &insn_info) == 0;
+  return true;
+}
+
+/* Delete the insn and free all of the fields inside INSN_INFO.  */
 
 static void
 delete_dead_store_insn (insn_info_t insn_info)
@@ -904,13 +972,14 @@ delete_dead_store_insn (insn_info_t insn_info)
   if (!dbg_cnt (dse))
     return;
 
-  check_for_inc_dec (insn_info->insn);
-  if (dump_file)
+  if (!check_for_inc_dec_1 (insn_info))
+    return;
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      fprintf (dump_file, "Locally deleting insn %d ", 
+      fprintf (dump_file, "Locally deleting insn %d ",
               INSN_UID (insn_info->insn));
       if (insn_info->store_rec->alias_set)
-       fprintf (dump_file, "alias set %d\n", 
+       fprintf (dump_file, "alias set %d\n",
                 (int) insn_info->store_rec->alias_set);
       else
        fprintf (dump_file, "\n");
@@ -918,7 +987,7 @@ delete_dead_store_insn (insn_info_t insn_info)
 
   free_store_info (insn_info);
   read_info = insn_info->read_rec;
-       
+
   while (read_info)
     {
       read_info_t next = read_info->next;
@@ -934,39 +1003,83 @@ delete_dead_store_insn (insn_info_t insn_info)
   insn_info->wild_read = false;
 }
 
+/* Return whether DECL, a local variable, can possibly escape the current
+   function scope.  */
+
+static bool
+local_variable_can_escape (tree decl)
+{
+  if (TREE_ADDRESSABLE (decl))
+    return true;
+
+  /* If this is a partitioned variable, we need to consider all the variables
+     in the partition.  This is necessary because a store into one of them can
+     be replaced with a store into another and this may not change the outcome
+     of the escape analysis.  */
+  if (cfun->gimple_df->decls_to_pointers != NULL)
+    {
+      tree *namep = cfun->gimple_df->decls_to_pointers->get (decl);
+      if (namep)
+       return TREE_ADDRESSABLE (*namep);
+    }
+
+  return false;
+}
+
+/* Return whether EXPR can possibly escape the current function scope.  */
+
+static bool
+can_escape (tree expr)
+{
+  tree base;
+  if (!expr)
+    return true;
+  base = get_base_address (expr);
+  if (DECL_P (base)
+      && !may_be_aliased (base)
+      && !(TREE_CODE (base) == VAR_DECL
+          && !DECL_EXTERNAL (base)
+          && !TREE_STATIC (base)
+          && local_variable_can_escape (base)))
+    return false;
+  return true;
+}
 
 /* Set the store* bitmaps offset_map_size* fields in GROUP based on
    OFFSET and WIDTH.  */
 
 static void
-set_usage_bits (group_info_t group, HOST_WIDE_INT offset, HOST_WIDE_INT width)
+set_usage_bits (group_info_t group, HOST_WIDE_INT offset, HOST_WIDE_INT width,
+                tree expr)
 {
   HOST_WIDE_INT i;
-
+  bool expr_escapes = can_escape (expr);
   if (offset > -MAX_OFFSET && offset + width < MAX_OFFSET)
     for (i=offset; i<offset+width; i++)
       {
        bitmap store1;
        bitmap store2;
+        bitmap escaped;
        int ai;
        if (i < 0)
          {
            store1 = group->store1_n;
            store2 = group->store2_n;
+           escaped = group->escaped_n;
            ai = -i;
          }
        else
          {
            store1 = group->store1_p;
            store2 = group->store2_p;
+           escaped = group->escaped_p;
            ai = i;
          }
-       
-       if (bitmap_bit_p (store1, ai))
+
+       if (!bitmap_set_bit (store1, ai))
          bitmap_set_bit (store2, ai);
-       else 
+       else
          {
-           bitmap_set_bit (store1, ai);
            if (i < 0)
              {
                if (group->offset_map_size_n < ai)
@@ -978,18 +1091,25 @@ set_usage_bits (group_info_t group, HOST_WIDE_INT offset, HOST_WIDE_INT width)
                  group->offset_map_size_p = ai;
              }
          }
+        if (expr_escapes)
+          bitmap_set_bit (escaped, ai);
       }
 }
 
+static void
+reset_active_stores (void)
+{
+  active_local_stores = NULL;
+  active_local_stores_len = 0;
+}
 
-/* Set the BB_INFO so that the last insn is marked as a wild read.  */
+/* Free all READ_REC of the LAST_INSN of BB_INFO.  */
 
 static void
-add_wild_read (bb_info_t bb_info)
+free_read_records (bb_info_t bb_info)
 {
   insn_info_t insn_info = bb_info->last_insn;
   read_info_t *ptr = &insn_info->read_rec;
-
   while (*ptr)
     {
       read_info_t next = (*ptr)->next;
@@ -997,14 +1117,34 @@ add_wild_read (bb_info_t bb_info)
         {
           pool_free (read_info_pool, *ptr);
           *ptr = next;
-       }
-      else 
-       ptr = &(*ptr)->next;
+        }
+      else
+        ptr = &(*ptr)->next;
     }
+}
+
+/* Set the BB_INFO so that the last insn is marked as a wild read.  */
+
+static void
+add_wild_read (bb_info_t bb_info)
+{
+  insn_info_t insn_info = bb_info->last_insn;
   insn_info->wild_read = true;
-  active_local_stores = NULL;
+  free_read_records (bb_info);
+  reset_active_stores ();
 }
 
+/* Set the BB_INFO so that the last insn is marked as a wild read of
+   non-frame locations.  */
+
+static void
+add_non_frame_wild_read (bb_info_t bb_info)
+{
+  insn_info_t insn_info = bb_info->last_insn;
+  insn_info->non_frame_wild_read = true;
+  free_read_records (bb_info);
+  reset_active_stores ();
+}
 
 /* Return true if X is a constant or one of the registers that behave
    as a constant over the life of a function.  This is equivalent to
@@ -1013,20 +1153,11 @@ add_wild_read (bb_info_t bb_info)
 static bool
 const_or_frame_p (rtx x)
 {
-  switch (GET_CODE (x))
-    {
-    case MEM:
-      return MEM_READONLY_P (x);
-
-    case CONST:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return true;
+  if (CONSTANT_P (x))
+    return true;
 
-    case REG:
+  if (GET_CODE (x) == REG)
+    {
       /* Note that we have to test for the actual rtx used for the frame
         and arg pointers and not just the register number in case we have
         eliminated the frame and/or arg pointer and are using it
@@ -1037,14 +1168,13 @@ const_or_frame_p (rtx x)
          || x == pic_offset_table_rtx)
        return true;
       return false;
-
-    default:
-      return false;
     }
+  
+  return false;
 }
 
-/* Take all reasonable action to put the address of MEM into the form 
-   that we can do analysis on.  
+/* Take all reasonable action to put the address of MEM into the form
+   that we can do analysis on.
 
    The gold standard is to get the address into the form: address +
    OFFSET where address is something that rtx_varies_p considers a
@@ -1054,8 +1184,8 @@ const_or_frame_p (rtx x)
    obtained from that.
 
    If that fails, we try cselib to get a value we can at least use
-   locally.  If that fails we return false.  
-   
+   locally.  If that fails we return false.
+
    The GROUP_ID is set to -1 for cselib bases and the index of the
    group for non_varying bases.
 
@@ -1065,121 +1195,108 @@ static bool
 canon_address (rtx mem,
               alias_set_type *alias_set_out,
               int *group_id,
-              HOST_WIDE_INT *offset, 
+              HOST_WIDE_INT *offset,
               cselib_val **base)
 {
+  machine_mode address_mode = get_address_mode (mem);
   rtx mem_address = XEXP (mem, 0);
   rtx expanded_address, address;
-  /* Make sure that cselib is has initialized all of the operands of
-     the address before asking it to do the subst.  */
-
-  if (clear_alias_sets)
-    {
-      /* If this is a spill, do not do any further processing.  */
-      alias_set_type alias_set = MEM_ALIAS_SET (mem);
-      if (dump_file)
-       fprintf (dump_file, "found alias set %d\n", (int) alias_set);
-      if (bitmap_bit_p (clear_alias_sets, alias_set))
-       {
-         struct clear_alias_mode_holder *entry 
-           = clear_alias_set_lookup (alias_set);
-
-         /* If the modes do not match, we cannot process this set.  */
-         if (entry->mode != GET_MODE (mem))
-           {
-             if (dump_file)
-               fprintf (dump_file, 
-                        "disqualifying alias set %d, (%s) != (%s)\n", 
-                        (int) alias_set, GET_MODE_NAME (entry->mode), 
-                        GET_MODE_NAME (GET_MODE (mem)));
-             
-             bitmap_set_bit (disqualified_clear_alias_sets, alias_set);
-             return false;
-           }
-
-         *alias_set_out = alias_set;
-         *group_id = clear_alias_group->id;
-         return true;
-       }
-    }
+  int expanded;
 
   *alias_set_out = 0;
 
-  cselib_lookup (mem_address, Pmode, 1);
+  cselib_lookup (mem_address, address_mode, 1, GET_MODE (mem));
 
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "  mem: ");
       print_inline_rtx (dump_file, mem_address, 0);
       fprintf (dump_file, "\n");
     }
 
-  /* Use cselib to replace all of the reg references with the full
-     expression.  This will take care of the case where we have 
-
-     r_x = base + offset;
-     val = *r_x;
-   
-     by making it into 
+  /* First see if just canon_rtx (mem_address) is const or frame,
+     if not, try cselib_expand_value_rtx and call canon_rtx on that.  */
+  address = NULL_RTX;
+  for (expanded = 0; expanded < 2; expanded++)
+    {
+      if (expanded)
+       {
+         /* Use cselib to replace all of the reg references with the full
+            expression.  This will take care of the case where we have
 
-     val = *(base + offset);  
-  */
+            r_x = base + offset;
+            val = *r_x;
 
-  expanded_address = cselib_expand_value_rtx (mem_address, scratch, 5);
+            by making it into
 
-  /* If this fails, just go with the mem_address.  */
-  if (!expanded_address)
-    expanded_address = mem_address;
+            val = *(base + offset);  */
 
-  /* Split the address into canonical BASE + OFFSET terms.  */
-  address = canon_rtx (expanded_address);
+         expanded_address = cselib_expand_value_rtx (mem_address,
+                                                     scratch, 5);
 
-  *offset = 0;
+         /* If this fails, just go with the address from first
+            iteration.  */
+         if (!expanded_address)
+           break;
+       }
+      else
+       expanded_address = mem_address;
 
-  if (dump_file)
-    {
-      fprintf (dump_file, "\n   after cselib_expand address: ");
-      print_inline_rtx (dump_file, expanded_address, 0);
-      fprintf (dump_file, "\n");
+      /* Split the address into canonical BASE + OFFSET terms.  */
+      address = canon_rtx (expanded_address);
 
-      fprintf (dump_file, "\n   after canon_rtx address: ");
-      print_inline_rtx (dump_file, address, 0);
-      fprintf (dump_file, "\n");
-    }
+      *offset = 0;
 
-  if (GET_CODE (address) == CONST)
-    address = XEXP (address, 0);
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         if (expanded)
+           {
+             fprintf (dump_file, "\n   after cselib_expand address: ");
+             print_inline_rtx (dump_file, expanded_address, 0);
+             fprintf (dump_file, "\n");
+           }
 
-  if (GET_CODE (address) == PLUS && GET_CODE (XEXP (address, 1)) == CONST_INT)
-    {
-      *offset = INTVAL (XEXP (address, 1));
-      address = XEXP (address, 0);
-    }
+         fprintf (dump_file, "\n   after canon_rtx address: ");
+         print_inline_rtx (dump_file, address, 0);
+         fprintf (dump_file, "\n");
+       }
 
-  if (const_or_frame_p (address))
-    {
-      group_info_t group = get_group_info (address);
+      if (GET_CODE (address) == CONST)
+       address = XEXP (address, 0);
 
-      if (dump_file)
-       fprintf (dump_file, "  gid=%d offset=%d \n", group->id, (int)*offset);
-      *base = NULL;
-      *group_id = group->id;
-    }
-  else
-    {
-      *base = cselib_lookup (address, Pmode, true);
-      *group_id = -1;
+      if (GET_CODE (address) == PLUS
+         && CONST_INT_P (XEXP (address, 1)))
+       {
+         *offset = INTVAL (XEXP (address, 1));
+         address = XEXP (address, 0);
+       }
 
-      if (*base == NULL)
+      if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (mem))
+         && const_or_frame_p (address))
        {
-         if (dump_file)
-           fprintf (dump_file, " no cselib val - should be a wild read.\n");
-         return false;
+         group_info_t group = get_group_info (address);
+
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, "  gid=%d offset=%d \n",
+                    group->id, (int)*offset);
+         *base = NULL;
+         *group_id = group->id;
+         return true;
        }
-      if (dump_file)
-       fprintf (dump_file, "  varying cselib base=%d offset = %d\n", 
-                (*base)->value, (int)*offset);
     }
+
+  *base = cselib_lookup (address, address_mode, true, GET_MODE (mem));
+  *group_id = -1;
+
+  if (*base == NULL)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, " no cselib val - should be a wild read.\n");
+      return false;
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "  varying cselib base=%u:%u offset = %d\n",
+            (*base)->uid, (*base)->hash, (int)*offset);
   return true;
 }
 
@@ -1213,11 +1330,8 @@ set_position_unneeded (store_info_t s_info, int pos)
 {
   if (__builtin_expect (s_info->is_large, false))
     {
-      if (!bitmap_bit_p (s_info->positions_needed.large.bmap, pos))
-       {
-         s_info->positions_needed.large.count++;
-         bitmap_set_bit (s_info->positions_needed.large.bmap, pos);
-       }
+      if (bitmap_set_bit (s_info->positions_needed.large.bmap, pos))
+       s_info->positions_needed.large.count++;
     }
   else
     s_info->positions_needed.small_bitmask
@@ -1275,7 +1389,7 @@ all_positions_needed_p (store_info_t s_info, int start, int width)
 }
 
 
-static rtx get_stored_val (store_info_t, enum machine_mode, HOST_WIDE_INT,
+static rtx get_stored_val (store_info_t, machine_mode, HOST_WIDE_INT,
                           HOST_WIDE_INT, basic_block, bool);
 
 
@@ -1323,7 +1437,7 @@ record_store (rtx body, bb_info_t bb_info)
     {
       if (GET_CODE (XEXP (mem, 0)) == SCRATCH)
        {
-         if (dump_file
+         if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, " adding wild read for (clobber (mem:BLK (scratch))\n");
          add_wild_read (bb_info);
          insn_info->cannot_delete = true;
@@ -1331,11 +1445,10 @@ record_store (rtx body, bb_info_t bb_info)
        }
       /* Handle (set (mem:BLK (addr) [... S36 ...]) (const_int 0))
         as memset (addr, 0, 36);  */
-      else if (!MEM_SIZE (mem)
-              || !CONST_INT_P (MEM_SIZE (mem))
+      else if (!MEM_SIZE_KNOWN_P (mem)
+              || MEM_SIZE (mem) <= 0
+              || MEM_SIZE (mem) > MAX_OFFSET
               || GET_CODE (body) != SET
-              || INTVAL (MEM_SIZE (mem)) <= 0
-              || INTVAL (MEM_SIZE (mem)) > MAX_OFFSET
               || !CONST_INT_P (SET_SRC (body)))
        {
          if (!store_is_unused)
@@ -1360,12 +1473,9 @@ record_store (rtx body, bb_info_t bb_info)
     }
 
   if (GET_MODE (mem) == BLKmode)
-    width = INTVAL (MEM_SIZE (mem));
+    width = MEM_SIZE (mem);
   else
-    {
-      width = GET_MODE_SIZE (GET_MODE (mem));
-      gcc_assert ((unsigned) width <= HOST_BITS_PER_WIDE_INT);
-    }
+    width = GET_MODE_SIZE (GET_MODE (mem));
 
   if (spill_alias_set)
     {
@@ -1373,18 +1483,16 @@ record_store (rtx body, bb_info_t bb_info)
       bitmap store2 = clear_alias_group->store2_p;
 
       gcc_assert (GET_MODE (mem) != BLKmode);
-      
-      if (bitmap_bit_p (store1, spill_alias_set))
+
+      if (!bitmap_set_bit (store1, spill_alias_set))
        bitmap_set_bit (store2, spill_alias_set);
-      else 
-       bitmap_set_bit (store1, spill_alias_set);
-       
+
       if (clear_alias_group->offset_map_size_p < spill_alias_set)
        clear_alias_group->offset_map_size_p = spill_alias_set;
-  
+
       store_info = (store_info_t) pool_alloc (rtx_store_info_pool);
 
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " processing spill store %d(%s)\n",
                 (int) spill_alias_set, GET_MODE_NAME (GET_MODE (mem)));
     }
@@ -1392,31 +1500,28 @@ record_store (rtx body, bb_info_t bb_info)
     {
       /* In the restrictive case where the base is a constant or the
         frame pointer we can do global analysis.  */
-      
-      group_info_t group 
-       = VEC_index (group_info_t, rtx_group_vec, group_id);
-      
+
+      group_info_t group
+       = rtx_group_vec[group_id];
+      tree expr = MEM_EXPR (mem);
+
       store_info = (store_info_t) pool_alloc (rtx_store_info_pool);
-      set_usage_bits (group, offset, width);
+      set_usage_bits (group, offset, width, expr);
 
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " processing const base store gid=%d[%d..%d)\n",
                 group_id, (int)offset, (int)(offset+width));
     }
   else
     {
-      rtx base_term = find_base_term (XEXP (mem, 0));
-      if (!base_term
-         || (GET_CODE (base_term) == ADDRESS
-             && GET_MODE (base_term) == Pmode
-             && XEXP (base_term, 0) == stack_pointer_rtx))
+      if (may_be_sp_based_p (XEXP (mem, 0)))
        insn_info->stack_pointer_based = true;
       insn_info->contains_cselib_groups = true;
 
       store_info = (store_info_t) pool_alloc (cse_store_info_pool);
       group_id = -1;
 
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " processing cselib store [%d..%d)\n",
                 (int)offset, (int)(offset+width));
     }
@@ -1467,11 +1572,11 @@ record_store (rtx body, bb_info_t bb_info)
       else
        {
          group_info_t group
-           = VEC_index (group_info_t, rtx_group_vec, group_id);
+           = rtx_group_vec[group_id];
          mem_addr = group->canon_base_addr;
        }
       if (offset)
-       mem_addr = plus_constant (mem_addr, offset);
+       mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
     }
 
   while (ptr)
@@ -1490,7 +1595,7 @@ record_store (rtx body, bb_info_t bb_info)
        del = false;
       else if (s_info->alias_set)
        {
-         struct clear_alias_mode_holder *entry 
+         struct clear_alias_mode_holder *entry
            = clear_alias_set_lookup (s_info->alias_set);
          /* Generally, spills cannot be processed if and of the
             references to the slot have a different mode.  But if
@@ -1503,17 +1608,17 @@ record_store (rtx body, bb_info_t bb_info)
              del = true;
              set_all_positions_unneeded (s_info);
            }
-         if (dump_file)
+         if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "    trying spill store in insn=%d alias_set=%d\n",
                     INSN_UID (ptr->insn), (int) s_info->alias_set);
        }
-      else if ((s_info->group_id == group_id) 
+      else if ((s_info->group_id == group_id)
               && (s_info->cse_base == base))
        {
          HOST_WIDE_INT i;
-         if (dump_file)
+         if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "    trying store in insn=%d gid=%d[%d..%d)\n",
-                    INSN_UID (ptr->insn), s_info->group_id, 
+                    INSN_UID (ptr->insn), s_info->group_id,
                     (int)s_info->begin, (int)s_info->end);
 
          /* Even if PTR won't be eliminated as unneeded, if both
@@ -1561,10 +1666,10 @@ record_store (rtx body, bb_info_t bb_info)
           the value of store_info.  If it is, set the rhs to NULL to
           keep it from being used to remove a load.  */
        {
-         if (canon_true_dependence (s_info->mem, 
+         if (canon_true_dependence (s_info->mem,
                                     GET_MODE (s_info->mem),
                                     s_info->mem_addr,
-                                    mem, mem_addr, rtx_varies_p))
+                                    mem, mem_addr))
            {
              s_info->rhs = NULL;
              s_info->const_rhs = NULL;
@@ -1573,27 +1678,28 @@ record_store (rtx body, bb_info_t bb_info)
 
       /* An insn can be deleted if every position of every one of
         its s_infos is zero.  */
-      if (any_positions_needed_p (s_info)
-         || ptr->cannot_delete)
+      if (any_positions_needed_p (s_info))
        del = false;
 
       if (del)
        {
          insn_info_t insn_to_delete = ptr;
-         
+
+         active_local_stores_len--;
          if (last)
            last->next_local_store = ptr->next_local_store;
          else
            active_local_stores = ptr->next_local_store;
-         
-         delete_dead_store_insn (insn_to_delete);
+
+         if (!insn_to_delete->cannot_delete)
+           delete_dead_store_insn (insn_to_delete);
        }
       else
        last = ptr;
-      
+
       ptr = next;
     }
-  
+
   /* Finish filling in the store_info.  */
   store_info->next = insn_info->store_rec;
   insn_info->store_rec = store_info;
@@ -1605,7 +1711,7 @@ record_store (rtx body, bb_info_t bb_info)
     {
       store_info->is_large = true;
       store_info->positions_needed.large.count = 0;
-      store_info->positions_needed.large.bmap = BITMAP_ALLOC (NULL);
+      store_info->positions_needed.large.bmap = BITMAP_ALLOC (&dse_bitmap_obstack);
     }
   else
     {
@@ -1630,7 +1736,7 @@ record_store (rtx body, bb_info_t bb_info)
 static void
 dump_insn_info (const char * start, insn_info_t insn_info)
 {
-  fprintf (dump_file, "%s insn=%d %s\n", start, 
+  fprintf (dump_file, "%s insn=%d %s\n", start,
           INSN_UID (insn_info->insn),
           insn_info->store_rec ? "has store" : "naked");
 }
@@ -1647,11 +1753,11 @@ dump_insn_info (const char * start, insn_info_t insn_info)
 static rtx
 find_shift_sequence (int access_size,
                     store_info_t store_info,
-                    enum machine_mode read_mode,
+                    machine_mode read_mode,
                     int shift, bool speed, bool require_cst)
 {
-  enum machine_mode store_mode = GET_MODE (store_info->mem);
-  enum machine_mode new_mode;
+  machine_mode store_mode = GET_MODE (store_info->mem);
+  machine_mode new_mode;
   rtx read_reg = NULL;
 
   /* Some machines like the x86 have shift insns for each size of
@@ -1666,7 +1772,8 @@ find_shift_sequence (int access_size,
        GET_MODE_BITSIZE (new_mode) <= BITS_PER_WORD;
        new_mode = GET_MODE_WIDER_MODE (new_mode))
     {
-      rtx target, new_reg, shift_seq, insn, new_lhs;
+      rtx target, new_reg, new_lhs;
+      rtx_insn *shift_seq, *insn;
       int cost;
 
       /* If a constant was stored into memory, try to simplify it here,
@@ -1686,7 +1793,7 @@ find_shift_sequence (int access_size,
                  byte = subreg_lowpart_offset (read_mode, new_mode);
                  ret = simplify_subreg (read_mode, ret, new_mode, byte);
                  if (ret && CONSTANT_P (ret)
-                     && rtx_cost (ret, SET, speed) <= COSTS_N_INSNS (1))
+                     && set_src_cost (ret, speed) <= COSTS_N_INSNS (1))
                    return ret;
                }
            }
@@ -1698,8 +1805,7 @@ find_shift_sequence (int access_size,
       /* Try a wider mode if truncating the store mode to NEW_MODE
         requires a real instruction.  */
       if (GET_MODE_BITSIZE (new_mode) < GET_MODE_BITSIZE (store_mode)
-         && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (new_mode),
-                                    GET_MODE_BITSIZE (store_mode)))
+         && !TRULY_NOOP_TRUNCATION_MODES_P (new_mode, store_mode))
        continue;
 
       /* Also try a wider mode if the necessary punning is either not
@@ -1767,12 +1873,11 @@ look_for_hardregs (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
   bitmap regs_set = (bitmap) data;
 
   if (REG_P (x)
-      && REGNO (x) < FIRST_PSEUDO_REGISTER)
+      && HARD_REGISTER_P (x))
     {
-      int regno = REGNO (x);
-      int n = hard_regno_nregs[regno][GET_MODE (x)];
-      while (--n >= 0)
-       bitmap_set_bit (regs_set, regno + n);
+      unsigned int regno = REGNO (x);
+      bitmap_set_range (regs_set, regno,
+                       hard_regno_nregs[regno][GET_MODE (x)]);
     }
 }
 
@@ -1782,11 +1887,11 @@ look_for_hardregs (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
    if not successful.  If REQUIRE_CST is true, return always constant.  */
 
 static rtx
-get_stored_val (store_info_t store_info, enum machine_mode read_mode,
+get_stored_val (store_info_t store_info, machine_mode read_mode,
                HOST_WIDE_INT read_begin, HOST_WIDE_INT read_end,
                basic_block bb, bool require_cst)
 {
-  enum machine_mode store_mode = GET_MODE (store_info->mem);
+  machine_mode store_mode = GET_MODE (store_info->mem);
   int shift;
   int access_size; /* In bytes.  */
   rtx read_reg;
@@ -1833,7 +1938,7 @@ get_stored_val (store_info_t store_info, enum machine_mode read_mode,
              c |= (c << shift);
              shift <<= 1;
            }
-         read_reg = GEN_INT (trunc_int_for_mode (c, store_mode));
+         read_reg = gen_int_mode (c, store_mode);
          read_reg = extract_low_bits (read_mode, store_mode, read_reg);
        }
     }
@@ -1855,7 +1960,7 @@ get_stored_val (store_info_t store_info, enum machine_mode read_mode,
      ...
      ... <- A
 
-   and change it into 
+   and change it into
    r2 <- r1
    A <- r1
    ...
@@ -1882,13 +1987,14 @@ get_stored_val (store_info_t store_info, enum machine_mode read_mode,
    went ok.  */
 
 static bool
-replace_read (store_info_t store_info, insn_info_t store_insn, 
+replace_read (store_info_t store_info, insn_info_t store_insn,
              read_info_t read_info, insn_info_t read_insn, rtx *loc,
              bitmap regs_live)
 {
-  enum machine_mode store_mode = GET_MODE (store_info->mem);
-  enum machine_mode read_mode = GET_MODE (read_info->mem);
-  rtx insns, this_insn, read_reg;
+  machine_mode store_mode = GET_MODE (store_info->mem);
+  machine_mode read_mode = GET_MODE (read_info->mem);
+  rtx_insn *insns, *this_insn;
+  rtx read_reg;
   basic_block bb;
 
   if (!dbg_cnt (dse))
@@ -1903,7 +2009,7 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
      in cache, so it is not going to be an expensive one.  Thus, we
      are not willing to do a multi insn shift or worse a subroutine
      call to get rid of the read.  */
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "trying to replace %smode load in insn %d"
             " from %smode store in insn %d\n",
             GET_MODE_NAME (read_mode), INSN_UID (read_insn->insn),
@@ -1916,7 +2022,7 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
   if (read_reg == NULL_RTX)
     {
       end_sequence ();
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " -- could not extract bits of stored value\n");
       return false;
     }
@@ -1933,21 +2039,21 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
         live at this point.  For instance, this can happen if one of
         the insns sets the CC and the CC happened to be live at that
         point.  This does occasionally happen, see PR 37922.  */
-      bitmap regs_set = BITMAP_ALLOC (NULL);
+      bitmap regs_set = BITMAP_ALLOC (&reg_obstack);
 
       for (this_insn = insns; this_insn != NULL_RTX; this_insn = NEXT_INSN (this_insn))
        note_stores (PATTERN (this_insn), look_for_hardregs, regs_set);
-      
+
       bitmap_and_into (regs_set, regs_live);
       if (!bitmap_empty_p (regs_set))
        {
-         if (dump_file)
+         if (dump_file && (dump_flags & TDF_DETAILS))
            {
-             fprintf (dump_file, 
+             fprintf (dump_file,
                       "abandoning replacement because sequence clobbers live hardregs:");
              df_print_regset (dump_file, regs_set);
            }
-         
+
          BITMAP_FREE (regs_set);
          return false;
        }
@@ -1958,25 +2064,25 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
     {
       deferred_change_t deferred_change =
        (deferred_change_t) pool_alloc (deferred_change_pool);
-      
+
       /* Insert this right before the store insn where it will be safe
         from later insns that might change it before the read.  */
       emit_insn_before (insns, store_insn->insn);
-      
+
       /* And now for the kludge part: cselib croaks if you just
         return at this point.  There are two reasons for this:
-        
+
         1) Cselib has an idea of how many pseudos there are and
         that does not include the new ones we just added.
-        
+
         2) Cselib does not know about the move insn we added
         above the store_info, and there is no way to tell it
         about it, because it has "moved on".
-        
+
         Problem (1) is fixable with a certain amount of engineering.
         Problem (2) is requires starting the bb from scratch.  This
         could be expensive.
-        
+
         So we are just going to have to lie.  The move/extraction
         insns are not really an issue, cselib did not see them.  But
         the use of the new pseudo read_insn is a real problem because
@@ -1985,18 +2091,18 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
         and when we are finished with the block, we undo this.  We
         keep a table of mems to get rid of.  At the end of the basic
         block we can put them back.  */
-      
+
       *loc = read_info->mem;
       deferred_change->next = deferred_change_list;
       deferred_change_list = deferred_change;
       deferred_change->loc = loc;
       deferred_change->reg = read_reg;
-      
+
       /* Get rid of the read_info, from the point of view of the
         rest of dse, play like this read never happened.  */
       read_insn->read_rec = read_info->next;
       pool_free (read_info_pool, read_info);
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, " -- replaced the loaded MEM with ");
          print_simple_rtl (dump_file, read_reg);
@@ -2004,9 +2110,9 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
        }
       return true;
     }
-  else 
+  else
     {
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, " -- replacing the loaded MEM with ");
          print_simple_rtl (dump_file, read_reg);
@@ -2016,50 +2122,44 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
     }
 }
 
-/* A for_each_rtx callback in which DATA is the bb_info.  Check to see
-   if LOC is a mem and if it is look at the address and kill any
-   appropriate stores that may be active.  */
+/* Check the address of MEM *LOC and kill any appropriate stores that may
+   be active.  */
 
-static int
-check_mem_read_rtx (rtx *loc, void *data)
+static void
+check_mem_read_rtx (rtx *loc, bb_info_t bb_info)
 {
   rtx mem = *loc, mem_addr;
-  bb_info_t bb_info;
   insn_info_t insn_info;
   HOST_WIDE_INT offset = 0;
   HOST_WIDE_INT width = 0;
   alias_set_type spill_alias_set = 0;
-  cselib_val *base = NULL;  
+  cselib_val *base = NULL;
   int group_id;
   read_info_t read_info;
 
-  if (!mem || !MEM_P (mem))
-    return 0;
-
-  bb_info = (bb_info_t) data;
   insn_info = bb_info->last_insn;
 
   if ((MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
       || (MEM_VOLATILE_P (mem)))
     {
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " adding wild read, volatile or barrier.\n");
       add_wild_read (bb_info);
       insn_info->cannot_delete = true;
-      return 0;
+      return;
     }
 
   /* If it is reading readonly mem, then there can be no conflict with
      another write. */
   if (MEM_READONLY_P (mem))
-    return 0;
+    return;
 
   if (!canon_address (mem, &spill_alias_set, &group_id, &offset, &base))
     {
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " adding wild read, canon_address failure.\n");
       add_wild_read (bb_info);
-      return 0;
+      return;
     }
 
   if (GET_MODE (mem) == BLKmode)
@@ -2085,11 +2185,11 @@ check_mem_read_rtx (rtx *loc, void *data)
       else
        {
          group_info_t group
-           = VEC_index (group_info_t, rtx_group_vec, group_id);
+           = rtx_group_vec[group_id];
          mem_addr = group->canon_base_addr;
        }
       if (offset)
-       mem_addr = plus_constant (mem_addr, offset);
+       mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
     }
 
   /* We ignore the clobbers in store_info.  The is mildly aggressive,
@@ -2100,7 +2200,7 @@ check_mem_read_rtx (rtx *loc, void *data)
       insn_info_t i_ptr = active_local_stores;
       insn_info_t last = NULL;
 
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " processing spill load %d\n",
                 (int) spill_alias_set);
 
@@ -2111,12 +2211,13 @@ check_mem_read_rtx (rtx *loc, void *data)
          /* Skip the clobbers.  */
          while (!store_info->is_set)
            store_info = store_info->next;
-         
+
          if (store_info->alias_set == spill_alias_set)
            {
-             if (dump_file)
+             if (dump_file && (dump_flags & TDF_DETAILS))
                dump_insn_info ("removing from active", i_ptr);
 
+             active_local_stores_len--;
              if (last)
                last->next_local_store = i_ptr->next_local_store;
              else
@@ -2133,8 +2234,8 @@ check_mem_read_rtx (rtx *loc, void *data)
         the frame pointer and offset is a constant.  */
       insn_info_t i_ptr = active_local_stores;
       insn_info_t last = NULL;
-      
-      if (dump_file)
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
          if (width == -1)
            fprintf (dump_file, " processing const load gid=%d[BLK]\n",
@@ -2148,35 +2249,35 @@ check_mem_read_rtx (rtx *loc, void *data)
        {
          bool remove = false;
          store_info_t store_info = i_ptr->store_rec;
-         
+
          /* Skip the clobbers.  */
          while (!store_info->is_set)
            store_info = store_info->next;
-         
+
          /* There are three cases here.  */
          if (store_info->group_id < 0)
            /* We have a cselib store followed by a read from a
               const base. */
-           remove 
-             = canon_true_dependence (store_info->mem, 
+           remove
+             = canon_true_dependence (store_info->mem,
                                       GET_MODE (store_info->mem),
                                       store_info->mem_addr,
-                                      mem, mem_addr, rtx_varies_p);
-         
+                                      mem, mem_addr);
+
          else if (group_id == store_info->group_id)
            {
              /* This is a block mode load.  We may get lucky and
                 canon_true_dependence may save the day.  */
              if (width == -1)
-               remove 
-                 = canon_true_dependence (store_info->mem, 
+               remove
+                 = canon_true_dependence (store_info->mem,
                                           GET_MODE (store_info->mem),
                                           store_info->mem_addr,
-                                          mem, mem_addr, rtx_varies_p);
-             
+                                          mem, mem_addr);
+
              /* If this read is just reading back something that we just
                 stored, rewrite the read.  */
-             else 
+             else
                {
                  if (store_info->rhs
                      && offset >= store_info->begin
@@ -2186,26 +2287,27 @@ check_mem_read_rtx (rtx *loc, void *data)
                                                 width)
                      && replace_read (store_info, i_ptr, read_info,
                                       insn_info, loc, bb_info->regs_live))
-                   return 0;
+                   return;
 
                  /* The bases are the same, just see if the offsets
                     overlap.  */
-                 if ((offset < store_info->end) 
+                 if ((offset < store_info->end)
                      && (offset + width > store_info->begin))
                    remove = true;
                }
            }
-         
-         /* else 
+
+         /* else
             The else case that is missing here is that the
             bases are constant but different.  There is nothing
             to do here because there is no overlap.  */
-         
+
          if (remove)
            {
-             if (dump_file)
+             if (dump_file && (dump_flags & TDF_DETAILS))
                dump_insn_info ("removing from active", i_ptr);
 
+             active_local_stores_len--;
              if (last)
                last->next_local_store = i_ptr->next_local_store;
              else
@@ -2216,11 +2318,11 @@ check_mem_read_rtx (rtx *loc, void *data)
          i_ptr = i_ptr->next_local_store;
        }
     }
-  else 
+  else
     {
       insn_info_t i_ptr = active_local_stores;
       insn_info_t last = NULL;
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, " processing cselib load mem:");
          print_inline_rtx (dump_file, mem, 0);
@@ -2231,8 +2333,8 @@ check_mem_read_rtx (rtx *loc, void *data)
        {
          bool remove = false;
          store_info_t store_info = i_ptr->store_rec;
-         
-         if (dump_file)
+
+         if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, " processing cselib load against insn %d\n",
                     INSN_UID (i_ptr->insn));
 
@@ -2252,19 +2354,20 @@ check_mem_read_rtx (rtx *loc, void *data)
                                         offset - store_info->begin, width)
              && replace_read (store_info, i_ptr,  read_info, insn_info, loc,
                               bb_info->regs_live))
-           return 0;
+           return;
 
          if (!store_info->alias_set)
-           remove = canon_true_dependence (store_info->mem, 
+           remove = canon_true_dependence (store_info->mem,
                                            GET_MODE (store_info->mem),
                                            store_info->mem_addr,
-                                           mem, mem_addr, rtx_varies_p);
-         
+                                           mem, mem_addr);
+
          if (remove)
            {
-             if (dump_file)
+             if (dump_file && (dump_flags & TDF_DETAILS))
                dump_insn_info ("removing from active", i_ptr);
-             
+
+             active_local_stores_len--;
              if (last)
                last->next_local_store = i_ptr->next_local_store;
              else
@@ -2275,17 +2378,22 @@ check_mem_read_rtx (rtx *loc, void *data)
          i_ptr = i_ptr->next_local_store;
        }
     }
-  return 0;
 }
 
-/* A for_each_rtx callback in which DATA points the INSN_INFO for 
+/* A note_uses callback in which DATA points the INSN_INFO for
    as check_mem_read_rtx.  Nullify the pointer if i_m_r_m_r returns
    true for any part of *LOC.  */
 
 static void
 check_mem_read_use (rtx *loc, void *data)
 {
-  for_each_rtx (loc, check_mem_read_rtx, data);
+  subrtx_ptr_iterator::array_type array;
+  FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
+    {
+      rtx *loc = *iter;
+      if (MEM_P (*loc))
+       check_mem_read_rtx (loc, (bb_info_t) data);
+    }
 }
 
 
@@ -2295,19 +2403,22 @@ check_mem_read_use (rtx *loc, void *data)
 static bool
 get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
 {
-  CUMULATIVE_ARGS args_so_far;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
   tree arg;
   int idx;
 
-  INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0, 3);
+  INIT_CUMULATIVE_ARGS (args_so_far_v, TREE_TYPE (fn), NULL_RTX, 0, 3);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
 
   arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
   for (idx = 0;
        arg != void_list_node && idx < nargs;
        arg = TREE_CHAIN (arg), idx++)
     {
-      enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
-      rtx reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1), link, tmp;
+      machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
+      rtx reg, link, tmp;
+      reg = targetm.calls.function_arg (args_so_far, mode, NULL_TREE, true);
       if (!reg || !REG_P (reg) || GET_MODE (reg) != mode
          || GET_MODE_CLASS (mode) != MODE_INT)
        return false;
@@ -2336,47 +2447,52 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
        {
          if (!tmp || !CONST_INT_P (tmp))
            return false;
-         tmp = GEN_INT (trunc_int_for_mode (INTVAL (tmp), mode));
+         tmp = gen_int_mode (INTVAL (tmp), mode);
        }
       if (tmp)
        args[idx] = tmp;
 
-      FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
+      targetm.calls.function_arg_advance (args_so_far, mode, NULL_TREE, true);
     }
   if (arg != void_list_node || idx != nargs)
     return false;
   return true;
 }
 
+/* Return a bitmap of the fixed registers contained in IN.  */
+
+static bitmap
+copy_fixed_regs (const_bitmap in)
+{
+  bitmap ret;
+
+  ret = ALLOC_REG_SET (NULL);
+  bitmap_and (ret, in, fixed_reg_set_regset);
+  return ret;
+}
 
 /* Apply record_store to all candidate stores in INSN.  Mark INSN
    if some part of it is not a candidate store and assigns to a
    non-register target.  */
 
 static void
-scan_insn (bb_info_t bb_info, rtx insn)
+scan_insn (bb_info_t bb_info, rtx_insn *insn)
 {
   rtx body;
   insn_info_t insn_info = (insn_info_t) pool_alloc (insn_info_pool);
   int mems_found = 0;
   memset (insn_info, 0, sizeof (struct insn_info));
 
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "\n**scanning insn=%d\n",
             INSN_UID (insn));
 
   insn_info->prev_insn = bb_info->last_insn;
   insn_info->insn = insn;
   bb_info->last_insn = insn_info;
-  
 
-  /* Cselib clears the table for this case, so we have to essentially
-     do the same.  */
-  if (NONJUMP_INSN_P (insn)
-      && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
-      && MEM_VOLATILE_P (PATTERN (insn)))
+  if (DEBUG_INSN_P (insn))
     {
-      add_wild_read (bb_info);
       insn_info->cannot_delete = true;
       return;
     }
@@ -2398,14 +2514,8 @@ scan_insn (bb_info_t bb_info, rtx insn)
       const_call = RTL_CONST_CALL_P (insn);
       if (!const_call)
        {
-         rtx call = PATTERN (insn);
-         if (GET_CODE (call) == PARALLEL)
-           call = XVECEXP (call, 0, 0);
-         if (GET_CODE (call) == SET)
-           call = SET_SRC (call);
-         if (GET_CODE (call) == CALL
-             && MEM_P (XEXP (call, 0))
-             && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+         rtx call = get_call_rtx_from (insn);
+         if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
            {
              rtx symbol = XEXP (XEXP (call, 0), 0);
              if (SYMBOL_REF_DECL (symbol)
@@ -2425,12 +2535,18 @@ scan_insn (bb_info_t bb_info, rtx insn)
          insn_info_t i_ptr = active_local_stores;
          insn_info_t last = NULL;
 
-         if (dump_file)
+         if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "%s call %d\n",
                     const_call ? "const" : "memset", INSN_UID (insn));
 
          /* See the head comment of the frame_read field.  */
-         if (reload_completed)
+         if (reload_completed
+             /* Tail calls are storing their arguments using
+                arg pointer.  If it is a frame pointer on the target,
+                even before reload we need to kill frame pointer based
+                stores.  */
+             || (SIBLING_CALL_P (insn)
+                 && HARD_FRAME_POINTER_IS_ARG_POINTER))
            insn_info->frame_read = true;
 
          /* Loop over the active stores and remove those which are
@@ -2453,16 +2569,16 @@ scan_insn (bb_info_t bb_info, rtx insn)
                    store_info = store_info->next;
 
                  if (store_info->group_id >= 0
-                     && VEC_index (group_info_t, rtx_group_vec,
-                                   store_info->group_id)->frame_related)
+                     && rtx_group_vec[store_info->group_id]->frame_related)
                    remove_store = true;
                }
 
              if (remove_store)
                {
-                 if (dump_file)
+                 if (dump_file && (dump_flags & TDF_DETAILS))
                    dump_insn_info ("removing from active", i_ptr);
-                 
+
+                 active_local_stores_len--;
                  if (last)
                    last->next_local_store = i_ptr->next_local_store;
                  else
@@ -2483,23 +2599,36 @@ scan_insn (bb_info_t bb_info, rtx insn)
                  && INTVAL (args[2]) > 0)
                {
                  rtx mem = gen_rtx_MEM (BLKmode, args[0]);
-                 set_mem_size (mem, args[2]);
+                 set_mem_size (mem, INTVAL (args[2]));
                  body = gen_rtx_SET (VOIDmode, mem, args[1]);
                  mems_found += record_store (body, bb_info);
-                 if (dump_file)
+                 if (dump_file && (dump_flags & TDF_DETAILS))
                    fprintf (dump_file, "handling memset as BLKmode store\n");
                  if (mems_found == 1)
                    {
+                     if (active_local_stores_len++
+                         >= PARAM_VALUE (PARAM_MAX_DSE_ACTIVE_LOCAL_STORES))
+                       {
+                         active_local_stores_len = 1;
+                         active_local_stores = NULL;
+                       }
+                     insn_info->fixed_regs_live
+                       = copy_fixed_regs (bb_info->regs_live);
                      insn_info->next_local_store = active_local_stores;
                      active_local_stores = insn_info;
                    }
                }
            }
        }
-
-      else
-       /* Every other call, including pure functions, may read memory.  */
+      else if (SIBLING_CALL_P (insn) && reload_completed)
+       /* Arguments for a sibling call that are pushed to memory are passed
+          using the incoming argument pointer of the current function.  After
+          reload that might be (and likely is) frame pointer based.  */
        add_wild_read (bb_info);
+      else
+       /* Every other call, including pure functions, may read any memory
+           that is not relative to the frame.  */
+        add_non_frame_wild_read (bb_info);
 
       return;
     }
@@ -2508,11 +2637,11 @@ scan_insn (bb_info_t bb_info, rtx insn)
      them.  */
   if ((GET_CODE (PATTERN (insn)) == CLOBBER)
       || volatile_refs_p (PATTERN (insn))
-      || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+      || (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (insn))
       || (RTX_FRAME_RELATED_P (insn))
       || find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX))
     insn_info->cannot_delete = true;
-  
+
   body = PATTERN (insn);
   if (GET_CODE (body) == PARALLEL)
     {
@@ -2523,8 +2652,8 @@ scan_insn (bb_info_t bb_info, rtx insn)
   else
     mems_found += record_store (body, bb_info);
 
-  if (dump_file)
-    fprintf (dump_file, "mems_found = %d, cannot_delete = %s\n", 
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "mems_found = %d, cannot_delete = %s\n",
             mems_found, insn_info->cannot_delete ? "true" : "false");
 
   /* If we found some sets of mems, add it into the active_local_stores so
@@ -2533,6 +2662,13 @@ scan_insn (bb_info_t bb_info, rtx insn)
      it as cannot delete.  This simplifies the processing later.  */
   if (mems_found == 1)
     {
+      if (active_local_stores_len++
+         >= PARAM_VALUE (PARAM_MAX_DSE_ACTIVE_LOCAL_STORES))
+       {
+         active_local_stores_len = 1;
+         active_local_stores = NULL;
+       }
+      insn_info->fixed_regs_live = copy_fixed_regs (bb_info->regs_live);
       insn_info->next_local_store = active_local_stores;
       active_local_stores = insn_info;
     }
@@ -2560,7 +2696,7 @@ remove_useless_values (cselib_val *base)
         being deleted, then the insn can not be deleted.  */
       while (store_info)
        {
-         if ((store_info->group_id == -1) 
+         if ((store_info->group_id == -1)
              && (store_info->cse_base == base))
            {
              del = true;
@@ -2571,6 +2707,7 @@ remove_useless_values (cselib_val *base)
 
       if (del)
        {
+         active_local_stores_len--;
          if (last)
            last->next_local_store = insn_info->next_local_store;
          else
@@ -2579,7 +2716,7 @@ remove_useless_values (cselib_val *base)
        }
       else
        last = insn_info;
-  
+
       insn_info = insn_info->next_local_store;
     }
 }
@@ -2591,19 +2728,19 @@ static void
 dse_step1 (void)
 {
   basic_block bb;
-  bitmap regs_live = BITMAP_ALLOC (NULL);
-  
-  cselib_init (false);
+  bitmap regs_live = BITMAP_ALLOC (&reg_obstack);
+
+  cselib_init (0);
   all_blocks = BITMAP_ALLOC (NULL);
   bitmap_set_bit (all_blocks, ENTRY_BLOCK);
   bitmap_set_bit (all_blocks, EXIT_BLOCK);
 
-  FOR_ALL_BB (bb)
+  FOR_ALL_BB_FN (bb, cfun)
     {
       insn_info_t ptr;
       bb_info_t bb_info = (bb_info_t) pool_alloc (bb_info_pool);
 
-      memset (bb_info, 0, sizeof (struct bb_info));
+      memset (bb_info, 0, sizeof (struct dse_bb_info));
       bitmap_set_bit (all_blocks, bb->index);
       bb_info->regs_live = regs_live;
 
@@ -2615,14 +2752,15 @@ dse_step1 (void)
 
       if (bb->index >= NUM_FIXED_BLOCKS)
        {
-         rtx insn;
+         rtx_insn *insn;
 
          cse_store_info_pool
-           = create_alloc_pool ("cse_store_info_pool", 
+           = create_alloc_pool ("cse_store_info_pool",
                                 sizeof (struct store_info), 100);
          active_local_stores = NULL;
+         active_local_stores_len = 0;
          cselib_clear_table ();
-         
+
          /* Scan the insns.  */
          FOR_BB_INSNS (bb, insn)
            {
@@ -2632,7 +2770,7 @@ dse_step1 (void)
              if (INSN_P (insn))
                df_simulate_one_insn_forwards (bb, insn, regs_live);
            }
-         
+
          /* This is something of a hack, because the global algorithm
             is supposed to take care of the case where stores go dead
             at the end of the function.  However, the global
@@ -2645,7 +2783,7 @@ dse_step1 (void)
          if (stores_off_frame_dead_at_return
              && (EDGE_COUNT (bb->succs) == 0
                  || (single_succ_p (bb)
-                     && single_succ (bb) == EXIT_BLOCK_PTR
+                     && single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun)
                      && ! crtl->calls_eh_return)))
            {
              insn_info_t i_ptr = active_local_stores;
@@ -2658,11 +2796,11 @@ dse_step1 (void)
                    store_info = store_info->next;
                  if (store_info->alias_set && !i_ptr->cannot_delete)
                    delete_dead_store_insn (i_ptr);
-                 else 
+                 else
                    if (store_info->group_id >= 0)
                      {
-                       group_info_t group 
-                         = VEC_index (group_info_t, rtx_group_vec, store_info->group_id);
+                       group_info_t group
+                         = rtx_group_vec[store_info->group_id];
                        if (group->frame_related && !i_ptr->cannot_delete)
                          delete_dead_store_insn (i_ptr);
                      }
@@ -2700,7 +2838,7 @@ dse_step1 (void)
                      && s_info->redundant_reason->insn
                      && !ptr->cannot_delete)
                    {
-                     if (dump_file)
+                     if (dump_file && (dump_flags & TDF_DETAILS))
                        fprintf (dump_file, "Locally deleting insn %d "
                                            "because insn %d stores the "
                                            "same value and couldn't be "
@@ -2709,8 +2847,6 @@ dse_step1 (void)
                                 INSN_UID (s_info->redundant_reason->insn));
                      delete_dead_store_insn (ptr);
                    }
-                 if (s_info)
-                   s_info->redundant_reason = NULL;
                  free_store_info (ptr);
                }
              else
@@ -2735,7 +2871,7 @@ dse_step1 (void)
 
   BITMAP_FREE (regs_live);
   cselib_finish ();
-  htab_empty (rtx_group_table);
+  rtx_group_table->empty ();
 }
 
 \f
@@ -2753,7 +2889,7 @@ dse_step2_init (void)
   unsigned int i;
   group_info_t group;
 
-  for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
+  FOR_EACH_VEC_ELT (rtx_group_vec, i, group)
     {
       /* For all non stack related bases, we only consider a store to
         be deletable if there are two or more stores for that
@@ -2763,7 +2899,7 @@ dse_step2_init (void)
         for the position.  We do this because the stack related
         stores can be deleted if their is no read between them and
         the end of the function.
-        
+
         To make this work in the current framework, we take the stack
         related bases add all of the bits from store1 into store2.
         This has the effect of making the eligible even if there is
@@ -2773,18 +2909,20 @@ dse_step2_init (void)
        {
          bitmap_ior_into (group->store2_n, group->store1_n);
          bitmap_ior_into (group->store2_p, group->store1_p);
-         if (dump_file)
-           fprintf (dump_file, "group %d is frame related ", i); 
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, "group %d is frame related ", i);
        }
 
       group->offset_map_size_n++;
-      group->offset_map_n = XNEWVEC (int, group->offset_map_size_n);
+      group->offset_map_n = XOBNEWVEC (&dse_obstack, int,
+                                      group->offset_map_size_n);
       group->offset_map_size_p++;
-      group->offset_map_p = XNEWVEC (int, group->offset_map_size_p);
+      group->offset_map_p = XOBNEWVEC (&dse_obstack, int,
+                                      group->offset_map_size_p);
       group->process_globally = false;
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
-         fprintf (dump_file, "group %d(%d+%d): ", i, 
+         fprintf (dump_file, "group %d(%d+%d): ", i,
                   (int)bitmap_count_bits (group->store2_n),
                   (int)bitmap_count_bits (group->store2_p));
          bitmap_print (dump_file, group->store2_n, "n ", " ");
@@ -2804,8 +2942,7 @@ dse_step2_nospill (void)
   /* Position 0 is unused because 0 is used in the maps to mean
      unused.  */
   current_position = 1;
-
-  for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
+  FOR_EACH_VEC_ELT (rtx_group_vec, i, group)
     {
       bitmap_iterator bi;
       unsigned int j;
@@ -2813,19 +2950,23 @@ dse_step2_nospill (void)
       if (group == clear_alias_group)
        continue;
 
-      memset (group->offset_map_n, 0, sizeof(int) * group->offset_map_size_n);
-      memset (group->offset_map_p, 0, sizeof(int) * group->offset_map_size_p);
+      memset (group->offset_map_n, 0, sizeof (int) * group->offset_map_size_n);
+      memset (group->offset_map_p, 0, sizeof (int) * group->offset_map_size_p);
       bitmap_clear (group->group_kill);
 
       EXECUTE_IF_SET_IN_BITMAP (group->store2_n, 0, j, bi)
        {
          bitmap_set_bit (group->group_kill, current_position);
+          if (bitmap_bit_p (group->escaped_n, j))
+           bitmap_set_bit (kill_on_calls, current_position);
          group->offset_map_n[j] = current_position++;
          group->process_globally = true;
        }
       EXECUTE_IF_SET_IN_BITMAP (group->store2_p, 0, j, bi)
        {
-         bitmap_set_bit (group->group_kill, current_position); 
+         bitmap_set_bit (group->group_kill, current_position);
+          if (bitmap_bit_p (group->escaped_p, j))
+           bitmap_set_bit (kill_on_calls, current_position);
          group->offset_map_p[j] = current_position++;
          group->process_globally = true;
        }
@@ -2834,134 +2975,14 @@ dse_step2_nospill (void)
 }
 
 
-/* Init the offset tables for the spill case.  */
-
-static bool
-dse_step2_spill (void)
-{
-  unsigned int j;
-  group_info_t group = clear_alias_group;
-  bitmap_iterator bi;
-
-  /* Position 0 is unused because 0 is used in the maps to mean
-     unused.  */
-  current_position = 1;
-
-  if (dump_file)
-    {
-      bitmap_print (dump_file, clear_alias_sets, 
-                   "clear alias sets              ", "\n");
-      bitmap_print (dump_file, disqualified_clear_alias_sets, 
-                   "disqualified clear alias sets ", "\n");
-    }
-
-  memset (group->offset_map_n, 0, sizeof(int) * group->offset_map_size_n);
-  memset (group->offset_map_p, 0, sizeof(int) * group->offset_map_size_p);
-  bitmap_clear (group->group_kill);
-  
-  /* Remove the disqualified positions from the store2_p set.  */
-  bitmap_and_compl_into (group->store2_p, disqualified_clear_alias_sets);
-  
-  /* We do not need to process the store2_n set because
-     alias_sets are always positive.  */
-  EXECUTE_IF_SET_IN_BITMAP (group->store2_p, 0, j, bi)
-    {
-      bitmap_set_bit (group->group_kill, current_position); 
-      group->offset_map_p[j] = current_position++;
-      group->process_globally = true;
-    }
-
-  return current_position != 1;
-}
-
-
 \f
 /*----------------------------------------------------------------------------
   Third step.
-  
+
   Build the bit vectors for the transfer functions.
 ----------------------------------------------------------------------------*/
 
 
-/* Note that this is NOT a general purpose function.  Any mem that has
-   an alias set registered here expected to be COMPLETELY unaliased:
-   i.e it's addresses are not and need not be examined.  
-
-   It is known that all references to this address will have this
-   alias set and there are NO other references to this address in the
-   function.  
-
-   Currently the only place that is known to be clean enough to use
-   this interface is the code that assigns the spill locations.  
-
-   All of the mems that have alias_sets registered are subjected to a
-   very powerful form of dse where function calls, volatile reads and
-   writes, and reads from random location are not taken into account.  
-
-   It is also assumed that these locations go dead when the function
-   returns.  This assumption could be relaxed if there were found to
-   be places that this assumption was not correct.
-
-   The MODE is passed in and saved.  The mode of each load or store to
-   a mem with ALIAS_SET is checked against MEM.  If the size of that
-   load or store is different from MODE, processing is halted on this
-   alias set.  For the vast majority of aliases sets, all of the loads
-   and stores will use the same mode.  But vectors are treated
-   differently: the alias set is established for the entire vector,
-   but reload will insert loads and stores for individual elements and
-   we do not necessarily have the information to track those separate
-   elements.  So when we see a mode mismatch, we just bail.  */
-
-
-void 
-dse_record_singleton_alias_set (alias_set_type alias_set, 
-                               enum machine_mode mode)
-{
-  struct clear_alias_mode_holder tmp_holder;
-  struct clear_alias_mode_holder *entry;
-  void **slot;
-
-  /* If we are not going to run dse, we need to return now or there
-     will be problems with allocating the bitmaps.  */
-  if ((!gate_dse()) || !alias_set)
-    return;
-
-  if (!clear_alias_sets)
-    {
-      clear_alias_sets = BITMAP_ALLOC (NULL);
-      disqualified_clear_alias_sets = BITMAP_ALLOC (NULL);
-      clear_alias_mode_table = htab_create (11, clear_alias_mode_hash,
-                                           clear_alias_mode_eq, NULL);
-      clear_alias_mode_pool = create_alloc_pool ("clear_alias_mode_pool", 
-                                                sizeof (struct clear_alias_mode_holder), 100);
-    }
-
-  bitmap_set_bit (clear_alias_sets, alias_set);
-
-  tmp_holder.alias_set = alias_set;
-
-  slot = htab_find_slot (clear_alias_mode_table, &tmp_holder, INSERT);
-  gcc_assert (*slot == NULL);
-
-  *slot = entry =
-    (struct clear_alias_mode_holder *) pool_alloc (clear_alias_mode_pool);
-  entry->alias_set = alias_set;
-  entry->mode = mode;
-}
-
-
-/* Remove ALIAS_SET from the sets of stack slots being considered.  */
-
-void 
-dse_invalidate_singleton_alias_set (alias_set_type alias_set)
-{
-  if ((!gate_dse()) || !alias_set)
-    return;
-
-  bitmap_clear_bit (clear_alias_sets, alias_set);
-}
-
-
 /* Look up the bitmap index for OFFSET in GROUP_INFO.  If it is not
    there, return 0.  */
 
@@ -2987,14 +3008,14 @@ get_bitmap_index (group_info_t group_info, HOST_WIDE_INT offset)
 /* Process the STORE_INFOs into the bitmaps into GEN and KILL.  KILL
    may be NULL. */
 
-static void 
+static void
 scan_stores_nospill (store_info_t store_info, bitmap gen, bitmap kill)
 {
   while (store_info)
     {
       HOST_WIDE_INT i;
-      group_info_t group_info 
-       = VEC_index (group_info_t, rtx_group_vec, store_info->group_id);
+      group_info_t group_info
+       = rtx_group_vec[store_info->group_id];
       if (group_info->process_globally)
        for (i = store_info->begin; i < store_info->end; i++)
          {
@@ -3014,14 +3035,14 @@ scan_stores_nospill (store_info_t store_info, bitmap gen, bitmap kill)
 /* Process the STORE_INFOs into the bitmaps into GEN and KILL.  KILL
    may be NULL. */
 
-static void 
+static void
 scan_stores_spill (store_info_t store_info, bitmap gen, bitmap kill)
 {
   while (store_info)
     {
       if (store_info->alias_set)
        {
-         int index = get_bitmap_index (clear_alias_group, 
+         int index = get_bitmap_index (clear_alias_group,
                                        store_info->alias_set);
          if (index != 0)
            {
@@ -3048,18 +3069,32 @@ scan_reads_nospill (insn_info_t insn_info, bitmap gen, bitmap kill)
   /* If this insn reads the frame, kill all the frame related stores.  */
   if (insn_info->frame_read)
     {
-      for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
+      FOR_EACH_VEC_ELT (rtx_group_vec, i, group)
        if (group->process_globally && group->frame_related)
          {
            if (kill)
              bitmap_ior_into (kill, group->group_kill);
-           bitmap_and_compl_into (gen, group->group_kill); 
+           bitmap_and_compl_into (gen, group->group_kill);
+         }
+    }
+  if (insn_info->non_frame_wild_read)
+    {
+      /* Kill all non-frame related stores.  Kill all stores of variables that
+         escape.  */
+      if (kill)
+        bitmap_ior_into (kill, kill_on_calls);
+      bitmap_and_compl_into (gen, kill_on_calls);
+      FOR_EACH_VEC_ELT (rtx_group_vec, i, group)
+       if (group->process_globally && !group->frame_related)
+         {
+           if (kill)
+             bitmap_ior_into (kill, group->group_kill);
+           bitmap_and_compl_into (gen, group->group_kill);
          }
     }
-
   while (read_info)
     {
-      for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
+      FOR_EACH_VEC_ELT (rtx_group_vec, i, group)
        {
          if (group->process_globally)
            {
@@ -3098,11 +3133,10 @@ scan_reads_nospill (insn_info_t insn_info, bitmap gen, bitmap kill)
                     something else with a different constant
                     base.  */
                  if ((read_info->group_id < 0)
-                     && canon_true_dependence (group->base_mem, 
-                                               QImode,
+                     && canon_true_dependence (group->base_mem,
+                                               GET_MODE (group->base_mem),
                                                group->canon_base_addr,
-                                               read_info->mem, NULL_RTX,
-                                               rtx_varies_p))
+                                               read_info->mem, NULL_RTX))
                    {
                      if (kill)
                        bitmap_ior_into (kill, group->group_kill);
@@ -3111,7 +3145,7 @@ scan_reads_nospill (insn_info_t insn_info, bitmap gen, bitmap kill)
                }
            }
        }
-      
+
       read_info = read_info->next;
     }
 }
@@ -3126,7 +3160,7 @@ scan_reads_spill (read_info_t read_info, bitmap gen, bitmap kill)
     {
       if (read_info->alias_set)
        {
-         int index = get_bitmap_index (clear_alias_group, 
+         int index = get_bitmap_index (clear_alias_group,
                                        read_info->alias_set);
          if (index != 0)
            {
@@ -3135,7 +3169,7 @@ scan_reads_spill (read_info_t read_info, bitmap gen, bitmap kill)
              bitmap_clear_bit (gen, index);
            }
        }
-      
+
       read_info = read_info->next;
     }
 }
@@ -3188,7 +3222,7 @@ dse_step3_scan (bool for_spills, basic_block bb)
     insn_info = bb_info->last_insn;
   else
     insn_info = find_insn_before_first_wild_read (bb_info);
-    
+
   /* In the spill case or in the no_spill case if there is no wild
      read in the block, we will need a kill set.  */
   if (insn_info == bb_info->last_insn)
@@ -3196,9 +3230,9 @@ dse_step3_scan (bool for_spills, basic_block bb)
       if (bb_info->kill)
        bitmap_clear (bb_info->kill);
       else
-       bb_info->kill = BITMAP_ALLOC (NULL);
+       bb_info->kill = BITMAP_ALLOC (&dse_bitmap_obstack);
     }
-  else 
+  else
     if (bb_info->kill)
       BITMAP_FREE (bb_info->kill);
 
@@ -3208,7 +3242,7 @@ dse_step3_scan (bool for_spills, basic_block bb)
         this phase.  */
       if (insn_info->insn && INSN_P (insn_info->insn))
        {
-         /* Process the read(s) last.  */ 
+         /* Process the read(s) last.  */
          if (for_spills)
            {
              scan_stores_spill (insn_info->store_rec, bb_info->gen, bb_info->kill);
@@ -3219,7 +3253,7 @@ dse_step3_scan (bool for_spills, basic_block bb)
              scan_stores_nospill (insn_info->store_rec, bb_info->gen, bb_info->kill);
              scan_reads_nospill (insn_info, bb_info->gen, bb_info->kill);
            }
-       }         
+       }
 
       insn_info = insn_info->prev_insn;
     }
@@ -3234,13 +3268,13 @@ dse_step3_exit_block_scan (bb_info_t bb_info)
 {
   /* The gen set is all 0's for the exit block except for the
      frame_pointer_group.  */
-  
+
   if (stores_off_frame_dead_at_return)
     {
       unsigned int i;
       group_info_t group;
-      
-      for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
+
+      FOR_EACH_VEC_ELT (rtx_group_vec, i, group)
        {
          if (group->process_globally && group->frame_related)
            bitmap_ior_into (bb_info->gen, group->group_kill);
@@ -3260,13 +3294,13 @@ mark_reachable_blocks (sbitmap unreachable_blocks, basic_block bb)
   edge e;
   edge_iterator ei;
 
-  if (TEST_BIT (unreachable_blocks, bb->index))
+  if (bitmap_bit_p (unreachable_blocks, bb->index))
     {
-      RESET_BIT (unreachable_blocks, bb->index);
+      bitmap_clear_bit (unreachable_blocks, bb->index);
       FOR_EACH_EDGE (e, ei, bb->preds)
-       {                                                               
+       {
          mark_reachable_blocks (unreachable_blocks, e->src);
-       }                                                               
+       }
     }
 }
 
@@ -3276,20 +3310,20 @@ static void
 dse_step3 (bool for_spills)
 {
   basic_block bb;
-  sbitmap unreachable_blocks = sbitmap_alloc (last_basic_block);
+  sbitmap unreachable_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
   sbitmap_iterator sbi;
   bitmap all_ones = NULL;
   unsigned int i;
-  
-  sbitmap_ones (unreachable_blocks);
 
-  FOR_ALL_BB (bb)
+  bitmap_ones (unreachable_blocks);
+
+  FOR_ALL_BB_FN (bb, cfun)
     {
       bb_info_t bb_info = bb_table[bb->index];
       if (bb_info->gen)
        bitmap_clear (bb_info->gen);
       else
-       bb_info->gen = BITMAP_ALLOC (NULL);
+       bb_info->gen = BITMAP_ALLOC (&dse_bitmap_obstack);
 
       if (bb->index == ENTRY_BLOCK)
        ;
@@ -3311,7 +3345,7 @@ dse_step3 (bool for_spills)
   /* For any block in an infinite loop, we must initialize the out set
      to all ones.  This could be expensive, but almost never occurs in
      practice. However, it is common in regression tests.  */
-  EXECUTE_IF_SET_IN_SBITMAP (unreachable_blocks, 0, i, sbi)
+  EXECUTE_IF_SET_IN_BITMAP (unreachable_blocks, 0, i, sbi)
     {
       if (bitmap_bit_p (all_blocks, i))
        {
@@ -3321,13 +3355,13 @@ dse_step3 (bool for_spills)
              unsigned int j;
              group_info_t group;
 
-             all_ones = BITMAP_ALLOC (NULL);
-             for (j = 0; VEC_iterate (group_info_t, rtx_group_vec, j, group); j++)
+             all_ones = BITMAP_ALLOC (&dse_bitmap_obstack);
+             FOR_EACH_VEC_ELT (rtx_group_vec, j, group)
                bitmap_ior_into (all_ones, group->group_kill);
            }
          if (!bb_info->out)
            {
-             bb_info->out = BITMAP_ALLOC (NULL);
+             bb_info->out = BITMAP_ALLOC (&dse_bitmap_obstack);
              bitmap_copy (bb_info->out, all_ones);
            }
        }
@@ -3363,7 +3397,7 @@ dse_confluence_0 (basic_block bb)
 
   if (!bb_info->out)
     {
-      bb_info->out = BITMAP_ALLOC (NULL);
+      bb_info->out = BITMAP_ALLOC (&dse_bitmap_obstack);
       bitmap_copy (bb_info->out, bb_table[EXIT_BLOCK]->gen);
     }
 }
@@ -3372,7 +3406,7 @@ dse_confluence_0 (basic_block bb)
    out set of the src of E.  If the various in or out sets are not
    there, that means they are all ones.  */
 
-static void
+static bool
 dse_confluence_n (edge e)
 {
   bb_info_t src_info = bb_table[e->src->index];
@@ -3384,15 +3418,16 @@ dse_confluence_n (edge e)
        bitmap_and_into (src_info->out, dest_info->in);
       else
        {
-         src_info->out = BITMAP_ALLOC (NULL);
+         src_info->out = BITMAP_ALLOC (&dse_bitmap_obstack);
          bitmap_copy (src_info->out, dest_info->in);
        }
     }
+  return true;
 }
 
 
 /* Propagate the info from the out to the in set of BB_INDEX's basic
-   block.  There are three cases:  
+   block.  There are three cases:
 
    1) The block has no kill set.  In this case the kill set is all
    ones.  It does not matter what the out set of the block is, none of
@@ -3418,12 +3453,12 @@ dse_transfer_function (int bb_index)
        {
          /* Case 3 above.  */
          if (bb_info->in)
-           return bitmap_ior_and_compl (bb_info->in, bb_info->gen, 
+           return bitmap_ior_and_compl (bb_info->in, bb_info->gen,
                                         bb_info->out, bb_info->kill);
          else
            {
-             bb_info->in = BITMAP_ALLOC (NULL);
-             bitmap_ior_and_compl (bb_info->in, bb_info->gen, 
+             bb_info->in = BITMAP_ALLOC (&dse_bitmap_obstack);
+             bitmap_ior_and_compl (bb_info->in, bb_info->gen,
                                    bb_info->out, bb_info->kill);
              return true;
            }
@@ -3440,7 +3475,7 @@ dse_transfer_function (int bb_index)
        return false;
       else
        {
-         bb_info->in = BITMAP_ALLOC (NULL);
+         bb_info->in = BITMAP_ALLOC (&dse_bitmap_obstack);
          bitmap_copy (bb_info->in, bb_info->gen);
          return true;
        }
@@ -3452,16 +3487,16 @@ dse_transfer_function (int bb_index)
 static void
 dse_step4 (void)
 {
-  df_simple_dataflow (DF_BACKWARD, NULL, dse_confluence_0, 
-                     dse_confluence_n, dse_transfer_function, 
-                     all_blocks, df_get_postorder (DF_BACKWARD), 
+  df_simple_dataflow (DF_BACKWARD, NULL, dse_confluence_0,
+                     dse_confluence_n, dse_transfer_function,
+                     all_blocks, df_get_postorder (DF_BACKWARD),
                      df_get_n_blocks (DF_BACKWARD));
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
       basic_block bb;
 
       fprintf (dump_file, "\n\n*** Global dataflow info after analysis.\n");
-      FOR_ALL_BB (bb)
+      FOR_ALL_BB_FN (bb, cfun)
        {
          bb_info_t bb_info = bb_table[bb->index];
 
@@ -3499,7 +3534,7 @@ static void
 dse_step5_nospill (void)
 {
   basic_block bb;
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       bb_info_t bb_info = bb_table[bb->index];
       insn_info_t insn_info = bb_info->last_insn;
@@ -3517,7 +3552,7 @@ dse_step5_nospill (void)
 
          /* There may have been code deleted by the dce pass run before
             this phase.  */
-         if (insn_info->insn 
+         if (insn_info->insn
              && INSN_P (insn_info->insn)
              && (!insn_info->cannot_delete)
              && (!bitmap_empty_p (v)))
@@ -3526,7 +3561,7 @@ dse_step5_nospill (void)
 
              /* Try to delete the current insn.  */
              deleted = true;
-             
+
              /* Skip the clobbers.  */
              while (!store_info->is_set)
                store_info = store_info->next;
@@ -3536,19 +3571,19 @@ dse_step5_nospill (void)
              else
                {
                  HOST_WIDE_INT i;
-                 group_info_t group_info 
-                   = VEC_index (group_info_t, rtx_group_vec, store_info->group_id);
-                 
+                 group_info_t group_info
+                   = rtx_group_vec[store_info->group_id];
+
                  for (i = store_info->begin; i < store_info->end; i++)
                    {
                      int index = get_bitmap_index (group_info, i);
-                     
-                     if (dump_file)
-                       fprintf (dump_file, "i = %d, index = %d\n", (int)i, index); 
+
+                     if (dump_file && (dump_flags & TDF_DETAILS))
+                       fprintf (dump_file, "i = %d, index = %d\n", (int)i, index);
                      if (index == 0 || !bitmap_bit_p (v, index))
                        {
-                         if (dump_file)
-                           fprintf (dump_file, "failing at i = %d\n", (int)i); 
+                         if (dump_file && (dump_flags & TDF_DETAILS))
+                           fprintf (dump_file, "failing at i = %d\n", (int)i);
                          deleted = false;
                          break;
                        }
@@ -3556,9 +3591,9 @@ dse_step5_nospill (void)
                }
              if (deleted)
                {
-                 if (dbg_cnt (dse))
+                 if (dbg_cnt (dse)
+                     && check_for_inc_dec_1 (insn_info))
                    {
-                     check_for_inc_dec (insn_info->insn);
                      delete_insn (insn_info->insn);
                      insn_info->insn = NULL;
                      globally_deleted++;
@@ -3568,91 +3603,28 @@ dse_step5_nospill (void)
          /* We do want to process the local info if the insn was
             deleted.  For instance, if the insn did a wild read, we
             no longer need to trash the info.  */
-         if (insn_info->insn 
+         if (insn_info->insn
              && INSN_P (insn_info->insn)
              && (!deleted))
            {
              scan_stores_nospill (insn_info->store_rec, v, NULL);
              if (insn_info->wild_read)
                {
-                 if (dump_file)
+                 if (dump_file && (dump_flags & TDF_DETAILS))
                    fprintf (dump_file, "wild read\n");
                  bitmap_clear (v);
                }
-             else if (insn_info->read_rec)
+             else if (insn_info->read_rec
+                       || insn_info->non_frame_wild_read)
                {
-                 if (dump_file)
+                 if (dump_file && !insn_info->non_frame_wild_read)
                    fprintf (dump_file, "regular read\n");
+                  else if (dump_file && (dump_flags & TDF_DETAILS))
+                   fprintf (dump_file, "non-frame wild read\n");
                  scan_reads_nospill (insn_info, v, NULL);
                }
            }
-             
-         insn_info = insn_info->prev_insn;
-       }
-    }
-}
 
-
-static void
-dse_step5_spill (void)
-{
-  basic_block bb;
-  FOR_EACH_BB (bb)
-    {
-      bb_info_t bb_info = bb_table[bb->index];
-      insn_info_t insn_info = bb_info->last_insn;
-      bitmap v = bb_info->out;
-
-      while (insn_info)
-       {
-         bool deleted = false;
-         /* There may have been code deleted by the dce pass run before
-            this phase.  */
-         if (insn_info->insn 
-             && INSN_P (insn_info->insn)
-             && (!insn_info->cannot_delete)
-             && (!bitmap_empty_p (v)))
-           {
-             /* Try to delete the current insn.  */
-             store_info_t store_info = insn_info->store_rec;
-             deleted = true;
-             
-             while (store_info)
-               {
-                 if (store_info->alias_set)
-                   {
-                     int index = get_bitmap_index (clear_alias_group, 
-                                                   store_info->alias_set);
-                     if (index == 0 || !bitmap_bit_p (v, index))
-                       {
-                         deleted = false;
-                         break;
-                       }
-                   }
-                 else 
-                   deleted = false;
-                 store_info = store_info->next;
-               }
-             if (deleted && dbg_cnt (dse))
-               {
-                 if (dump_file)
-                   fprintf (dump_file, "Spill deleting insn %d\n", 
-                            INSN_UID (insn_info->insn));
-                 check_for_inc_dec (insn_info->insn);
-                 delete_insn (insn_info->insn);
-                 spill_deleted++;
-                 insn_info->insn = NULL;
-               }
-           }
-         
-         if (insn_info->insn 
-             && INSN_P (insn_info->insn)
-             && (!deleted))
-           {
-             scan_stores_spill (insn_info->store_rec, v, NULL);
-             scan_reads_spill (insn_info->read_rec, v, NULL);
-           }
-             
          insn_info = insn_info->prev_insn;
        }
     }
@@ -3672,7 +3644,7 @@ dse_step6 (void)
 {
   basic_block bb;
 
-  FOR_ALL_BB (bb)
+  FOR_ALL_BB_FN (bb, cfun)
     {
       bb_info_t bb_info = bb_table[bb->index];
       insn_info_t insn_info = bb_info->last_insn;
@@ -3694,8 +3666,8 @@ dse_step6 (void)
                  && s_info->redundant_reason->insn
                  && INSN_P (s_info->redundant_reason->insn))
                {
-                 rtx rinsn = s_info->redundant_reason->insn;
-                 if (dump_file)
+                 rtx_insn *rinsn = s_info->redundant_reason->insn;
+                 if (dump_file && (dump_flags & TDF_DETAILS))
                    fprintf (dump_file, "Locally deleting insn %d "
                                        "because insn %d stores the "
                                        "same value and couldn't be "
@@ -3713,52 +3685,20 @@ dse_step6 (void)
 /*----------------------------------------------------------------------------
    Seventh step.
 
-   Destroy everything left standing. 
+   Destroy everything left standing.
 ----------------------------------------------------------------------------*/
 
-static void 
-dse_step7 (bool global_done)
+static void
+dse_step7 (void)
 {
-  unsigned int i;
-  group_info_t group;
-  basic_block bb;
-  
-  for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
-    {
-      free (group->offset_map_n);
-      free (group->offset_map_p);
-      BITMAP_FREE (group->store1_n);
-      BITMAP_FREE (group->store1_p);
-      BITMAP_FREE (group->store2_n);
-      BITMAP_FREE (group->store2_p);
-      BITMAP_FREE (group->group_kill);
-    }
-
-  if (global_done)
-    FOR_ALL_BB (bb)
-      {
-       bb_info_t bb_info = bb_table[bb->index];
-       BITMAP_FREE (bb_info->gen);
-       if (bb_info->kill)
-         BITMAP_FREE (bb_info->kill);
-       if (bb_info->in)
-         BITMAP_FREE (bb_info->in);
-       if (bb_info->out)
-         BITMAP_FREE (bb_info->out);
-      }
-
-  if (clear_alias_sets)
-    {
-      BITMAP_FREE (clear_alias_sets);
-      BITMAP_FREE (disqualified_clear_alias_sets);
-      free_alloc_pool (clear_alias_mode_pool);
-      htab_delete (clear_alias_mode_table);
-    }
+  bitmap_obstack_release (&dse_bitmap_obstack);
+  obstack_free (&dse_obstack, NULL);
 
   end_alias_analysis ();
   free (bb_table);
-  htab_delete (rtx_group_table);
-  VEC_free (group_info_t, heap, rtx_group_vec);
+  delete rtx_group_table;
+  rtx_group_table = NULL;
+  rtx_group_vec.release ();
   BITMAP_FREE (all_blocks);
   BITMAP_FREE (scratch);
 
@@ -3780,8 +3720,6 @@ dse_step7 (bool global_done)
 static unsigned int
 rest_of_handle_dse (void)
 {
-  bool did_global = false;
-
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
   /* Need the notes since we must track live hardregs in the forwards
@@ -3796,101 +3734,106 @@ rest_of_handle_dse (void)
     {
       df_set_flags (DF_LR_RUN_DCE);
       df_analyze ();
-      did_global = true;
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "doing global processing\n");
       dse_step3 (false);
       dse_step4 ();
       dse_step5_nospill ();
     }
 
-  /* For the instance of dse that runs after reload, we make a special
-     pass to process the spills.  These are special in that they are
-     totally transparent, i.e, there is no aliasing issues that need
-     to be considered.  This means that the wild reads that kill
-     everything else do not apply here.  */ 
-  if (clear_alias_sets && dse_step2_spill ())
-    {
-      if (!did_global)
-       {
-         df_set_flags (DF_LR_RUN_DCE);
-         df_analyze ();
-       }
-      did_global = true;
-      if (dump_file)
-       fprintf (dump_file, "doing global spill processing\n");
-      dse_step3 (true);
-      dse_step4 ();
-      dse_step5_spill ();
-    }
-
   dse_step6 ();
-  dse_step7 (did_global);
+  dse_step7 ();
 
   if (dump_file)
     fprintf (dump_file, "dse: local deletions = %d, global deletions = %d, spill deletions = %d\n",
             locally_deleted, globally_deleted, spill_deleted);
+
+  /* DSE can eliminate potentially-trapping MEMs.
+     Remove any EH edges associated with them.  */
+  if ((locally_deleted || globally_deleted)
+      && cfun->can_throw_non_call_exceptions
+      && purge_all_dead_edges ())
+    cleanup_cfg (0);
+
   return 0;
 }
 
-static bool
-gate_dse (void)
+namespace {
+
+const pass_data pass_data_rtl_dse1 =
 {
-  return gate_dse1 () || gate_dse2 ();
-}
+  RTL_PASS, /* type */
+  "dse1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_DSE1, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
+};
 
-static bool
-gate_dse1 (void)
+class pass_rtl_dse1 : public rtl_opt_pass
 {
-  return optimize > 0 && flag_dse
-    && dbg_cnt (dse1);
-}
+public:
+  pass_rtl_dse1 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_rtl_dse1, ctxt)
+  {}
 
-static bool
-gate_dse2 (void)
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return optimize > 0 && flag_dse && dbg_cnt (dse1);
+    }
+
+  virtual unsigned int execute (function *) { return rest_of_handle_dse (); }
+
+}; // class pass_rtl_dse1
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_dse1 (gcc::context *ctxt)
 {
-  return optimize > 0 && flag_dse
-    && dbg_cnt (dse2);
+  return new pass_rtl_dse1 (ctxt);
 }
 
-struct rtl_opt_pass pass_rtl_dse1 =
-{
- {
-  RTL_PASS,
-  "dse1",                               /* name */
-  gate_dse1,                            /* gate */
-  rest_of_handle_dse,                   /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_DSE1,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_dump_func |
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect                      /* todo_flags_finish */
- }
-};
+namespace {
 
-struct rtl_opt_pass pass_rtl_dse2 =
-{
- {
-  RTL_PASS,
-  "dse2",                               /* name */
-  gate_dse2,                            /* gate */
-  rest_of_handle_dse,                   /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_DSE2,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_dump_func |
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect                      /* todo_flags_finish */
- }
+const pass_data pass_data_rtl_dse2 =
+{
+  RTL_PASS, /* type */
+  "dse2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_DSE2, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
 };
+
+class pass_rtl_dse2 : public rtl_opt_pass
+{
+public:
+  pass_rtl_dse2 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_rtl_dse2, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return optimize > 0 && flag_dse && dbg_cnt (dse2);
+    }
+
+  virtual unsigned int execute (function *) { return rest_of_handle_dse (); }
+
+}; // class pass_rtl_dse2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_dse2 (gcc::context *ctxt)
+{
+  return new pass_rtl_dse2 (ctxt);
+}