re PR debug/52983 (internal compiler error: in df_uses_record, at df-scan.c:3243)
authorAlexandre Oliva <aoliva@redhat.com>
Thu, 2 Aug 2012 00:34:11 +0000 (00:34 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Thu, 2 Aug 2012 00:34:11 +0000 (00:34 +0000)
PR debug/52983
* valtrack.h, valtrack.c: New.
* Makefile.in (VALTRACK_H): New.
(OBJS): Add valtrack.o.
(valtrack.o): New.
(cselib.o, dce.o, df-problems.o, combine.o): Add VALTRACK_H.
* combine.c: Include valtrack.h.
(make_compound_operation): Publish.
(cleanup_auto_inc_dec): Move to valtrack.c.
(struct rtx_subst_pair, propagate_for_debug_subst): Likewise.
(propagate_for_debug): Likewise.  Add this_basic_block parameter.
Adjust all callers.
* cselib.c: Include valtrack.h.
* dce.c: Likewise.
* df-problems.c: Likewise.
(dead_debug_init, dead_debug_reset_uses): Move to valtrack.c.
(dead_debug_finish, dead_debug_add): Likewise.
(dead_debug_insert_temp): Likewise.
* df.h (struct dead_debug_use): Move to valtrack.h.
(struct dead_debug, enum debug_temp_where): Likewise.
(dead_debug_init, dead_debug_reset_uses): Move to valtrack.h.
(dead_debug_finish, dead_debug_add): Likewise.
(dead_debug_insert_temp): Likewise.
* rtl.h (make_compound_operation): Declare.

From-SVN: r190061

gcc/ChangeLog
gcc/Makefile.in
gcc/combine.c
gcc/cselib.c
gcc/dce.c
gcc/df-problems.c
gcc/df.h
gcc/rtl.h
gcc/valtrack.c [new file with mode: 0644]
gcc/valtrack.h [new file with mode: 0644]

index 4d5bf54..ea9a7b1 100644 (file)
@@ -1,3 +1,30 @@
+2012-08-01  Alexandre Oliva  <aoliva@redhat.com>
+
+       PR debug/52983
+       * valtrack.h, valtrack.c: New.
+       * Makefile.in (VALTRACK_H): New.
+       (OBJS): Add valtrack.o.
+       (valtrack.o): New.
+       (cselib.o, dce.o, df-problems.o, combine.o): Add VALTRACK_H.
+       * combine.c: Include valtrack.h.
+       (make_compound_operation): Publish.
+       (cleanup_auto_inc_dec): Move to valtrack.c.
+       (struct rtx_subst_pair, propagate_for_debug_subst): Likewise.
+       (propagate_for_debug): Likewise.  Add this_basic_block parameter.
+       Adjust all callers.
+       * cselib.c: Include valtrack.h.
+       * dce.c: Likewise.
+       * df-problems.c: Likewise.
+       (dead_debug_init, dead_debug_reset_uses): Move to valtrack.c.
+       (dead_debug_finish, dead_debug_add): Likewise.
+       (dead_debug_insert_temp): Likewise.
+       * df.h (struct dead_debug_use): Move to valtrack.h.
+       (struct dead_debug, enum debug_temp_where): Likewise.
+       (dead_debug_init, dead_debug_reset_uses): Move to valtrack.h.
+       (dead_debug_finish, dead_debug_add): Likewise.
+       (dead_debug_insert_temp): Likewise.
+       * rtl.h (make_compound_operation): Declare.
+
 2012-08-01  Catherine Moore  <clm@codesourcery.com>
            Sandra Loosemore  <sandra@codesourcery.com>
 
index 7633282..b2c4d4f 100644 (file)
@@ -904,6 +904,7 @@ CGRAPH_H = cgraph.h $(VEC_H) $(TREE_H) $(BASIC_BLOCK_H) $(FUNCTION_H) \
        cif-code.def ipa-ref.h ipa-ref-inline.h $(LINKER_PLUGIN_API_H)
 DF_H = df.h $(BITMAP_H) $(REGSET_H) sbitmap.h $(BASIC_BLOCK_H) \
        alloc-pool.h $(TIMEVAR_H)
+VALTRACK_H = valtrack.h $(BITMAP_H) $(DF_H) $(RTL_H) $(BASIC_BLOCK_H)
 RESOURCE_H = resource.h hard-reg-set.h $(DF_H)
 DDG_H = ddg.h sbitmap.h $(DF_H)
 GCC_H = gcc.h version.h $(DIAGNOSTIC_CORE_H)
@@ -1447,6 +1448,7 @@ OBJS = \
        tree-vectorizer.o \
        tree-vrp.o \
        tree.o \
+       valtrack.o \
        value-prof.o \
        var-tracking.o \
        varasm.o \
@@ -2947,7 +2949,7 @@ cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
    $(DF_H) $(DBGCNT_H)
 dce.o : dce.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) $(EXCEPT_H) $(DF_H) cselib.h \
-   $(DBGCNT_H) dce.h $(TREE_PASS_H) $(DBGCNT_H) $(TM_P_H) \
+   $(DBGCNT_H) dce.h $(VALTRACK_H) $(TREE_PASS_H) $(DBGCNT_H) $(TM_P_H) \
    $(EMIT_RTL_H)
 dse.o : dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(TM_P_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
@@ -3039,7 +3041,7 @@ df-core.o : df-core.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
 df-problems.o : df-problems.c $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h $(TM_H) \
    $(RTL_H) insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \
    hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) $(BITMAP_H) sbitmap.h $(TIMEVAR_H) \
-   $(TM_P_H) $(TARGET_H) $(FLAGS_H) $(EXCEPT_H) dce.h vecprim.h
+   $(TM_P_H) $(TARGET_H) $(FLAGS_H) $(EXCEPT_H) dce.h vecprim.h $(VALTRACK_H)
 df-scan.o : df-scan.c $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h $(TM_H) $(RTL_H) \
    insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \
    hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) $(BITMAP_H) sbitmap.h \
@@ -3048,6 +3050,8 @@ df-scan.o : df-scan.c $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h $(TM_H) $(R
 regstat.o : regstat.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TM_P_H) $(FLAGS_H) $(REGS_H) $(EXCEPT_H) hard-reg-set.h \
    $(BASIC_BLOCK_H) $(TIMEVAR_H) $(DF_H)
+valtrack.o : valtrack.c $(VALTRACK_H) $(CONFIG_H) $(SYSTEM_H) \
+   coretypes.h $(TM_H) $(FUNCTION_H) $(REGS_H) $(EMIT_RTL_H)
 var-tracking.o : var-tracking.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \
    $(BASIC_BLOCK_H) bitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
@@ -3144,9 +3148,10 @@ et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 combine.o : combine.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) $(FUNCTION_H) insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) \
    rtlhooks-def.h $(BASIC_BLOCK_H) $(RECOG_H) hard-reg-set.h \
-   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(TREE_H) $(TARGET_H) $(PARAMS_H) $(OPTABS_H) \
-   insn-codes.h $(TREE_PASS_H) $(DF_H) vecprim.h $(CGRAPH_H) \
-   $(OBSTACK_H)
+   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(TREE_H) $(TARGET_H) \
+   output.h $(PARAMS_H) $(OPTABS_H) \
+   insn-codes.h $(TREE_PASS_H) $(DF_H) $(VALTRACK_H) \
+   vecprim.h $(CGRAPH_H) $(OBSTACK_H)
 reginfo.o : reginfo.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) addresses.h $(REGS_H) \
    insn-config.h $(RECOG_H) reload.h $(DIAGNOSTIC_CORE_H) \
index a07c046..dbc6ff6 100644 (file)
@@ -100,6 +100,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "tree-pass.h"
 #include "df.h"
+#include "valtrack.h"
 #include "cgraph.h"
 #include "obstack.h"
 
@@ -424,7 +425,6 @@ static const_rtx expand_field_assignment (const_rtx);
 static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
                            rtx, unsigned HOST_WIDE_INT, int, int, int);
 static rtx extract_left_shift (rtx, int);
-static rtx make_compound_operation (rtx, enum rtx_code);
 static int get_pos_from_mask (unsigned HOST_WIDE_INT,
                              unsigned HOST_WIDE_INT *);
 static rtx canon_reg_for_combine (rtx, rtx);
@@ -2357,161 +2357,6 @@ reg_subword_p (rtx x, rtx reg)
         && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
 }
 
-#ifdef AUTO_INC_DEC
-/* Replace auto-increment addressing modes with explicit operations to access
-   the same addresses without modifying the corresponding registers.  */
-
-static rtx
-cleanup_auto_inc_dec (rtx src, enum machine_mode mem_mode)
-{
-  rtx x = src;
-  const RTX_CODE code = GET_CODE (x);
-  int i;
-  const char *fmt;
-
-  switch (code)
-    {
-    case REG:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_FIXED:
-    case CONST_VECTOR:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-    case SCRATCH:
-      /* SCRATCH must be shared because they represent distinct values.  */
-      return x;
-    case CLOBBER:
-      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
-       return x;
-      break;
-
-    case CONST:
-      if (shared_const_p (x))
-       return x;
-      break;
-
-    case MEM:
-      mem_mode = GET_MODE (x);
-      break;
-
-    case PRE_INC:
-    case PRE_DEC:
-      gcc_assert (mem_mode != VOIDmode && mem_mode != BLKmode);
-      return gen_rtx_PLUS (GET_MODE (x),
-                          cleanup_auto_inc_dec (XEXP (x, 0), mem_mode),
-                          GEN_INT (code == PRE_INC
-                                   ? GET_MODE_SIZE (mem_mode)
-                                   : -GET_MODE_SIZE (mem_mode)));
-
-    case POST_INC:
-    case POST_DEC:
-    case PRE_MODIFY:
-    case POST_MODIFY:
-      return cleanup_auto_inc_dec (code == PRE_MODIFY
-                                  ? XEXP (x, 1) : XEXP (x, 0),
-                                  mem_mode);
-
-    default:
-      break;
-    }
-
-  /* Copy the various flags, fields, and other information.  We assume
-     that all fields need copying, and then clear the fields that should
-     not be copied.  That is the sensible default behavior, and forces
-     us to explicitly document why we are *not* copying a flag.  */
-  x = shallow_copy_rtx (x);
-
-  /* We do not copy the USED flag, which is used as a mark bit during
-     walks over the RTL.  */
-  RTX_FLAG (x, used) = 0;
-
-  /* We do not copy FRAME_RELATED for INSNs.  */
-  if (INSN_P (x))
-    RTX_FLAG (x, frame_related) = 0;
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    if (fmt[i] == 'e')
-      XEXP (x, i) = cleanup_auto_inc_dec (XEXP (x, i), mem_mode);
-    else if (fmt[i] == 'E' || fmt[i] == 'V')
-      {
-       int j;
-       XVEC (x, i) = rtvec_alloc (XVECLEN (x, i));
-       for (j = 0; j < XVECLEN (x, i); j++)
-         XVECEXP (x, i, j)
-           = cleanup_auto_inc_dec (XVECEXP (src, i, j), mem_mode);
-      }
-
-  return x;
-}
-#endif
-
-/* Auxiliary data structure for propagate_for_debug_stmt.  */
-
-struct rtx_subst_pair
-{
-  rtx to;
-  bool adjusted;
-};
-
-/* DATA points to an rtx_subst_pair.  Return the value that should be
-   substituted.  */
-
-static rtx
-propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
-{
-  struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
-
-  if (!rtx_equal_p (from, old_rtx))
-    return NULL_RTX;
-  if (!pair->adjusted)
-    {
-      pair->adjusted = true;
-#ifdef AUTO_INC_DEC
-      pair->to = cleanup_auto_inc_dec (pair->to, VOIDmode);
-#else
-      pair->to = copy_rtx (pair->to);
-#endif
-      pair->to = make_compound_operation (pair->to, SET);
-      return pair->to;
-    }
-  return copy_rtx (pair->to);
-}
-
-/* Replace all the occurrences of DEST with SRC in DEBUG_INSNs between INSN
-   and LAST, not including INSN, but including LAST.  Also stop at the end
-   of THIS_BASIC_BLOCK.  */
-
-static void
-propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src)
-{
-  rtx next, loc, end = NEXT_INSN (BB_END (this_basic_block));
-
-  struct rtx_subst_pair p;
-  p.to = src;
-  p.adjusted = false;
-
-  next = NEXT_INSN (insn);
-  last = NEXT_INSN (last);
-  while (next != last && next != end)
-    {
-      insn = next;
-      next = NEXT_INSN (insn);
-      if (DEBUG_INSN_P (insn))
-       {
-         loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
-                                        dest, propagate_for_debug_subst, &p);
-         if (loc == INSN_VAR_LOCATION_LOC (insn))
-           continue;
-         INSN_VAR_LOCATION_LOC (insn) = loc;
-         df_insn_rescan (insn);
-       }
-    }
-}
-
 /* Delete the unconditional jump INSN and adjust the CFG correspondingly.
    Note that the INSN should be deleted *after* removing dead edges, so
    that the kept edge is the fallthrough edge for a (set (pc) (pc))
@@ -3971,7 +3816,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
                   i2src while its original mode is temporarily
                   restored, and then clear i2scratch so that we don't
                   do it again later.  */
-               propagate_for_debug (i2, last_combined_insn, reg, i2src);
+               propagate_for_debug (i2, last_combined_insn, reg, i2src,
+                                    this_basic_block);
                i2scratch = false;
                /* Put back the new mode.  */
                adjust_reg_mode (reg, new_mode);
@@ -4005,10 +3851,12 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
                   with this copy we have created; then, replace the
                   copy with the SUBREG of the original shared reg,
                   once again changed to the new mode.  */
-               propagate_for_debug (first, last, reg, tempreg);
+               propagate_for_debug (first, last, reg, tempreg,
+                                    this_basic_block);
                adjust_reg_mode (reg, new_mode);
                propagate_for_debug (first, last, tempreg,
-                                    lowpart_subreg (old_mode, reg, new_mode));
+                                    lowpart_subreg (old_mode, reg, new_mode),
+                                    this_basic_block);
              }
          }
     }
@@ -4220,14 +4068,16 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
     if (newi2pat)
       {
        if (MAY_HAVE_DEBUG_INSNS && i2scratch)
-         propagate_for_debug (i2, last_combined_insn, i2dest, i2src);
+         propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
+                              this_basic_block);
        INSN_CODE (i2) = i2_code_number;
        PATTERN (i2) = newi2pat;
       }
     else
       {
        if (MAY_HAVE_DEBUG_INSNS && i2src)
-         propagate_for_debug (i2, last_combined_insn, i2dest, i2src);
+         propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
+                              this_basic_block);
        SET_INSN_DELETED (i2);
       }
 
@@ -4236,7 +4086,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
        LOG_LINKS (i1) = NULL;
        REG_NOTES (i1) = 0;
        if (MAY_HAVE_DEBUG_INSNS)
-         propagate_for_debug (i1, last_combined_insn, i1dest, i1src);
+         propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
+                              this_basic_block);
        SET_INSN_DELETED (i1);
       }
 
@@ -4245,7 +4096,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
        LOG_LINKS (i0) = NULL;
        REG_NOTES (i0) = 0;
        if (MAY_HAVE_DEBUG_INSNS)
-         propagate_for_debug (i0, last_combined_insn, i0dest, i0src);
+         propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
+                              this_basic_block);
        SET_INSN_DELETED (i0);
       }
 
@@ -7596,7 +7448,7 @@ extract_left_shift (rtx x, int count)
    being kludges), it is MEM.  When processing the arguments of a comparison
    or a COMPARE against zero, it is COMPARE.  */
 
-static rtx
+rtx
 make_compound_operation (rtx x, enum rtx_code in_code)
 {
   enum rtx_code code = GET_CODE (x);
index ece2240..88a74b4 100644 (file)
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "hashtab.h"
 #include "dumpfile.h"
 #include "cselib.h"
+#include "valtrack.h"
 #include "params.h"
 #include "alloc-pool.h"
 #include "target.h"
index c72cdd1..c951865 100644 (file)
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "cselib.h"
 #include "dce.h"
+#include "valtrack.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
 #include "tm_p.h"
index d572b0f..8699304 100644 (file)
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "dce.h"
 #include "vecprim.h"
+#include "valtrack.h"
 #include "dumpfile.h"
 
 /* Note that turning REG_DEAD_DEBUGGING on will cause
@@ -3047,312 +3048,6 @@ df_create_unused_note (rtx insn, df_ref def,
 }
 
 
-/* Initialize DEBUG to an empty list, and clear USED, if given.  */
-void
-dead_debug_init (struct dead_debug *debug, bitmap used)
-{
-  debug->head = NULL;
-  debug->used = used;
-  debug->to_rescan = NULL;
-  if (used)
-    bitmap_clear (used);
-}
-
-/* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of
-   each reset insn.  DEBUG is not otherwise modified.  If HEAD is
-   DEBUG->head, DEBUG->head will be set to NULL at the end.
-   Otherwise, entries from DEBUG->head that pertain to reset insns
-   will be removed, and only then rescanned.  */
-
-static void
-dead_debug_reset_uses (struct dead_debug *debug, struct dead_debug_use *head)
-{
-  bool got_head = (debug->head == head);
-  bitmap rescan;
-  struct dead_debug_use **tailp = &debug->head;
-  struct dead_debug_use *cur;
-  bitmap_iterator bi;
-  unsigned int uid;
-
-  if (got_head)
-    rescan = NULL;
-  else
-    rescan = BITMAP_ALLOC (NULL);
-
-  while (head)
-    {
-      struct dead_debug_use *next = head->next;
-      rtx insn;
-
-      insn = DF_REF_INSN (head->use);
-      if (!next || DF_REF_INSN (next->use) != insn)
-       {
-         INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
-         if (got_head)
-           df_insn_rescan_debug_internal (insn);
-         else
-           bitmap_set_bit (rescan, INSN_UID (insn));
-         if (debug->to_rescan)
-           bitmap_clear_bit (debug->to_rescan, INSN_UID (insn));
-       }
-      XDELETE (head);
-      head = next;
-    }
-
-  if (got_head)
-    {
-      debug->head = NULL;
-      return;
-    }
-
-  while ((cur = *tailp))
-    if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use))))
-      {
-       *tailp = cur->next;
-       XDELETE (cur);
-      }
-    else
-      tailp = &cur->next;
-
-  EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi)
-    {
-      struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
-      if (insn_info)
-       df_insn_rescan_debug_internal (insn_info->insn);
-    }
-
-  BITMAP_FREE (rescan);
-}
-
-/* Reset all debug insns with pending uses.  Release the bitmap in it,
-   unless it is USED.  USED must be the same bitmap passed to
-   dead_debug_init.  */
-void
-dead_debug_finish (struct dead_debug *debug, bitmap used)
-{
-  if (debug->used != used)
-    BITMAP_FREE (debug->used);
-
-  dead_debug_reset_uses (debug, debug->head);
-
-  if (debug->to_rescan)
-    {
-      bitmap_iterator bi;
-      unsigned int uid;
-
-      EXECUTE_IF_SET_IN_BITMAP (debug->to_rescan, 0, uid, bi)
-       {
-         struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
-         if (insn_info)
-           df_insn_rescan (insn_info->insn);
-       }
-      BITMAP_FREE (debug->to_rescan);
-    }
-}
-
-/* Add USE to DEBUG.  It must be a dead reference to UREGNO in a debug
-   insn.  Create a bitmap for DEBUG as needed.  */
-void
-dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno)
-{
-  struct dead_debug_use *newddu = XNEW (struct dead_debug_use);
-
-  newddu->use = use;
-  newddu->next = debug->head;
-  debug->head = newddu;
-
-  if (!debug->used)
-    debug->used = BITMAP_ALLOC (NULL);
-
-  /* ??? If we dealt with split multi-registers below, we should set
-     all registers for the used mode in case of hardware
-     registers.  */
-  bitmap_set_bit (debug->used, uregno);
-}
-
-/* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
-   before or after INSN (depending on WHERE), that binds a debug temp
-   to the widest-mode use of UREGNO, if WHERE is *_WITH_REG, or the
-   value stored in UREGNO by INSN otherwise, and replace all uses of
-   UREGNO in DEBUG with uses of the debug temp.  INSN must be where
-   UREGNO dies, if WHERE is *_BEFORE_*, or where it is set otherwise.
-   Return the number of debug insns emitted.  */
-int
-dead_debug_insert_temp (struct dead_debug *debug, unsigned int uregno,
-                       rtx insn, enum debug_temp_where where)
-{
-  struct dead_debug_use **tailp = &debug->head;
-  struct dead_debug_use *cur;
-  struct dead_debug_use *uses = NULL;
-  struct dead_debug_use **usesp = &uses;
-  rtx reg = NULL;
-  rtx breg;
-  rtx dval;
-  rtx bind;
-
-  if (!debug->used || !bitmap_clear_bit (debug->used, uregno))
-    return 0;
-
-  /* Move all uses of uregno from debug->head to uses, setting mode to
-     the widest referenced mode.  */
-  while ((cur = *tailp))
-    {
-      if (DF_REF_REGNO (cur->use) == uregno)
-       {
-         *usesp = cur;
-         usesp = &cur->next;
-         *tailp = cur->next;
-         cur->next = NULL;
-         if (!reg
-             || (GET_MODE_BITSIZE (GET_MODE (reg))
-                 < GET_MODE_BITSIZE (GET_MODE (*DF_REF_REAL_LOC (cur->use)))))
-           reg = *DF_REF_REAL_LOC (cur->use);
-       }
-      else
-       tailp = &(*tailp)->next;
-    }
-
-  /* We may have dangling bits in debug->used for registers that were part
-     of a multi-register use, one component of which has been reset.  */
-  if (reg == NULL)
-    {
-      gcc_checking_assert (!uses);
-      return 0;
-    }
-
-  gcc_checking_assert (uses);
-
-  breg = reg;
-  /* Recover the expression INSN stores in REG.  */
-  if (where == DEBUG_TEMP_BEFORE_WITH_VALUE)
-    {
-      rtx set = single_set (insn);
-      rtx dest, src;
-
-      if (set)
-       {
-         dest = SET_DEST (set);
-         src = SET_SRC (set);
-         /* Lose if the REG-setting insn is a CALL.  */
-         if (GET_CODE (src) == CALL)
-           {
-             while (uses)
-               {
-                 cur = uses->next;
-                 XDELETE (uses);
-                 uses = cur;
-               }
-             return 0;
-           }
-       }
-
-      /* ??? Should we try to extract it from a PARALLEL?  */
-      if (!set)
-       breg = NULL;
-      /* Cool, it's the same REG, we can use SRC.  */
-      else if (dest == reg)
-       breg = copy_rtx (src);
-      else if (REG_P (dest))
-       {
-         /* Hmm...  Something's fishy, we should be setting REG here.  */
-         if (REGNO (dest) != REGNO (reg))
-           breg = NULL;
-         /* If we're not overwriting all the hardware registers that
-            setting REG in its mode would, we won't know what to bind
-            the debug temp to.  ??? We could bind the debug_expr to a
-            CONCAT or PARALLEL with the split multi-registers, and
-            replace them as we found the corresponding sets.  */
-         else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
-                  && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
-                      != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
-           breg = NULL;
-         /* Ok, it's the same (hardware) REG, but with a different
-            mode, so SUBREG it.  */
-         else
-           breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src),
-                                  GET_MODE (dest));
-       }
-      else if (GET_CODE (dest) == SUBREG)
-       {
-         /* We should be setting REG here.  Lose.  */
-         if (REGNO (SUBREG_REG (dest)) != REGNO (reg))
-           breg = NULL;
-         /* Lose if we're setting something other than the lowpart of
-            REG.  */
-         else if (!subreg_lowpart_p (dest))
-           breg = NULL;
-         /* If we're not overwriting all the hardware registers that
-            setting REG in its mode would, we won't know what to bind
-            the debug temp to.  */
-         else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
-                  && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
-                      != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
-           breg = NULL;
-         /* Yay, we can use SRC, just adjust its mode.  */
-         else
-           breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src),
-                                  GET_MODE (dest));
-       }
-      /* Oh well, we're out of luck.  */
-      else
-       breg = NULL;
-
-      /* We couldn't figure out the value stored in REG, so reset all
-        of its pending debug uses.  */
-      if (!breg)
-       {
-         dead_debug_reset_uses (debug, uses);
-         return 0;
-       }
-    }
-
-  /* If there's a single (debug) use of an otherwise unused REG, and
-     the debug use is not part of a larger expression, then it
-     probably doesn't make sense to introduce a new debug temp.  */
-  if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
-    {
-      rtx next = DF_REF_INSN (uses->use);
-
-      if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
-       {
-         XDELETE (uses);
-         return 0;
-       }
-    }
-
-  /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL).  */
-  dval = make_debug_expr_from_rtl (reg);
-
-  /* Emit a debug bind insn before the insn in which reg dies.  */
-  bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
-                              DEBUG_EXPR_TREE_DECL (dval), breg,
-                              VAR_INIT_STATUS_INITIALIZED);
-
-  if (where == DEBUG_TEMP_AFTER_WITH_REG)
-    bind = emit_debug_insn_after (bind, insn);
-  else
-    bind = emit_debug_insn_before (bind, insn);
-  df_insn_rescan (bind);
-
-  /* Adjust all uses.  */
-  while ((cur = uses))
-    {
-      if (GET_MODE (*DF_REF_REAL_LOC (cur->use)) == GET_MODE (reg))
-       *DF_REF_REAL_LOC (cur->use) = dval;
-      else
-       *DF_REF_REAL_LOC (cur->use)
-         = gen_lowpart_SUBREG (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval);
-      /* ??? Should we simplify subreg of subreg?  */
-      if (debug->to_rescan == NULL)
-       debug->to_rescan = BITMAP_ALLOC (NULL);
-      bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
-      uses = cur->next;
-      XDELETE (cur);
-    }
-
-  return 1;
-}
-
 /* Recompute the REG_DEAD and REG_UNUSED notes and compute register
    info: lifetime, bb, and number of defs and uses for basic block
    BB.  The three bitvectors are scratch regs used here.  */
index 1b4882d..e59ae12 100644 (file)
--- a/gcc/df.h
+++ b/gcc/df.h
@@ -1101,46 +1101,4 @@ extern void union_defs (df_ref, struct web_entry *,
                        unsigned int *used, struct web_entry *,
                        bool (*fun) (struct web_entry *, struct web_entry *));
 
-/* Debug uses of dead regs.  */
-
-/* Node of a linked list of uses of dead REGs in debug insns.  */
-struct dead_debug_use
-{
-  df_ref use;
-  struct dead_debug_use *next;
-};
-
-/* Linked list of the above, with a bitmap of the REGs in the
-   list.  */
-struct dead_debug
-{
-  struct dead_debug_use *head;
-  bitmap used;
-  bitmap to_rescan;
-};
-
-/* This type controls the behavior of dead_debug_insert_temp WRT
-   UREGNO and INSN.  */
-enum debug_temp_where
-  {
-    /* Bind a newly-created debug temporary to a REG for UREGNO, and
-       insert the debug insn before INSN.  REG is expected to die at
-       INSN.  */
-    DEBUG_TEMP_BEFORE_WITH_REG = -1,
-    /* Bind a newly-created debug temporary to the value INSN stores
-       in REG, and insert the debug insn before INSN.  */
-    DEBUG_TEMP_BEFORE_WITH_VALUE = 0,
-    /* Bind a newly-created debug temporary to a REG for UREGNO, and
-       insert the debug insn after INSN.  REG is expected to be set at
-       INSN.  */
-    DEBUG_TEMP_AFTER_WITH_REG = 1
-  };
-
-extern void dead_debug_init (struct dead_debug *, bitmap);
-extern void dead_debug_finish (struct dead_debug *, bitmap);
-extern void dead_debug_add (struct dead_debug *, df_ref, unsigned int);
-extern int dead_debug_insert_temp (struct dead_debug *,
-                                  unsigned int uregno, rtx insn,
-                                  enum debug_temp_where);
-
 #endif /* GCC_DF_H */
index b611fbe..82c3e59 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2460,6 +2460,7 @@ extern unsigned int extended_count (const_rtx, enum machine_mode, int);
 extern rtx remove_death (unsigned int, rtx);
 extern void dump_combine_stats (FILE *);
 extern void dump_combine_total_stats (FILE *);
+extern rtx make_compound_operation (rtx, enum rtx_code);
 
 /* In cfgcleanup.c  */
 extern void delete_dead_jumptables (void);
diff --git a/gcc/valtrack.c b/gcc/valtrack.c
new file mode 100644 (file)
index 0000000..3e03599
--- /dev/null
@@ -0,0 +1,492 @@
+/* Infrastructure for tracking user variable locations and values
+   throughout compilation.
+   Copyright (C) 2010, 2011, 2012  Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.com>.
+
+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 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+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 COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "valtrack.h"
+#include "function.h"
+#include "regs.h"
+#include "emit-rtl.h"
+
+/* Replace auto-increment addressing modes with explicit operations to access
+   the same addresses without modifying the corresponding registers.  */
+
+#ifdef AUTO_INC_DEC
+static rtx
+cleanup_auto_inc_dec (rtx src, enum machine_mode mem_mode ATTRIBUTE_UNUSED)
+{
+  rtx x = src;
+  const RTX_CODE code = GET_CODE (x);
+  int i;
+  const char *fmt;
+
+  switch (code)
+    {
+    case REG:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST_FIXED:
+    case CONST_VECTOR:
+    case SYMBOL_REF:
+    case CODE_LABEL:
+    case PC:
+    case CC0:
+    case SCRATCH:
+      /* SCRATCH must be shared because they represent distinct values.  */
+      return x;
+    case CLOBBER:
+      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+       return x;
+      break;
+
+    case CONST:
+      if (shared_const_p (x))
+       return x;
+      break;
+
+    case MEM:
+      mem_mode = GET_MODE (x);
+      break;
+
+    case PRE_INC:
+    case PRE_DEC:
+      gcc_assert (mem_mode != VOIDmode && mem_mode != BLKmode);
+      return gen_rtx_PLUS (GET_MODE (x),
+                          cleanup_auto_inc_dec (XEXP (x, 0), mem_mode),
+                          GEN_INT (code == PRE_INC
+                                   ? GET_MODE_SIZE (mem_mode)
+                                   : -GET_MODE_SIZE (mem_mode)));
+
+    case POST_INC:
+    case POST_DEC:
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      return cleanup_auto_inc_dec (code == PRE_MODIFY
+                                  ? XEXP (x, 1) : XEXP (x, 0),
+                                  mem_mode);
+
+    default:
+      break;
+    }
+
+  /* Copy the various flags, fields, and other information.  We assume
+     that all fields need copying, and then clear the fields that should
+     not be copied.  That is the sensible default behavior, and forces
+     us to explicitly document why we are *not* copying a flag.  */
+  x = shallow_copy_rtx (x);
+
+  /* We do not copy the USED flag, which is used as a mark bit during
+     walks over the RTL.  */
+  RTX_FLAG (x, used) = 0;
+
+  /* We do not copy FRAME_RELATED for INSNs.  */
+  if (INSN_P (x))
+    RTX_FLAG (x, frame_related) = 0;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      XEXP (x, i) = cleanup_auto_inc_dec (XEXP (x, i), mem_mode);
+    else if (fmt[i] == 'E' || fmt[i] == 'V')
+      {
+       int j;
+       XVEC (x, i) = rtvec_alloc (XVECLEN (x, i));
+       for (j = 0; j < XVECLEN (x, i); j++)
+         XVECEXP (x, i, j)
+           = cleanup_auto_inc_dec (XVECEXP (src, i, j), mem_mode);
+      }
+
+  return x;
+}
+#endif
+
+/* Auxiliary data structure for propagate_for_debug_stmt.  */
+
+struct rtx_subst_pair
+{
+  rtx to;
+  bool adjusted;
+};
+
+/* DATA points to an rtx_subst_pair.  Return the value that should be
+   substituted.  */
+
+static rtx
+propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
+{
+  struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
+
+  if (!rtx_equal_p (from, old_rtx))
+    return NULL_RTX;
+  if (!pair->adjusted)
+    {
+      pair->adjusted = true;
+#ifdef AUTO_INC_DEC
+      pair->to = cleanup_auto_inc_dec (pair->to, VOIDmode);
+#else
+      pair->to = copy_rtx (pair->to);
+#endif
+      pair->to = make_compound_operation (pair->to, SET);
+      return pair->to;
+    }
+  return copy_rtx (pair->to);
+}
+
+/* Replace all the occurrences of DEST with SRC in DEBUG_INSNs between INSN
+   and LAST, not including INSN, but including LAST.  Also stop at the end
+   of THIS_BASIC_BLOCK.  */
+
+void
+propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src,
+                    basic_block this_basic_block)
+{
+  rtx next, loc, end = NEXT_INSN (BB_END (this_basic_block));
+
+  struct rtx_subst_pair p;
+  p.to = src;
+  p.adjusted = false;
+
+  next = NEXT_INSN (insn);
+  last = NEXT_INSN (last);
+  while (next != last && next != end)
+    {
+      insn = next;
+      next = NEXT_INSN (insn);
+      if (DEBUG_INSN_P (insn))
+       {
+         loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
+                                        dest, propagate_for_debug_subst, &p);
+         if (loc == INSN_VAR_LOCATION_LOC (insn))
+           continue;
+         INSN_VAR_LOCATION_LOC (insn) = loc;
+         df_insn_rescan (insn);
+       }
+    }
+}
+
+/* Initialize DEBUG to an empty list, and clear USED, if given.  */
+void
+dead_debug_init (struct dead_debug *debug, bitmap used)
+{
+  debug->head = NULL;
+  debug->used = used;
+  debug->to_rescan = NULL;
+  if (used)
+    bitmap_clear (used);
+}
+
+/* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of
+   each reset insn.  DEBUG is not otherwise modified.  If HEAD is
+   DEBUG->head, DEBUG->head will be set to NULL at the end.
+   Otherwise, entries from DEBUG->head that pertain to reset insns
+   will be removed, and only then rescanned.  */
+
+static void
+dead_debug_reset_uses (struct dead_debug *debug, struct dead_debug_use *head)
+{
+  bool got_head = (debug->head == head);
+  bitmap rescan;
+  struct dead_debug_use **tailp = &debug->head;
+  struct dead_debug_use *cur;
+  bitmap_iterator bi;
+  unsigned int uid;
+
+  if (got_head)
+    rescan = NULL;
+  else
+    rescan = BITMAP_ALLOC (NULL);
+
+  while (head)
+    {
+      struct dead_debug_use *next = head->next;
+      rtx insn;
+
+      insn = DF_REF_INSN (head->use);
+      if (!next || DF_REF_INSN (next->use) != insn)
+       {
+         INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+         if (got_head)
+           df_insn_rescan_debug_internal (insn);
+         else
+           bitmap_set_bit (rescan, INSN_UID (insn));
+         if (debug->to_rescan)
+           bitmap_clear_bit (debug->to_rescan, INSN_UID (insn));
+       }
+      XDELETE (head);
+      head = next;
+    }
+
+  if (got_head)
+    {
+      debug->head = NULL;
+      return;
+    }
+
+  while ((cur = *tailp))
+    if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use))))
+      {
+       *tailp = cur->next;
+       XDELETE (cur);
+      }
+    else
+      tailp = &cur->next;
+
+  EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi)
+    {
+      struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
+      if (insn_info)
+       df_insn_rescan_debug_internal (insn_info->insn);
+    }
+
+  BITMAP_FREE (rescan);
+}
+
+/* Reset all debug insns with pending uses.  Release the bitmap in it,
+   unless it is USED.  USED must be the same bitmap passed to
+   dead_debug_init.  */
+void
+dead_debug_finish (struct dead_debug *debug, bitmap used)
+{
+  if (debug->used != used)
+    BITMAP_FREE (debug->used);
+
+  dead_debug_reset_uses (debug, debug->head);
+
+  if (debug->to_rescan)
+    {
+      bitmap_iterator bi;
+      unsigned int uid;
+
+      EXECUTE_IF_SET_IN_BITMAP (debug->to_rescan, 0, uid, bi)
+       {
+         struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
+         if (insn_info)
+           df_insn_rescan (insn_info->insn);
+       }
+      BITMAP_FREE (debug->to_rescan);
+    }
+}
+
+/* Add USE to DEBUG.  It must be a dead reference to UREGNO in a debug
+   insn.  Create a bitmap for DEBUG as needed.  */
+void
+dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno)
+{
+  struct dead_debug_use *newddu = XNEW (struct dead_debug_use);
+
+  newddu->use = use;
+  newddu->next = debug->head;
+  debug->head = newddu;
+
+  if (!debug->used)
+    debug->used = BITMAP_ALLOC (NULL);
+
+  /* ??? If we dealt with split multi-registers below, we should set
+     all registers for the used mode in case of hardware
+     registers.  */
+  bitmap_set_bit (debug->used, uregno);
+}
+
+/* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
+   before or after INSN (depending on WHERE), that binds a debug temp
+   to the widest-mode use of UREGNO, if WHERE is *_WITH_REG, or the
+   value stored in UREGNO by INSN otherwise, and replace all uses of
+   UREGNO in DEBUG with uses of the debug temp.  INSN must be where
+   UREGNO dies, if WHERE is *_BEFORE_*, or where it is set otherwise.
+   Return the number of debug insns emitted.  */
+int
+dead_debug_insert_temp (struct dead_debug *debug, unsigned int uregno,
+                       rtx insn, enum debug_temp_where where)
+{
+  struct dead_debug_use **tailp = &debug->head;
+  struct dead_debug_use *cur;
+  struct dead_debug_use *uses = NULL;
+  struct dead_debug_use **usesp = &uses;
+  rtx reg = NULL;
+  rtx breg;
+  rtx dval;
+  rtx bind;
+
+  if (!debug->used || !bitmap_clear_bit (debug->used, uregno))
+    return 0;
+
+  /* Move all uses of uregno from debug->head to uses, setting mode to
+     the widest referenced mode.  */
+  while ((cur = *tailp))
+    {
+      if (DF_REF_REGNO (cur->use) == uregno)
+       {
+         *usesp = cur;
+         usesp = &cur->next;
+         *tailp = cur->next;
+         cur->next = NULL;
+         if (!reg
+             || (GET_MODE_BITSIZE (GET_MODE (reg))
+                 < GET_MODE_BITSIZE (GET_MODE (*DF_REF_REAL_LOC (cur->use)))))
+           reg = *DF_REF_REAL_LOC (cur->use);
+       }
+      else
+       tailp = &(*tailp)->next;
+    }
+
+  /* We may have dangling bits in debug->used for registers that were part
+     of a multi-register use, one component of which has been reset.  */
+  if (reg == NULL)
+    {
+      gcc_checking_assert (!uses);
+      return 0;
+    }
+
+  gcc_checking_assert (uses);
+
+  breg = reg;
+  /* Recover the expression INSN stores in REG.  */
+  if (where == DEBUG_TEMP_BEFORE_WITH_VALUE)
+    {
+      rtx set = single_set (insn);
+      rtx dest, src;
+
+      if (set)
+       {
+         dest = SET_DEST (set);
+         src = SET_SRC (set);
+         /* Lose if the REG-setting insn is a CALL.  */
+         if (GET_CODE (src) == CALL)
+           {
+             while (uses)
+               {
+                 cur = uses->next;
+                 XDELETE (uses);
+                 uses = cur;
+               }
+             return 0;
+           }
+       }
+
+      /* ??? Should we try to extract it from a PARALLEL?  */
+      if (!set)
+       breg = NULL;
+      /* Cool, it's the same REG, we can use SRC.  */
+      else if (dest == reg)
+       breg = copy_rtx (src);
+      else if (REG_P (dest))
+       {
+         /* Hmm...  Something's fishy, we should be setting REG here.  */
+         if (REGNO (dest) != REGNO (reg))
+           breg = NULL;
+         /* If we're not overwriting all the hardware registers that
+            setting REG in its mode would, we won't know what to bind
+            the debug temp to.  ??? We could bind the debug_expr to a
+            CONCAT or PARALLEL with the split multi-registers, and
+            replace them as we found the corresponding sets.  */
+         else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
+                  && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
+                      != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
+           breg = NULL;
+         /* Ok, it's the same (hardware) REG, but with a different
+            mode, so SUBREG it.  */
+         else
+           breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src),
+                                  GET_MODE (dest));
+       }
+      else if (GET_CODE (dest) == SUBREG)
+       {
+         /* We should be setting REG here.  Lose.  */
+         if (REGNO (SUBREG_REG (dest)) != REGNO (reg))
+           breg = NULL;
+         /* Lose if we're setting something other than the lowpart of
+            REG.  */
+         else if (!subreg_lowpart_p (dest))
+           breg = NULL;
+         /* If we're not overwriting all the hardware registers that
+            setting REG in its mode would, we won't know what to bind
+            the debug temp to.  */
+         else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
+                  && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
+                      != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
+           breg = NULL;
+         /* Yay, we can use SRC, just adjust its mode.  */
+         else
+           breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src),
+                                  GET_MODE (dest));
+       }
+      /* Oh well, we're out of luck.  */
+      else
+       breg = NULL;
+
+      /* We couldn't figure out the value stored in REG, so reset all
+        of its pending debug uses.  */
+      if (!breg)
+       {
+         dead_debug_reset_uses (debug, uses);
+         return 0;
+       }
+    }
+
+  /* If there's a single (debug) use of an otherwise unused REG, and
+     the debug use is not part of a larger expression, then it
+     probably doesn't make sense to introduce a new debug temp.  */
+  if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
+    {
+      rtx next = DF_REF_INSN (uses->use);
+
+      if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
+       {
+         XDELETE (uses);
+         return 0;
+       }
+    }
+
+  /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL).  */
+  dval = make_debug_expr_from_rtl (reg);
+
+  /* Emit a debug bind insn before the insn in which reg dies.  */
+  bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
+                              DEBUG_EXPR_TREE_DECL (dval), breg,
+                              VAR_INIT_STATUS_INITIALIZED);
+
+  if (where == DEBUG_TEMP_AFTER_WITH_REG)
+    bind = emit_debug_insn_after (bind, insn);
+  else
+    bind = emit_debug_insn_before (bind, insn);
+  df_insn_rescan (bind);
+
+  /* Adjust all uses.  */
+  while ((cur = uses))
+    {
+      if (GET_MODE (*DF_REF_REAL_LOC (cur->use)) == GET_MODE (reg))
+       *DF_REF_REAL_LOC (cur->use) = dval;
+      else
+       *DF_REF_REAL_LOC (cur->use)
+         = gen_lowpart_SUBREG (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval);
+      /* ??? Should we simplify subreg of subreg?  */
+      if (debug->to_rescan == NULL)
+       debug->to_rescan = BITMAP_ALLOC (NULL);
+      bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
+      uses = cur->next;
+      XDELETE (cur);
+    }
+
+  return 1;
+}
diff --git a/gcc/valtrack.h b/gcc/valtrack.h
new file mode 100644 (file)
index 0000000..9f96f21
--- /dev/null
@@ -0,0 +1,75 @@
+/* Infrastructure for tracking user variable locations and values
+   throughout compilation.
+   Copyright (C) 2010, 2011, 2012  Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.com>.
+
+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 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+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 COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_VALTRACK_H
+#define GCC_VALTRACK_H
+
+#include "bitmap.h"
+#include "df.h"
+#include "rtl.h"
+#include "basic-block.h"
+
+/* Debug uses of dead regs.  */
+
+/* Node of a linked list of uses of dead REGs in debug insns.  */
+struct dead_debug_use
+{
+  df_ref use;
+  struct dead_debug_use *next;
+};
+
+/* Linked list of the above, with a bitmap of the REGs in the
+   list.  */
+struct dead_debug
+{
+  struct dead_debug_use *head;
+  bitmap used;
+  bitmap to_rescan;
+};
+
+/* This type controls the behavior of dead_debug_insert_temp WRT
+   UREGNO and INSN.  */
+enum debug_temp_where
+  {
+    /* Bind a newly-created debug temporary to a REG for UREGNO, and
+       insert the debug insn before INSN.  REG is expected to die at
+       INSN.  */
+    DEBUG_TEMP_BEFORE_WITH_REG = -1,
+    /* Bind a newly-created debug temporary to the value INSN stores
+       in REG, and insert the debug insn before INSN.  */
+    DEBUG_TEMP_BEFORE_WITH_VALUE = 0,
+    /* Bind a newly-created debug temporary to a REG for UREGNO, and
+       insert the debug insn after INSN.  REG is expected to be set at
+       INSN.  */
+    DEBUG_TEMP_AFTER_WITH_REG = 1
+  };
+
+extern void dead_debug_init (struct dead_debug *, bitmap);
+extern void dead_debug_finish (struct dead_debug *, bitmap);
+extern void dead_debug_add (struct dead_debug *, df_ref, unsigned int);
+extern int dead_debug_insert_temp (struct dead_debug *,
+                                  unsigned int uregno, rtx insn,
+                                  enum debug_temp_where);
+
+extern void propagate_for_debug (rtx, rtx, rtx, rtx, basic_block);
+
+
+#endif /* GCC_VALTRACK_H */