OSDN Git Service

Revert "Fix PR debug/49047"
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 3f3b863..d83b38a 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,6 +1,6 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -20,7 +20,6 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
-/* stdio.h must precede rtl.h for FFS.  */
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
@@ -30,11 +29,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "regs.h"
 #include "basic-block.h"
 #include "flags.h"
-#include "real.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "function.h"
 #include "expr.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "output.h"
 #include "ggc.h"
@@ -686,7 +685,7 @@ approx_reg_cost_1 (rtx *xp, void *data)
        {
          if (regno < FIRST_PSEUDO_REGISTER)
            {
-             if (SMALL_REGISTER_CLASSES)
+             if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
                return 1;
              *cost_p += 2;
            }
@@ -797,8 +796,7 @@ init_cse_reg_info (unsigned int nregs)
        }
 
       /* Reallocate the table with NEW_SIZE entries.  */
-      if (cse_reg_info_table)
-       free (cse_reg_info_table);
+      free (cse_reg_info_table);
       cse_reg_info_table = XNEWVEC (struct cse_reg_info, new_size);
       cse_reg_info_table_size = new_size;
       cse_reg_info_table_first_uninitialized = 0;
@@ -2237,7 +2235,7 @@ hash_rtx_string (const char *ps)
   return hash;
 }
 
-/* Same as hash_rtx, but call CB on each rtx if it is not NULL.  
+/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
    When the callback returns true, we continue with the new rtx.  */
 
 unsigned
@@ -2260,7 +2258,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
     return hash;
 
   /* Invoke the callback first.  */
-  if (cb != NULL 
+  if (cb != NULL
       && ((*cb) (x, mode, &newx, &newmode)))
     {
       hash += hash_rtx_cb (newx, newmode, do_not_record_p,
@@ -2287,7 +2285,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
 
               On all machines, we can't record any global registers.
               Nor should we record any register that is in a small
-              class, as defined by CLASS_LIKELY_SPILLED_P.  */
+              class, as defined by TARGET_CLASS_LIKELY_SPILLED_P.  */
            bool record;
 
            if (regno >= FIRST_PSEUDO_REGISTER)
@@ -2304,9 +2302,9 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
              record = true;
            else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
              record = true;
-           else if (SMALL_REGISTER_CLASSES)
+           else if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
              record = false;
-           else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
+           else if (targetm.class_likely_spilled_p (REGNO_REG_CLASS (regno)))
              record = false;
            else
              record = true;
@@ -2370,7 +2368,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
          {
            elt = CONST_VECTOR_ELT (x, i);
            hash += hash_rtx_cb (elt, GET_MODE (elt),
-                                 do_not_record_p, hash_arg_in_memory_p, 
+                                 do_not_record_p, hash_arg_in_memory_p,
                                  have_reg_qty, cb);
          }
 
@@ -2516,7 +2514,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
              x = XEXP (x, i);
              goto repeat;
            }
-          
+
          hash += hash_rtx_cb (XEXP (x, i), VOIDmode, do_not_record_p,
                                hash_arg_in_memory_p,
                                have_reg_qty, cb);
@@ -2623,6 +2621,10 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
   if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
+  /* MEMs refering to different address space are not equivalent.  */
+  if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+    return 0;
+
   switch (code)
     {
     case PC:
@@ -2667,26 +2669,16 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
     case MEM:
       if (for_gcse)
        {
+         /* Can't merge two expressions in different alias sets, since we
+            can decide that the expression is transparent in a block when
+            it isn't, due to it being set with the different alias set.  */
+         if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
+           return 0;
+
          /* A volatile mem should not be considered equivalent to any
             other.  */
          if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
            return 0;
-
-         /* Can't merge two expressions in different alias sets, since we
-            can decide that the expression is transparent in a block when
-            it isn't, due to it being set with the different alias set.
-
-            Also, can't merge two expressions with different MEM_ATTRS.
-            They could e.g. be two different entities allocated into the
-            same space on the stack (see e.g. PR25130).  In that case, the
-            MEM addresses can be the same, even though the two MEMs are
-            absolutely not equivalent.  
-   
-            But because really all MEM attributes should be the same for
-            equivalent MEMs, we just use the invariant that MEMs that have
-            the same attributes share the same mem_attrs data structure.  */
-         if (MEM_ATTRS (x) != MEM_ATTRS (y))
-           return 0;
        }
       break;
 
@@ -3423,7 +3415,7 @@ fold_rtx (rtx x, rtx insn)
                     constant through simplifications.  */
                  p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
                              mode_arg0);
-                 
+
                  if (p != NULL)
                    {
                      cheapest_simplification = x;
@@ -4345,12 +4337,23 @@ cse_insn (rtx insn)
       if (MEM_P (XEXP (x, 0)))
        canon_reg (XEXP (x, 0), insn);
     }
-
   /* Canonicalize a USE of a pseudo register or memory location.  */
   else if (GET_CODE (x) == USE
           && ! (REG_P (XEXP (x, 0))
                 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
-    canon_reg (XEXP (x, 0), insn);
+    canon_reg (x, insn);
+  else if (GET_CODE (x) == ASM_OPERANDS)
+    {
+      for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+       {
+         rtx input = ASM_OPERANDS_INPUT (x, i);
+         if (!(REG_P (input) && REGNO (input) < FIRST_PSEUDO_REGISTER))
+           {
+             input = canon_reg (input, insn);
+             validate_change (insn, &ASM_OPERANDS_INPUT (x, i), input, 1);
+           }
+       }
+    }
   else if (GET_CODE (x) == CALL)
     {
       /* The result of apply_change_group can be ignored; see canon_reg.  */
@@ -4432,6 +4435,7 @@ cse_insn (rtx insn)
 
   for (i = 0; i < n_sets; i++)
     {
+      bool repeat = false;
       rtx src, dest;
       rtx src_folded;
       struct table_elt *elt = 0, *p;
@@ -5021,10 +5025,81 @@ cse_insn (rtx insn)
              dest = canon_rtx (SET_DEST (sets[i].rtl));
 
              if (!MEM_P (src) || !MEM_P (dest)
-                 || !nonoverlapping_memrefs_p (src, dest))
+                 || !nonoverlapping_memrefs_p (src, dest, false))
                break;
            }
 
+         /* Try to optimize
+            (set (reg:M N) (const_int A))
+            (set (reg:M2 O) (const_int B))
+            (set (zero_extract:M2 (reg:M N) (const_int C) (const_int D))
+                 (reg:M2 O)).  */
+         if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
+             && CONST_INT_P (trial)
+             && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
+             && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
+             && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
+             && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (sets[i].rtl)))
+                 >= INTVAL (XEXP (SET_DEST (sets[i].rtl), 1)))
+             && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
+                 + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
+                 <= HOST_BITS_PER_WIDE_INT))
+           {
+             rtx dest_reg = XEXP (SET_DEST (sets[i].rtl), 0);
+             rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
+             rtx pos = XEXP (SET_DEST (sets[i].rtl), 2);
+             unsigned int dest_hash = HASH (dest_reg, GET_MODE (dest_reg));
+             struct table_elt *dest_elt
+               = lookup (dest_reg, dest_hash, GET_MODE (dest_reg));
+             rtx dest_cst = NULL;
+
+             if (dest_elt)
+               for (p = dest_elt->first_same_value; p; p = p->next_same_value)
+                 if (p->is_const && CONST_INT_P (p->exp))
+                   {
+                     dest_cst = p->exp;
+                     break;
+                   }
+             if (dest_cst)
+               {
+                 HOST_WIDE_INT val = INTVAL (dest_cst);
+                 HOST_WIDE_INT mask;
+                 unsigned int shift;
+                 if (BITS_BIG_ENDIAN)
+                   shift = GET_MODE_BITSIZE (GET_MODE (dest_reg))
+                           - INTVAL (pos) - INTVAL (width);
+                 else
+                   shift = INTVAL (pos);
+                 if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
+                   mask = ~(HOST_WIDE_INT) 0;
+                 else
+                   mask = ((HOST_WIDE_INT) 1 << INTVAL (width)) - 1;
+                 val &= ~(mask << shift);
+                 val |= (INTVAL (trial) & mask) << shift;
+                 val = trunc_int_for_mode (val, GET_MODE (dest_reg));
+                 validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
+                                          dest_reg, 1);
+                 validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+                                          GEN_INT (val), 1);
+                 if (apply_change_group ())
+                   {
+                     rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+                     if (note)
+                       {
+                         remove_note (insn, note);
+                         df_notes_rescan (insn);
+                       }
+                     src_eqv = NULL_RTX;
+                     src_eqv_elt = NULL;
+                     src_eqv_volatile = 0;
+                     src_eqv_in_memory = 0;
+                     src_eqv_hash = 0;
+                     repeat = true;
+                     break;
+                   }
+               }
+           }
+
          /* We don't normally have an insn matching (set (pc) (pc)), so
             check for this separately here.  We will delete such an
             insn below.
@@ -5100,6 +5175,13 @@ cse_insn (rtx insn)
            }
        }
 
+      /* If we changed the insn too much, handle this set from scratch.  */
+      if (repeat)
+       {
+         i--;
+         continue;
+       }
+
       src = SET_SRC (sets[i].rtl);
 
       /* In general, it is good to have a SET with SET_SRC == SET_DEST.
@@ -5997,7 +6079,7 @@ cse_process_notes (rtx x, rtx object, bool *changed)
    describe the path.
    It is filled with a queue of basic blocks, starting with FIRST_BB
    and following a trace through the CFG.
-  
+
    If all paths starting at FIRST_BB have been followed, or no new path
    starting at FIRST_BB can be constructed, this function returns FALSE.
    Otherwise, DATA->path is filled and the function returns TRUE indicating
@@ -6013,7 +6095,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
   basic_block bb;
   edge e;
   int path_size;
+
   SET_BIT (cse_visited_basic_blocks, first_bb->index);
 
   /* See if there is a previous path.  */
@@ -6174,7 +6256,7 @@ cse_prescan_path (struct cse_basic_block_data *data)
   int path_entry;
 
   /* Scan to end of each basic block in the path.  */
-  for (path_entry = 0; path_entry < path_size; path_entry++) 
+  for (path_entry = 0; path_entry < path_size; path_entry++)
     {
       basic_block bb;
       rtx insn;
@@ -6234,9 +6316,9 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
            }
        }
 
+      optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
       FOR_BB_INSNS (bb, insn)
        {
-         optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
          /* If we have processed 1,000 insns, flush the hash table to
             avoid extreme quadratic behavior.  We must not include NOTEs
             in the count since there may be more of them when generating
@@ -6276,29 +6358,31 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                recorded_label_ref = true;
 
 #ifdef HAVE_cc0
-             /* If the previous insn set CC0 and this insn no longer
-                references CC0, delete the previous insn.  Here we use
-                fact that nothing expects CC0 to be valid over an insn,
-                which is true until the final pass.  */
-             {
-               rtx prev_insn, tem;
-
-               prev_insn = PREV_INSN (insn);
-               if (prev_insn && NONJUMP_INSN_P (prev_insn)
-                   && (tem = single_set (prev_insn)) != 0
-                   && SET_DEST (tem) == cc0_rtx
-                   && ! reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-                 delete_insn (prev_insn);
-             }
-
-             /* If this insn is not the last insn in the basic block,
-                it will be PREV_INSN(insn) in the next iteration.  If
-                we recorded any CC0-related information for this insn,
-                remember it.  */
-             if (insn != BB_END (bb))
+             if (NONDEBUG_INSN_P (insn))
                {
-                 prev_insn_cc0 = this_insn_cc0;
-                 prev_insn_cc0_mode = this_insn_cc0_mode;
+                 /* If the previous insn sets CC0 and this insn no
+                    longer references CC0, delete the previous insn.
+                    Here we use fact that nothing expects CC0 to be
+                    valid over an insn, which is true until the final
+                    pass.  */
+                 rtx prev_insn, tem;
+
+                 prev_insn = prev_nonnote_nondebug_insn (insn);
+                 if (prev_insn && NONJUMP_INSN_P (prev_insn)
+                     && (tem = single_set (prev_insn)) != NULL_RTX
+                     && SET_DEST (tem) == cc0_rtx
+                     && ! reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+                   delete_insn (prev_insn);
+
+                 /* If this insn is not the last insn in the basic
+                    block, it will be PREV_INSN(insn) in the next
+                    iteration.  If we recorded any CC0-related
+                    information for this insn, remember it.  */
+                 if (insn != BB_END (bb))
+                   {
+                     prev_insn_cc0 = this_insn_cc0;
+                     prev_insn_cc0_mode = this_insn_cc0_mode;
+                   }
                }
 #endif
            }
@@ -6307,7 +6391,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
       /* With non-call exceptions, we are not always able to update
         the CFG properly inside cse_insn.  So clean up possibly
         redundant EH edges here.  */
-      if (flag_non_call_exceptions && have_eh_succ_edges (bb))
+      if (cfun->can_throw_non_call_exceptions && have_eh_succ_edges (bb))
        cse_cfg_altered |= purge_dead_edges (bb);
 
       /* If we changed a conditional jump, we may have terminated
@@ -6490,8 +6574,9 @@ check_for_label_ref (rtx *rtl, void *data)
    Don't count a usage of DEST, which is the SET_DEST of a SET which
    contains X in its SET_SRC.  This is because such a SET does not
    modify the liveness of DEST.
-   DEST is set to pc_rtx for a trapping insn, which means that we must count
-   uses of a SET_DEST regardless because the insn can't be deleted here.  */
+   DEST is set to pc_rtx for a trapping insn, or for an insn with side effects.
+   We must then count uses of a SET_DEST regardless, because the insn can't be
+   deleted here.  */
 
 static void
 count_reg_usage (rtx x, int *counts, rtx dest, int incr)
@@ -6544,9 +6629,10 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     case CALL_INSN:
     case INSN:
     case JUMP_INSN:
-    /* We expect dest to be NULL_RTX here.  If the insn may trap, mark
-       this fact by setting DEST to pc_rtx.  */
-      if (flag_non_call_exceptions && may_trap_p (PATTERN (x)))
+      /* We expect dest to be NULL_RTX here.  If the insn may trap,
+        or if it cannot be deleted due to side-effects, mark this fact
+        by setting DEST to pc_rtx.  */
+      if (insn_could_throw_p (x) || side_effects_p (PATTERN (x)))
        dest = pc_rtx;
       if (code == CALL_INSN)
        count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
@@ -6586,10 +6672,6 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
       return;
 
     case ASM_OPERANDS:
-      /* If the asm is volatile, then this insn cannot be deleted,
-        and so the inputs *must* be live.  */
-      if (MEM_VOLATILE_P (x))
-       dest = NULL_RTX;
       /* Iterate over just the inputs, not the constraints as well.  */
       for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
        count_reg_usage (ASM_OPERANDS_INPUT (x, i), counts, dest, incr);
@@ -6613,14 +6695,11 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     }
 }
 \f
-/* Return true if a register is dead.  Can be used in for_each_rtx.  */
+/* Return true if X is a dead register.  */
 
-static int
-is_dead_reg (rtx *loc, void *data)
+static inline int
+is_dead_reg (rtx x, int *counts)
 {
-  rtx x = *loc;
-  int *counts = (int *)data;
-
   return (REG_P (x)
          && REGNO (x) >= FIRST_PSEUDO_REGISTER
          && counts[REGNO (x)] == 0);
@@ -6641,12 +6720,12 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
 #ifdef HAVE_cc0
   else if (GET_CODE (SET_DEST (set)) == CC0
           && !side_effects_p (SET_SRC (set))
-          && ((tem = next_nonnote_insn (insn)) == 0
+          && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
               || !INSN_P (tem)
               || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
 #endif
-  else if (!is_dead_reg (&SET_DEST (set), counts)
+  else if (!is_dead_reg (SET_DEST (set), counts)
           || side_effects_p (SET_SRC (set)))
     return true;
   return false;
@@ -6658,7 +6737,7 @@ static bool
 insn_live_p (rtx insn, int *counts)
 {
   int i;
-  if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+  if (insn_could_throw_p (insn))
     return true;
   else if (GET_CODE (PATTERN (insn)) == SET)
     return set_live_p (PATTERN (insn), insn, counts);
@@ -6690,21 +6769,68 @@ insn_live_p (rtx insn, int *counts)
        else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
          return false;
 
-      /* If this debug insn references a dead register, drop the
-        location expression for now.  ??? We could try to find the
-        def and see if propagation is possible.  */
-      if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn), is_dead_reg, counts))
-       {
-         INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
-         df_insn_rescan (insn);
-       }
-
       return true;
     }
   else
     return true;
 }
 
+/* Count the number of stores into pseudo.  Callback for note_stores.  */
+
+static void
+count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data)
+{
+  int *counts = (int *) data;
+  if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+    counts[REGNO (x)]++;
+}
+
+struct dead_debug_insn_data
+{
+  int *counts;
+  rtx *replacements;
+  bool seen_repl;
+};
+
+/* Return if a DEBUG_INSN needs to be reset because some dead
+   pseudo doesn't have a replacement.  Callback for for_each_rtx.  */
+
+static int
+is_dead_debug_insn (rtx *loc, void *data)
+{
+  rtx x = *loc;
+  struct dead_debug_insn_data *ddid = (struct dead_debug_insn_data *) data;
+
+  if (is_dead_reg (x, ddid->counts))
+    {
+      if (ddid->replacements && ddid->replacements[REGNO (x)] != NULL_RTX)
+       ddid->seen_repl = true;
+      else
+       return 1;
+    }
+  return 0;
+}
+
+/* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
+   Callback for simplify_replace_fn_rtx.  */
+
+static rtx
+replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
+{
+  rtx *replacements = (rtx *) data;
+
+  if (REG_P (x)
+      && REGNO (x) >= FIRST_PSEUDO_REGISTER
+      && replacements[REGNO (x)] != NULL_RTX)
+    {
+      if (GET_MODE (x) == GET_MODE (replacements[REGNO (x)]))
+       return replacements[REGNO (x)];
+      return lowpart_subreg (GET_MODE (x), replacements[REGNO (x)],
+                            GET_MODE (replacements[REGNO (x)]));
+    }
+  return NULL_RTX;
+}
+
 /* Scan all the insns and delete any that are dead; i.e., they store a register
    that is never used or they copy a register to itself.
 
@@ -6718,22 +6844,51 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 {
   int *counts;
   rtx insn, prev;
+  rtx *replacements = NULL;
   int ndead = 0;
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  counts = XCNEWVEC (int, nreg);
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      count_reg_usage (insn, counts, NULL_RTX, 1);
-
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      counts = XCNEWVEC (int, nreg * 3);
+      for (insn = insns; insn; insn = NEXT_INSN (insn))
+       if (DEBUG_INSN_P (insn))
+         count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+                          NULL_RTX, 1);
+       else if (INSN_P (insn))
+         {
+           count_reg_usage (insn, counts, NULL_RTX, 1);
+           note_stores (PATTERN (insn), count_stores, counts + nreg * 2);
+         }
+      /* If there can be debug insns, COUNTS are 3 consecutive arrays.
+        First one counts how many times each pseudo is used outside
+        of debug insns, second counts how many times each pseudo is
+        used in debug insns and third counts how many times a pseudo
+        is stored.  */
+    }
+  else
+    {
+      counts = XCNEWVEC (int, nreg);
+      for (insn = insns; insn; insn = NEXT_INSN (insn))
+       if (INSN_P (insn))
+         count_reg_usage (insn, counts, NULL_RTX, 1);
+      /* If no debug insns can be present, COUNTS is just an array
+        which counts how many times each pseudo is used.  */
+    }
   /* Go from the last insn to the first and delete insns that only set unused
      registers or copy a register to itself.  As we delete an insn, remove
      usage counts for registers it uses.
 
      The first jump optimization pass may leave a real insn as the last
      insn in the function.   We must not skip that insn or we may end
-     up deleting code that is not really dead.  */
+     up deleting code that is not really dead.
+
+     If some otherwise unused register is only used in DEBUG_INSNs,
+     try to create a DEBUG_EXPR temporary and emit a DEBUG_INSN before
+     the setter.  Then go through DEBUG_INSNs and if a DEBUG_EXPR
+     has been created for the unused register, replace it with
+     the DEBUG_EXPR, otherwise reset the DEBUG_INSN.  */
   for (insn = get_last_insn (); insn; insn = prev)
     {
       int live_insn = 0;
@@ -6749,12 +6904,79 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 
       if (! live_insn && dbg_cnt (delete_trivial_dead))
        {
-         count_reg_usage (insn, counts, NULL_RTX, -1);
+         if (DEBUG_INSN_P (insn))
+           count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+                            NULL_RTX, -1);
+         else
+           {
+             rtx set;
+             if (MAY_HAVE_DEBUG_INSNS
+                 && (set = single_set (insn)) != NULL_RTX
+                 && is_dead_reg (SET_DEST (set), counts)
+                 /* Used at least once in some DEBUG_INSN.  */
+                 && counts[REGNO (SET_DEST (set)) + nreg] > 0
+                 /* And set exactly once.  */
+                 && counts[REGNO (SET_DEST (set)) + nreg * 2] == 1
+                 && !side_effects_p (SET_SRC (set))
+                 && asm_noperands (PATTERN (insn)) < 0)
+               {
+                 rtx dval, bind;
+
+                 /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL).  */
+                 dval = make_debug_expr_from_rtl (SET_DEST (set));
+
+                 /* Emit a debug bind insn before the insn in which
+                    reg dies.  */
+                 bind = gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)),
+                                              DEBUG_EXPR_TREE_DECL (dval),
+                                              SET_SRC (set),
+                                              VAR_INIT_STATUS_INITIALIZED);
+                 count_reg_usage (bind, counts + nreg, NULL_RTX, 1);
+
+                 bind = emit_debug_insn_before (bind, insn);
+                 df_insn_rescan (bind);
+
+                 if (replacements == NULL)
+                   replacements = XCNEWVEC (rtx, nreg);
+                 replacements[REGNO (SET_DEST (set))] = dval;
+               }
+
+             count_reg_usage (insn, counts, NULL_RTX, -1);
+             ndead++;
+           }
          delete_insn_and_edges (insn);
-         ndead++;
        }
     }
 
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      struct dead_debug_insn_data ddid;
+      ddid.counts = counts;
+      ddid.replacements = replacements;
+      for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
+       if (DEBUG_INSN_P (insn))
+         {
+           /* If this debug insn references a dead register that wasn't replaced
+              with an DEBUG_EXPR, reset the DEBUG_INSN.  */
+           ddid.seen_repl = false;
+           if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn),
+                             is_dead_debug_insn, &ddid))
+             {
+               INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+               df_insn_rescan (insn);
+             }
+           else if (ddid.seen_repl)
+             {
+               INSN_VAR_LOCATION_LOC (insn)
+                 = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
+                                            NULL_RTX, replace_dead_reg,
+                                            replacements);
+               df_insn_rescan (insn);
+             }
+         }
+      free (replacements);
+    }
+
   if (dump_file && ndead)
     fprintf (dump_file, "Deleted %i trivially dead insns\n",
             ndead);
@@ -6780,7 +7002,7 @@ cse_change_cc_mode (rtx *loc, void *data)
       && GET_MODE (*loc) != GET_MODE (args->newreg))
     {
       validate_change (args->insn, loc, args->newreg, 1);
-      
+
       return -1;
     }
   return 0;
@@ -6800,10 +7022,10 @@ cse_change_cc_mode_insn (rtx insn, rtx newreg)
 
   args.insn = insn;
   args.newreg = newreg;
-  
+
   for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
   for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, &args);
-  
+
   /* If the following assertion was triggered, there is most probably
      something wrong with the cc_modes_compatible back end function.
      CC modes only can be considered compatible if the insn - with the mode
@@ -6922,7 +7144,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
                                       XEXP (SET_SRC (set), 0))
                       && rtx_equal_p (XEXP (cc_src, 1),
                                       XEXP (SET_SRC (set), 1)))
-                          
+
                {
                  comp_mode = targetm.cc_modes_compatible (mode, set_mode);
                  if (comp_mode != VOIDmode
@@ -7179,8 +7401,8 @@ struct rtl_opt_pass pass_cse =
  {
   RTL_PASS,
   "cse1",                               /* name */
-  gate_handle_cse,                      /* gate */   
-  rest_of_handle_cse,                  /* execute */       
+  gate_handle_cse,                      /* gate */
+  rest_of_handle_cse,                  /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
@@ -7242,8 +7464,8 @@ struct rtl_opt_pass pass_cse2 =
  {
   RTL_PASS,
   "cse2",                               /* name */
-  gate_handle_cse2,                     /* gate */   
-  rest_of_handle_cse2,                 /* execute */       
+  gate_handle_cse2,                     /* gate */
+  rest_of_handle_cse2,                 /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
@@ -7303,8 +7525,8 @@ struct rtl_opt_pass pass_cse_after_global_opts =
  {
   RTL_PASS,
   "cse_local",                          /* name */
-  gate_handle_cse_after_global_opts,    /* gate */   
-  rest_of_handle_cse_after_global_opts, /* execute */       
+  gate_handle_cse_after_global_opts,    /* gate */
+  rest_of_handle_cse_after_global_opts, /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */