OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / dse.c
index 1f7588d..0a3ebb4 100644 (file)
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -1,5 +1,5 @@
 /* RTL dead store elimination.
-   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    Contributed by Richard Sandiford <rsandifor@codesourcery.com>
    and Kenneth Zadeck <zadeck@naturalbridge.com>
@@ -8,7 +8,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -17,9 +17,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #undef BASELINE
 
@@ -30,6 +29,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
@@ -43,6 +43,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "expr.h"
 #include "recog.h"
 #include "dse.h"
+#include "optabs.h"
 #include "dbgcnt.h"
 
 /* This file contains three techniques for performing Dead Store
@@ -219,7 +220,7 @@ struct store_info
   rtx mem_addr;
 
   /* If this is non-zero, it is the alias set of a spill location.  */
-  HOST_WIDE_INT alias_set;
+  alias_set_type alias_set;
 
   /* The offset of the first and byte before the last byte associated
      with the operation.  */
@@ -228,7 +229,7 @@ struct store_info
   /* An bitmask as wide as the number of bytes in the word that
      contains a 1 if the byte may be needed.  The store is unused if
      all of the bits are 0.  */
-  long positions_needed;
+  unsigned HOST_WIDE_INT positions_needed;
 
   /* The next store info for this insn.  */
   struct store_info *next;
@@ -239,6 +240,15 @@ struct store_info
   rtx rhs;  
 };
 
+/* Return a bitmask with the first N low bits set.  */
+
+static unsigned HOST_WIDE_INT
+lowpart_bitmask (int n)
+{
+  unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT) 0;
+  return mask >> (HOST_BITS_PER_WIDE_INT - n);
+}
+
 typedef struct store_info *store_info_t;
 static alloc_pool cse_store_info_pool;
 static alloc_pool rtx_store_info_pool;
@@ -251,7 +261,7 @@ struct read_info
   int group_id;
 
   /* If this is non-zero, it is the alias set of a spill location.  */
-  HOST_WIDE_INT alias_set;
+  alias_set_type alias_set;
 
   /* The offset of the first and byte after the last byte associated
      with the operation.  If begin == end == 0, the read did not have
@@ -284,12 +294,29 @@ struct insn_info
      contains a wild read, the use_rec will be null.  */
   bool wild_read;
 
-  /* This field is set for const function calls.  Const functions
-     cannot read memory, but they can read the stack because that is
-     where they may get their parms.  So having this set is less
-     severe than a wild read, it just means that all of the stores to
-     the stack are killed rather than all stores.  */
-  bool stack_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
+     this conservative because, like the store motion pass, we don't
+     consider CALL_INSN_FUNCTION_USAGE when processing call insns.
+     Moreover, we need to distinguish two cases:
+     1. Before reload (register elimination), the stores related to
+       outgoing arguments are stack pointer based and thus deemed
+       of non-constant base in this pass.  This requires special
+       handling but also means that the frame pointer based stores
+       need not be killed upon encountering a const function call.
+     2. After reload, the stores related to outgoing arguments can be
+       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.  */
+  bool frame_read;
+
+  /* This field is only used for the processing of const functions.
+     It is set if the insn may contain a stack pointer based store.  */
+  bool stack_pointer_based;
 
   /* This is true if any of the sets within the store contains a
      cselib base.  Such stores can only be deleted by the local
@@ -318,7 +345,7 @@ struct insn_info
   /* The linked list of insns that are in consideration for removal in
      the forwards pass thru 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 traveral starts
+     time it is guaranteed to be correct is when the traversal starts
      at active_local_stores.  */
   struct insn_info * next_local_store;
 };
@@ -441,6 +468,7 @@ struct group_info
   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.  */
@@ -497,17 +525,14 @@ static htab_t clear_alias_mode_table;
 /* Hash table element to look up the mode for an alias set.  */
 struct clear_alias_mode_holder
 {
-  HOST_WIDE_INT alias_set;
+  alias_set_type alias_set;
   enum machine_mode mode;
 };
 
 static alloc_pool clear_alias_mode_pool;
 
-/* This is true except for two cases:
-   (1) current_function_stdarg -- i.e. we cannot do this 
-       for vararg functions because they play games with the frame.  
-   (2) In ada, it is sometimes not safe to do assume that any stores
-       based off the stack frame go dead at the exit to a function.  */
+/* 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.  */
@@ -522,6 +547,8 @@ static unsigned int current_position;
 
 
 static bool gate_dse (void);
+static bool gate_dse1 (void);
+static bool gate_dse2 (void);
 
 \f
 /*----------------------------------------------------------------------------
@@ -556,7 +583,7 @@ clear_alias_mode_hash (const void *p)
 /* Find the entry associated with ALIAS_SET.  */
 
 static struct clear_alias_mode_holder *
-clear_alias_set_lookup (HOST_WIDE_INT alias_set)
+clear_alias_set_lookup (alias_set_type alias_set)
 {
   struct clear_alias_mode_holder tmp_holder;
   void **slot;
@@ -565,7 +592,7 @@ clear_alias_set_lookup (HOST_WIDE_INT alias_set)
   slot = htab_find_slot (clear_alias_mode_table, &tmp_holder, NO_INSERT);
   gcc_assert (*slot);
   
-  return *slot;
+  return (struct clear_alias_mode_holder *) *slot;
 }
 
 
@@ -575,8 +602,8 @@ clear_alias_set_lookup (HOST_WIDE_INT alias_set)
 static int
 invariant_group_base_eq (const void *p1, const void *p2)
 {
-  const group_info_t gi1 = (const group_info_t) p1;
-  const group_info_t gi2 = (const group_info_t) p2;
+  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);
 }
 
@@ -584,7 +611,7 @@ invariant_group_base_eq (const void *p1, const void *p2)
 static hashval_t
 invariant_group_base_hash (const void *p)
 {
-  const group_info_t gi = (const group_info_t) p;
+  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);
 }
@@ -611,7 +638,8 @@ get_group_info (rtx base)
     {
       if (!clear_alias_group)
        {
-         clear_alias_group = gi = pool_alloc (rtx_group_info_pool);
+         clear_alias_group = gi =
+           (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);
@@ -631,7 +659,7 @@ get_group_info (rtx base)
 
   if (gi == NULL)
     {
-      *slot = gi = pool_alloc (rtx_group_info_pool);
+      *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);
@@ -691,10 +719,7 @@ dse_step0 (void)
   bb_table = XCNEWVEC (bb_info_t, last_basic_block);
   rtx_group_next_id = 0;
 
-  stores_off_frame_dead_at_return = 
-    (!(TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
-       && (TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))))
-    && (!current_function_stdarg);
+  stores_off_frame_dead_at_return = !cfun->stdarg;
 
   init_alias_analysis ();
   
@@ -758,10 +783,9 @@ replace_inc_dec (rtx *r, void *d)
       {
        rtx r1 = XEXP (x, 0);
        rtx c = gen_int_mode (Pmode, data->size);
-       add_insn_before (data->insn, 
-                        gen_rtx_SET (Pmode, r1, 
-                                     gen_rtx_PLUS (Pmode, r1, c)),
-                        NULL);
+       emit_insn_before (gen_rtx_SET (Pmode, r1, 
+                                      gen_rtx_PLUS (Pmode, r1, c)),
+                         data->insn);
        return -1;
       }
                 
@@ -770,10 +794,9 @@ replace_inc_dec (rtx *r, void *d)
       {
        rtx r1 = XEXP (x, 0);
        rtx c = gen_int_mode (Pmode, -data->size);
-       add_insn_before (data->insn, 
-                        gen_rtx_SET (Pmode, r1, 
-                                     gen_rtx_PLUS (Pmode, r1, c)),
-                        NULL);
+       emit_insn_before (gen_rtx_SET (Pmode, r1, 
+                                      gen_rtx_PLUS (Pmode, r1, c)),
+                         data->insn);
        return -1;
       }
        
@@ -784,8 +807,7 @@ replace_inc_dec (rtx *r, void *d)
           insn that contained it.  */
        rtx add = XEXP (x, 0);
        rtx r1 = XEXP (add, 0);
-       add_insn_before (data->insn, 
-                        gen_rtx_SET (Pmode, r1, add), NULL);
+       emit_insn_before (gen_rtx_SET (Pmode, r1, add), data->insn);
        return -1;
       }
 
@@ -802,12 +824,12 @@ static int
 replace_inc_dec_mem (rtx *r, void *d)
 {
   rtx x = *r;
-  if (GET_CODE (x) == MEM)
+  if (x != NULL_RTX && MEM_P (x))
     {
       struct insn_size data;
 
       data.size = GET_MODE_SIZE (GET_MODE (x));
-      data.insn = (rtx)d;
+      data.insn = (rtx) d;
 
       for_each_rtx (&XEXP (x, 0), replace_inc_dec, &data);
        
@@ -845,7 +867,7 @@ delete_dead_store_insn (insn_info_t insn_info)
               INSN_UID (insn_info->insn));
       if (insn_info->store_rec->alias_set)
        fprintf (dump_file, "alias set %d\n", 
-                (int)insn_info->store_rec->alias_set);
+                (int) insn_info->store_rec->alias_set);
       else
        fprintf (dump_file, "\n");
     }
@@ -927,7 +949,7 @@ add_wild_read (bb_info_t bb_info)
   while (*ptr)
     {
       read_info_t next = (*ptr)->next;
-      if ( (*ptr)->alias_set == 0 )
+      if ((*ptr)->alias_set == 0)
         {
           pool_free (read_info_pool, *ptr);
           *ptr = next;
@@ -940,8 +962,9 @@ add_wild_read (bb_info_t bb_info)
 }
 
 
-/* Return true if X is a constant or one of the registers that behaves
-   as a constant over the life of a function.  */
+/* 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
+   !rtx_varies_p for memory addresses.  */
 
 static bool
 const_or_frame_p (rtx x)
@@ -996,7 +1019,7 @@ const_or_frame_p (rtx x)
 
 static bool
 canon_address (rtx mem,
-              HOST_WIDE_INT *alias_set_out,
+              alias_set_type *alias_set_out,
               int *group_id,
               HOST_WIDE_INT *offset, 
               cselib_val **base)
@@ -1009,9 +1032,9 @@ canon_address (rtx mem,
   if (clear_alias_sets)
     {
       /* If this is a spill, do not do any further processing.  */
-      HOST_WIDE_INT alias_set = MEM_ALIAS_SET (mem);
+      alias_set_type alias_set = MEM_ALIAS_SET (mem);
       if (dump_file)
-       fprintf (dump_file, "found alias set %d\n", (int)alias_set);
+       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 
@@ -1023,7 +1046,7 @@ canon_address (rtx mem,
              if (dump_file)
                fprintf (dump_file, 
                         "disqualifying alias set %d, (%s) != (%s)\n", 
-                        (int)alias_set, GET_MODE_NAME (entry->mode), 
+                        (int) alias_set, GET_MODE_NAME (entry->mode), 
                         GET_MODE_NAME (GET_MODE (mem)));
              
              bitmap_set_bit (disqualified_clear_alias_sets, alias_set);
@@ -1148,7 +1171,7 @@ record_store (rtx body, bb_info_t bb_info)
   rtx mem;
   HOST_WIDE_INT offset = 0;
   HOST_WIDE_INT width = 0;
-  HOST_WIDE_INT spill_alias_set;
+  alias_set_type spill_alias_set;
   insn_info_t insn_info = bb_info->last_insn;
   store_info_t store_info = NULL;
   int group_id;
@@ -1221,11 +1244,11 @@ record_store (rtx body, bb_info_t bb_info)
       if (clear_alias_group->offset_map_size_p < spill_alias_set)
        clear_alias_group->offset_map_size_p = spill_alias_set;
   
-      store_info = pool_alloc (rtx_store_info_pool);
+      store_info = (store_info_t) pool_alloc (rtx_store_info_pool);
 
       if (dump_file)
        fprintf (dump_file, " processing spill store %d(%s)\n",
-                (int)spill_alias_set, GET_MODE_NAME (GET_MODE (mem)));
+                (int) spill_alias_set, GET_MODE_NAME (GET_MODE (mem)));
     }
   else if (group_id >= 0)
     {
@@ -1235,7 +1258,7 @@ record_store (rtx body, bb_info_t bb_info)
       group_info_t group 
        = VEC_index (group_info_t, rtx_group_vec, group_id);
       
-      store_info = pool_alloc (rtx_store_info_pool);
+      store_info = (store_info_t) pool_alloc (rtx_store_info_pool);
       set_usage_bits (group, offset, width);
 
       if (dump_file)
@@ -1244,8 +1267,15 @@ record_store (rtx body, bb_info_t bb_info)
     }
   else
     {
-      store_info = pool_alloc (cse_store_info_pool);
+      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))
+       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)
@@ -1262,7 +1292,7 @@ record_store (rtx body, bb_info_t bb_info)
     {
       insn_info_t next = ptr->next_local_store;
       store_info_t s_info = ptr->store_rec;
-      bool delete = true;
+      bool del = true;
 
       /* Skip the clobbers. We delete the active insn if this insn
         shadows the set.  To have been put on the active list, it
@@ -1271,7 +1301,7 @@ record_store (rtx body, bb_info_t bb_info)
        s_info = s_info->next;
 
       if (s_info->alias_set != spill_alias_set)
-       delete = false;
+       del = false;
       else if (s_info->alias_set)
        {
          struct clear_alias_mode_holder *entry 
@@ -1284,12 +1314,12 @@ record_store (rtx body, bb_info_t bb_info)
          if ((GET_MODE (mem) == GET_MODE (s_info->mem))
              && (GET_MODE (mem) == entry->mode))
            {
-             delete = true;
-             s_info->positions_needed = 0;
+             del = true;
+             s_info->positions_needed = (unsigned HOST_WIDE_INT) 0;
            }
          if (dump_file)
            fprintf (dump_file, "    trying spill store in insn=%d alias_set=%d\n",
-                    INSN_UID (ptr->insn), (int)s_info->alias_set);
+                    INSN_UID (ptr->insn), (int) s_info->alias_set);
        }
       else if ((s_info->group_id == group_id) 
               && (s_info->cse_base == base))
@@ -1301,7 +1331,8 @@ record_store (rtx body, bb_info_t bb_info)
                     (int)s_info->begin, (int)s_info->end);
          for (i = offset; i < offset+width; i++)
            if (i >= s_info->begin && i < s_info->end)
-             s_info->positions_needed &= ~(1L << (i - s_info->begin));
+             s_info->positions_needed
+               &= ~(((unsigned HOST_WIDE_INT) 1) << (i - s_info->begin));
        }
       else if (s_info->rhs)
        /* Need to see if it is possible for this store to overwrite
@@ -1317,10 +1348,10 @@ 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 (s_info->positions_needed != 0)
-       delete = false;
+      if (s_info->positions_needed != (unsigned HOST_WIDE_INT) 0)
+       del = false;
       
-      if (delete)
+      if (del)
        {
          insn_info_t insn_to_delete = ptr;
          
@@ -1337,7 +1368,7 @@ record_store (rtx body, bb_info_t bb_info)
       ptr = next;
     }
   
-  gcc_assert ((unsigned) width < sizeof (store_info->positions_needed) * CHAR_BIT);
+  gcc_assert ((unsigned) width <= HOST_BITS_PER_WIDE_INT);
   
   /* Finish filling in the store_info.  */
   store_info->next = insn_info->store_rec;
@@ -1346,7 +1377,7 @@ record_store (rtx body, bb_info_t bb_info)
   store_info->alias_set = spill_alias_set;
   store_info->mem_addr = get_addr (XEXP (mem, 0));
   store_info->cse_base = base;
-  store_info->positions_needed = (1L << width) - 1;
+  store_info->positions_needed = lowpart_bitmask (width);
   store_info->group_id = group_id;
   store_info->begin = offset;
   store_info->end = offset + width;
@@ -1355,9 +1386,9 @@ record_store (rtx body, bb_info_t bb_info)
   if (store_info->is_set 
       /* No place to keep the value after ra.  */
       && !reload_completed
-      /* The careful reviewer may wish to comment my checking that the
-        rhs of a store is always a reg.  */
-      && REG_P (SET_SRC (body))
+      && (REG_P (SET_SRC (body))
+         || GET_CODE (SET_SRC (body)) == SUBREG
+         || CONSTANT_P (SET_SRC (body)))
       /* Sometimes the store and reload is used for truncation and
         rounding.  */
       && !(FLOAT_MODE_P (GET_MODE (mem)) && (flag_float_store)))
@@ -1381,6 +1412,104 @@ dump_insn_info (const char * start, insn_info_t insn_info)
 }
 
 
+/* If the modes are different and the value's source and target do not
+   line up, we need to extract the value from lower part of the rhs of
+   the store, shift it, and then put it into a form that can be shoved
+   into the read_insn.  This function generates a right SHIFT of a
+   value that is at least ACCESS_SIZE bytes wide of READ_MODE.  The
+   shift sequence is returned or NULL if we failed to find a
+   shift.  */
+
+static rtx
+find_shift_sequence (int access_size,
+                    store_info_t store_info,
+                    read_info_t read_info,
+                    int shift,
+                    bool speed)
+{
+  enum machine_mode store_mode = GET_MODE (store_info->mem);
+  enum machine_mode read_mode = GET_MODE (read_info->mem);
+  enum machine_mode new_mode;
+  rtx read_reg = NULL;
+
+  /* Some machines like the x86 have shift insns for each size of
+     operand.  Other machines like the ppc or the ia-64 may only have
+     shift insns that shift values within 32 or 64 bit registers.
+     This loop tries to find the smallest shift insn that will right
+     justify the value we want to read but is available in one insn on
+     the machine.  */
+
+  for (new_mode = smallest_mode_for_size (access_size * BITS_PER_UNIT,
+                                         MODE_INT);
+       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;
+      int cost;
+
+      /* 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)))
+       continue;
+
+      /* Also try a wider mode if the necessary punning is either not
+        desirable or not possible.  */
+      if (!CONSTANT_P (store_info->rhs)
+         && !MODES_TIEABLE_P (new_mode, store_mode))
+       continue;
+
+      new_reg = gen_reg_rtx (new_mode);
+
+      start_sequence ();
+
+      /* In theory we could also check for an ashr.  Ian Taylor knows
+        of one dsp where the cost of these two was not the same.  But
+        this really is a rare case anyway.  */
+      target = expand_binop (new_mode, lshr_optab, new_reg,
+                            GEN_INT (shift), new_reg, 1, OPTAB_DIRECT);
+
+      shift_seq = get_insns ();
+      end_sequence ();
+
+      if (target != new_reg || shift_seq == NULL)
+       continue;
+
+      cost = 0;
+      for (insn = shift_seq; insn != NULL_RTX; insn = NEXT_INSN (insn))
+       if (INSN_P (insn))
+         cost += insn_rtx_cost (PATTERN (insn), speed);
+
+      /* The computation up to here is essentially independent
+        of the arguments and could be precomputed.  It may
+        not be worth doing so.  We could precompute if
+        worthwhile or at least cache the results.  The result
+        technically depends on both SHIFT and ACCESS_SIZE,
+        but in practice the answer will depend only on ACCESS_SIZE.  */
+
+      if (cost > COSTS_N_INSNS (1))
+       continue;
+
+      new_lhs = extract_low_bits (new_mode, store_mode,
+                                 copy_rtx (store_info->rhs));
+      if (new_lhs == NULL_RTX)
+       continue;
+
+      /* We found an acceptable shift.  Generate a move to
+        take the value from the store and put it into the
+        shift pseudo, then shift it, then generate another
+        move to put in into the target of the read.  */
+      emit_move_insn (new_reg, new_lhs);
+      emit_insn (shift_seq);
+      read_reg = extract_low_bits (read_mode, new_mode, new_reg);
+      break;
+    }
+
+  return read_reg;
+}
+
+
 /* Take a sequence of:
      A <- r1
      ...
@@ -1392,7 +1521,23 @@ dump_insn_info (const char * start, insn_info_t insn_info)
    ...
    ... <- r2
 
-   The STORE_INFO and STORE_INFO are for the store and the READ_INFO
+   or
+
+   r3 <- extract (r1)
+   r3 <- r3 >> shift
+   r2 <- extract (r3)
+   ... <- r2
+
+   or
+
+   r2 <- extract (r1)
+   ... <- r2
+
+   Depending on the alignment and the mode of the store and
+   subsequent load.
+
+
+   The STORE_INFO and STORE_INSN are for the store and READ_INFO
    and READ_INSN are for the read.  Return true if the replacement
    went ok.  */
 
@@ -1400,82 +1545,124 @@ static bool
 replace_read (store_info_t store_info, insn_info_t store_insn, 
              read_info_t read_info, insn_info_t read_insn, rtx *loc)
 {
+  enum machine_mode store_mode = GET_MODE (store_info->mem);
+  enum machine_mode read_mode = GET_MODE (read_info->mem);
+  int shift;
+  int access_size; /* In bytes.  */
+  rtx insns, read_reg;
+
   if (!dbg_cnt (dse))
     return false;
 
+  /* To get here the read is within the boundaries of the write so
+     shift will never be negative.  Start out with the shift being in
+     bytes.  */
+  if (BYTES_BIG_ENDIAN)
+    shift = store_info->end - read_info->end;
+  else
+    shift = read_info->begin - store_info->begin;
+
+  access_size = shift + GET_MODE_SIZE (read_mode);
+
+  /* From now on it is bits.  */
+  shift *= BITS_PER_UNIT;
+
+  /* Create a sequence of instructions to set up the read register.
+     This sequence goes immediately before the store and its result
+     is read by the load.
+
+     We need to keep this in perspective.  We are replacing a read
+     with a sequence of insns, but the read will almost certainly be
+     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)
-    fprintf (dump_file, "generating move to replace load at %d from store at %d\n", 
-            INSN_UID (read_insn->insn), INSN_UID (store_insn->insn)); 
-  if (GET_MODE (store_info->mem) == GET_MODE (read_info->mem))
+    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),
+            GET_MODE_NAME (store_mode), INSN_UID (store_insn->insn));
+  start_sequence ();
+  if (shift)
+    read_reg = find_shift_sequence (access_size, store_info, read_info, shift,
+                                   optimize_bb_for_speed_p (BLOCK_FOR_INSN (read_insn->insn)));
+  else
+    read_reg = extract_low_bits (read_mode, store_mode,
+                                copy_rtx (store_info->rhs));
+  if (read_reg == NULL_RTX)
     {
-      rtx new_reg = gen_reg_rtx (GET_MODE (store_info->mem));
-      if (validate_change (read_insn->insn, loc, new_reg, 0))
-       {
-         rtx insns;
-         deferred_change_t deferred_change = pool_alloc (deferred_change_pool);
-
-         start_sequence ();
-         emit_move_insn (new_reg, store_info->rhs);
-         insns = get_insns ();
-         end_sequence ();
-         emit_insn_before (insns, store_insn->insn);
+      end_sequence ();
+      if (dump_file)
+       fprintf (dump_file, " -- could not extract bits of stored value\n");
+      return false;
+    }
+  /* Force the value into a new register so that it won't be clobbered
+     between the store and the load.  */
+  read_reg = copy_to_mode_reg (read_mode, read_reg);
+  insns = get_insns ();
+  end_sequence ();
 
-         if (dump_file)
-           fprintf (dump_file, " -- adding move insn %d: r%d = r%d\n", 
-                    INSN_UID (insns), REGNO (new_reg), REGNO (store_info->rhs)); 
-
-         /* And now for the cludge 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 one 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".
-
-            So we are just going to have to lie.  The move insn is
-            not really an issue, cselib did not see it.  But the use
-            of the new pseudo read_insn is a real problem.  The way
-            that we solve this problem is that we are just going to
-            put the mem back keep a table of mems to get rid of.  At
-            the end of the basic block we can put it back.  */
-
-         *loc = read_info->mem;
-         deferred_change->next = deferred_change_list;
-         deferred_change_list = deferred_change;
-         deferred_change->loc = loc;
-         deferred_change->reg = new_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);
-         return true;
-       }
-      else 
+  if (validate_change (read_insn->insn, loc, read_reg, 0))
+    {
+      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
+        cselib has not scanned this insn.  The way that we solve this
+        problem is that we are just going to put the mem back for now
+        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)
-           fprintf (dump_file, " -- validation failure\n"); 
-         return false;
+         fprintf (dump_file, " -- replaced the loaded MEM with ");
+         print_simple_rtl (dump_file, read_reg);
+         fprintf (dump_file, "\n");
        }
+      return true;
     }
-  else
+  else 
     {
-      /* Someone with excellent rtl skills needs to fill this in.  You
-        are guaranteed that the read is of the same size or smaller
-        than the store, and that the read does not hang off one of
-        the ends of the store.  But the offsets of each must be
-        checked because the read does not have to line up on either
-        end of the store so the begin fields need to be examined in
-        both the store_info and read_info.  */
       if (dump_file)
-       fprintf (dump_file, " -- complex load, currently unsupported.\n"); 
+       {
+         fprintf (dump_file, " -- replacing the loaded MEM with ");
+         print_simple_rtl (dump_file, read_reg);
+         fprintf (dump_file, " led to an invalid instruction\n");
+       }
       return false;
     }
 }
 
-
 /* 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.  */
@@ -1488,7 +1675,7 @@ check_mem_read_rtx (rtx *loc, void *data)
   insn_info_t insn_info;
   HOST_WIDE_INT offset = 0;
   HOST_WIDE_INT width = 0;
-  HOST_WIDE_INT spill_alias_set = 0;
+  alias_set_type spill_alias_set = 0;
   cselib_val *base = NULL;  
   int group_id;
   read_info_t read_info;
@@ -1527,7 +1714,7 @@ check_mem_read_rtx (rtx *loc, void *data)
   else
     width = GET_MODE_SIZE (GET_MODE (mem));
 
-  read_info = pool_alloc (read_info_pool);
+  read_info = (read_info_t) pool_alloc (read_info_pool);
   read_info->group_id = group_id;
   read_info->mem = mem;
   read_info->alias_set = spill_alias_set;
@@ -1546,7 +1733,7 @@ check_mem_read_rtx (rtx *loc, void *data)
 
       if (dump_file)
        fprintf (dump_file, " processing spill load %d\n",
-                (int)spill_alias_set);
+                (int) spill_alias_set);
 
       while (i_ptr)
        {
@@ -1626,8 +1813,10 @@ check_mem_read_rtx (rtx *loc, void *data)
                      && (offset >= store_info->begin)
                      && (offset + width <= store_info->end))
                    {
-                     int mask = ((1L << width) - 1) << (offset - store_info->begin);
-                     
+                     unsigned HOST_WIDE_INT mask
+                       = (lowpart_bitmask (width)
+                          << (offset - store_info->begin));
+
                      if ((store_info->positions_needed & mask) == mask
                          && replace_read (store_info, i_ptr, 
                                           read_info, insn_info, loc))
@@ -1693,8 +1882,10 @@ check_mem_read_rtx (rtx *loc, void *data)
              && (offset >= store_info->begin)
              && (offset + width <= store_info->end))
            {
-             int mask = ((1L << width) - 1) << (offset - store_info->begin);
-             
+             unsigned HOST_WIDE_INT mask
+               = (lowpart_bitmask (width)
+                  << (offset - store_info->begin));
+
              if ((store_info->positions_needed & mask) == mask
                  && replace_read (store_info, i_ptr, 
                                   read_info, insn_info, loc))
@@ -1743,7 +1934,7 @@ static void
 scan_insn (bb_info_t bb_info, rtx insn)
 {
   rtx body;
-  insn_info_t insn_info = pool_alloc (insn_info_pool);
+  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));
 
@@ -1773,10 +1964,11 @@ scan_insn (bb_info_t bb_info, rtx insn)
   if (CALL_P (insn))
     {
       insn_info->cannot_delete = true;
+
       /* Const functions cannot do anything bad i.e. read memory,
-        however, they can read their parameters which may have been
-        pushed onto the stack.  */
-      if (CONST_OR_PURE_CALL_P (insn) && !pure_call_p (insn))
+        however, they can read their parameters which may have
+        been pushed onto the stack.  */
+      if (RTL_CONST_CALL_P (insn))
        {
          insn_info_t i_ptr = active_local_stores;
          insn_info_t last = NULL;
@@ -1784,17 +1976,36 @@ scan_insn (bb_info_t bb_info, rtx insn)
          if (dump_file)
            fprintf (dump_file, "const call %d\n", INSN_UID (insn));
 
+         /* See the head comment of the frame_read field.  */
+         if (reload_completed)
+           insn_info->frame_read = true;
+
+         /* Loop over the active stores and remove those which are
+            killed by the const function call.  */
          while (i_ptr)
            {
-             store_info_t store_info = i_ptr->store_rec;
+             bool remove_store = false;
 
-             /* Skip the clobbers.  */
-             while (!store_info->is_set)
-               store_info = store_info->next;
+             /* The stack pointer based stores are always killed.  */
+             if (i_ptr->stack_pointer_based)
+               remove_store = true;
 
-             /* Remove the frame related stores.  */
-             if (store_info->group_id >= 0
-                 && VEC_index (group_info_t, rtx_group_vec, store_info->group_id)->frame_related)
+             /* If the frame is read, the frame related stores are killed.  */
+             else if (insn_info->frame_read)
+               {
+                 store_info_t store_info = i_ptr->store_rec;
+
+                 /* Skip the clobbers.  */
+                 while (!store_info->is_set)
+                   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)
+                   remove_store = true;
+               }
+
+             if (remove_store)
                {
                  if (dump_file)
                    dump_insn_info ("removing from active", i_ptr);
@@ -1806,23 +2017,22 @@ scan_insn (bb_info_t bb_info, rtx insn)
                }
              else
                last = i_ptr;
+
              i_ptr = i_ptr->next_local_store;
            }
-
-         insn_info->stack_read = true;
-         
-         return;
        }
 
-      /* Every other call, including pure functions may read memory.  */
-      add_wild_read (bb_info);
+      else
+       /* Every other call, including pure functions, may read memory.  */
+       add_wild_read (bb_info);
+
       return;
     }
 
   /* Assuming that there are sets in these insns, we cannot delete
      them.  */
   if ((GET_CODE (PATTERN (insn)) == CLOBBER)
-      || volatile_insn_p (PATTERN (insn))
+      || volatile_refs_p (PATTERN (insn))
       || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
       || (RTX_FRAME_RELATED_P (insn))
       || find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX))
@@ -1869,7 +2079,7 @@ remove_useless_values (cselib_val *base)
   while (insn_info)
     {
       store_info_t store_info = insn_info->store_rec;
-      bool delete = false;
+      bool del = false;
 
       /* If ANY of the store_infos match the cselib group that is
         being deleted, then the insn can not be deleted.  */
@@ -1878,13 +2088,13 @@ remove_useless_values (cselib_val *base)
          if ((store_info->group_id == -1) 
              && (store_info->cse_base == base))
            {
-             delete = true;
+             del = true;
              break;
            }
          store_info = store_info->next;
        }
 
-      if (delete)
+      if (del)
        {
          if (last)
            last->next_local_store = insn_info->next_local_store;
@@ -1915,7 +2125,7 @@ dse_step1 (void)
   FOR_ALL_BB (bb)
     {
       insn_info_t ptr;
-      bb_info_t bb_info = pool_alloc (bb_info_pool);
+      bb_info_t bb_info = (bb_info_t) pool_alloc (bb_info_pool);
 
       memset (bb_info, 0, sizeof (struct bb_info));
       bitmap_set_bit (all_blocks, bb->index);
@@ -1954,7 +2164,7 @@ dse_step1 (void)
              && (EDGE_COUNT (bb->succs) == 0
                  || (single_succ_p (bb)
                      && single_succ (bb) == EXIT_BLOCK_PTR
-                     && ! current_function_calls_eh_return)))
+                     && ! crtl->calls_eh_return)))
            {
              insn_info_t i_ptr = active_local_stores;
              while (i_ptr)
@@ -2187,7 +2397,7 @@ dse_step2_spill (void)
 
 
 void 
-dse_record_singleton_alias_set (HOST_WIDE_INT alias_set, 
+dse_record_singleton_alias_set (alias_set_type alias_set, 
                                enum machine_mode mode)
 {
   struct clear_alias_mode_holder tmp_holder;
@@ -2216,7 +2426,8 @@ dse_record_singleton_alias_set (HOST_WIDE_INT alias_set,
   slot = htab_find_slot (clear_alias_mode_table, &tmp_holder, INSERT);
   gcc_assert (*slot == NULL);
 
-  *slot = entry = pool_alloc (clear_alias_mode_pool);
+  *slot = entry =
+    (struct clear_alias_mode_holder *) pool_alloc (clear_alias_mode_pool);
   entry->alias_set = alias_set;
   entry->mode = mode;
 }
@@ -2225,7 +2436,7 @@ dse_record_singleton_alias_set (HOST_WIDE_INT alias_set,
 /* Remove ALIAS_SET from the sets of stack slots being considered.  */
 
 void 
-dse_invalidate_singleton_alias_set (HOST_WIDE_INT alias_set)
+dse_invalidate_singleton_alias_set (alias_set_type alias_set)
 {
   if ((!gate_dse()) || !alias_set)
     return;
@@ -2317,8 +2528,8 @@ scan_reads_nospill (insn_info_t insn_info, bitmap gen, bitmap kill)
   int i;
   group_info_t group;
 
-  /* For const function calls kill the stack related stores.  */
-  if (insn_info->stack_read)
+  /* 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++)
        if (group->process_globally && group->frame_related)
@@ -2944,43 +3155,30 @@ dse_step6 (bool global_done)
   group_info_t group;
   basic_block bb;
   
-  if (global_done)
-    {
-      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);
-       }
-
-      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);
-       }
-    }
-  else
+  for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
     {
-      for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
-       {
-         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);
-       }
+      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);
@@ -3005,7 +3203,6 @@ dse_step6 (bool global_done)
 }
 
 
-
 /* -------------------------------------------------------------------------
    DSE
    ------------------------------------------------------------------------- */
@@ -3065,13 +3262,29 @@ rest_of_handle_dse (void)
 static bool
 gate_dse (void)
 {
-  return optimize > 0 && flag_dse;
+  return gate_dse1 () || gate_dse2 ();
+}
+
+static bool
+gate_dse1 (void)
+{
+  return optimize > 0 && flag_dse
+    && dbg_cnt (dse1);
+}
+
+static bool
+gate_dse2 (void)
+{
+  return optimize > 0 && flag_dse
+    && dbg_cnt (dse2);
 }
 
-struct tree_opt_pass pass_rtl_dse1 =
+struct rtl_opt_pass pass_rtl_dse1 =
 {
+ {
+  RTL_PASS,
   "dse1",                               /* name */
-  gate_dse                            /* gate */
+  gate_dse1,                            /* gate */
   rest_of_handle_dse,                   /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
@@ -3082,15 +3295,17 @@ struct tree_opt_pass pass_rtl_dse1 =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func |
-  TODO_df_finish |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'w'                                   /* letter */
+  TODO_df_finish | TODO_verify_rtl_sharing |
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
 
-struct tree_opt_pass pass_rtl_dse2 =
+struct rtl_opt_pass pass_rtl_dse2 =
 {
+ {
+  RTL_PASS,
   "dse2",                               /* name */
-  gate_dse                            /* gate */
+  gate_dse2,                            /* gate */
   rest_of_handle_dse,                   /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
@@ -3101,8 +3316,7 @@ struct tree_opt_pass pass_rtl_dse2 =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func |
-  TODO_df_finish |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'w'                                   /* letter */
+  TODO_df_finish | TODO_verify_rtl_sharing |
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
-