aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog27
-rw-r--r--gcc/Makefile.in15
-rw-r--r--gcc/combine.c180
-rw-r--r--gcc/cselib.c1
-rw-r--r--gcc/dce.c1
-rw-r--r--gcc/df-problems.c307
-rw-r--r--gcc/df.h42
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/valtrack.c492
-rw-r--r--gcc/valtrack.h75
10 files changed, 624 insertions, 517 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4d5bf54..ea9a7b1 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7633282..b2c4d4f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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) \
diff --git a/gcc/combine.c b/gcc/combine.c
index a07c046..dbc6ff6 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -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);
diff --git a/gcc/cselib.c b/gcc/cselib.c
index ece2240..88a74b4 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -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"
diff --git a/gcc/dce.c b/gcc/dce.c
index c72cdd1..c951865 100644
--- 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"
diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index d572b0f..8699304 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -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. */
diff --git a/gcc/df.h b/gcc/df.h
index 1b4882d..e59ae12 100644
--- 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 */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index b611fbe..82c3e59 100644
--- 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
index 0000000..3e03599
--- /dev/null
+++ b/gcc/valtrack.c
@@ -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
index 0000000..9f96f21
--- /dev/null
+++ b/gcc/valtrack.h
@@ -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 */