summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog54
-rw-r--r--gcc/cfgexpand.c12
-rw-r--r--gcc/cselib.c12
-rw-r--r--gcc/emit-rtl.c8
-rw-r--r--gcc/gengtype.c2
-rw-r--r--gcc/gimple-iterator.c8
-rw-r--r--gcc/print-rtl.c6
-rw-r--r--gcc/rtl.c4
-rw-r--r--gcc/rtl.def4
-rw-r--r--gcc/sched-vis.c13
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/gcc.dg/debug/pr41264-1.c36
-rw-r--r--gcc/testsuite/gcc.dg/debug/pr41343-1.c20
-rw-r--r--gcc/testsuite/gcc.dg/guality/pr41447-1.c25
-rw-r--r--gcc/tree-dump.c4
-rw-r--r--gcc/tree-flow.h6
-rw-r--r--gcc/tree-pretty-print.c3
-rw-r--r--gcc/tree-ssa-dce.c26
-rw-r--r--gcc/tree-ssa-forwprop.c8
-rw-r--r--gcc/tree-ssa-loop-im.c20
-rw-r--r--gcc/tree-ssa-operands.c4
-rw-r--r--gcc/tree-ssa-reassoc.c2
-rw-r--r--gcc/tree-ssa-sink.c7
-rw-r--r--gcc/tree-ssa.c240
-rw-r--r--gcc/tree-ssanames.c2
-rw-r--r--gcc/tree.c13
-rw-r--r--gcc/tree.def4
-rw-r--r--gcc/tree.h4
-rw-r--r--gcc/var-tracking.c41
29 files changed, 444 insertions, 154 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7b6c0800795..9e066b4d1f6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,57 @@
+2009-10-12 Alexandre Oliva <aoliva@redhat.com>
+
+ PR debug/41343
+ PR debug/41447
+ PR debug/41264
+ PR debug/41338
+ * tree.def (DEBUG_EXPR_DECL): New.
+ * rtl.def (DEBUG_EXPR): New.
+ * gengtype.c (adjust_field_rtx_def): Handle it.
+ * tree-ssa.c (propagate_var_def_into_debug_stmts): Rename to...
+ (insert_debug_temp_for_var_def): ... this. Drop support for
+ moving. Take iterator for def stmt; insert debug stmt before it.
+ Scan early for use count and kind in debug stmts.
+ (propagate_defs_into_debug_stmts): Rename to...
+ (insert_debug_temps_for_defs): ... this. Likewise.
+ * tree.h (DEBUG_TEMP_UID): New.
+ * tree.c (next_debug_decl_uid): New.
+ (make_node_stat): Count debug decls separately.
+ (copy_node_stat): Likewise.
+ * cfgexpand.c (expand_debug_expr): Handle DEBUG_EXPR_DECL.
+ * var-tracking.c (dv_is_decl_p): Recognize it.
+ (VALUE_RECURSED_INTO): Apply to DEBUG_EXPRs too.
+ (track_expr_p): Track expanded DEBUG_EXPR_DECLs.
+ (vt_expand_loc_callback): Expand DEBUG_EXPRs.
+ (emit_note_insn_var_location): Don't emit notes for DEBUG_EXPR_DECLs.
+ * cselib.c (rtx_equal_for_cselib_p): Handle DEBUG_EXPR.
+ (cselib_hash_rtx): Likewise.
+ (cselib_expand_value_rtx_1): Use callback for DEBUG_EXPR.
+ * tree-ssa-operands.c (get_expr_operands): Skip DEBUG_EXPR_DECLs in
+ debug bind stmts.
+ * emit-rtl.c (verify_rtx_sharing): Handle DEBUG_EXPR and VALUE.
+ (copy_rtx_if_shared_1, reset_used_flags, set_used_flags): Likewise.
+ * rtl.c (copy_rtx): Likewise.
+ (rtx_equal_p_cb, rtx_equal_p): Handle DEBUG_EXPR.
+ * print-rtl.c (print_rtx): Likewise.
+ * sched-vis.c (print_value): Likewise.
+ (print_insn): Handle DEBUG_EXPR_DECL.
+ * tree-dump.c (dequeue_and_dump): Likewise.
+ * tree-pretty-print.c (dump_decl_name, dump_generic_node): Likewise.
+ * gimple-iterator (gsi_replace): Check for same lhs.
+ (gsi_remove): Insert debug temps.
+ * tree-ssa-loop-im.c (rewrite_reciprocal): Replace with same lhs.
+ (move_computations_stmt): Drop explicit propagation into debug stmts.
+ (rewrite_bittest): Likewise. Use gsi_remove for propagation.
+ * tree-ssa-reassoc.c (rewrite_expr_tree, linearize_expr): Likewise.
+ * tree-ssa-sink.c (statement_sink_location): Likewise.
+ * tree-ssa-forwprop (forward_propagate_addr_expr): Likewise.
+ * tree-ssanames.c (release_ssa_name): Adjust for rename.
+ * tree-flow.h: Likewise.
+ * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Don't mark
+ debug temps without values.
+ (eliminate_unnecessary_stmts): Don't discard just-inserted
+ debug stmts.
+
2009-10-12 Hans-Peter Nilsson <hp@axis.com>
PR target/26515
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 2117ee3bc52..31832e71c87 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2361,6 +2361,18 @@ expand_debug_expr (tree exp)
op1 = wrap_constant (GET_MODE_INNER (mode), op1);
return gen_rtx_CONCAT (mode, op0, op1);
+ case DEBUG_EXPR_DECL:
+ op0 = DECL_RTL_IF_SET (exp);
+
+ if (op0)
+ return op0;
+
+ op0 = gen_rtx_DEBUG_EXPR (mode);
+ XTREE (op0, 0) = exp;
+ SET_DECL_RTL (exp, op0);
+
+ return op0;
+
case VAR_DECL:
case PARM_DECL:
case FUNCTION_DECL:
diff --git a/gcc/cselib.c b/gcc/cselib.c
index e6e5c143dad..c26742ddf1a 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -585,6 +585,7 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
{
case CONST_DOUBLE:
case CONST_FIXED:
+ case DEBUG_EXPR:
return 0;
case LABEL_REF:
@@ -703,6 +704,10 @@ cselib_hash_rtx (rtx x, int create)
return e->value;
+ case DEBUG_EXPR:
+ hash += ((unsigned) DEBUG_EXPR << 7) + DEBUG_TEMP_UID (XTREE (x, 0));
+ return hash ? hash : (unsigned int) DEBUG_EXPR;
+
case CONST_INT:
hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
return hash ? hash : (unsigned int) CONST_INT;
@@ -1213,6 +1218,13 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
result = expand_loc (CSELIB_VAL_PTR (orig)->locs, evd, max_depth);
return result;
}
+
+ case DEBUG_EXPR:
+ if (evd->callback)
+ return evd->callback (orig, evd->regs_active, max_depth,
+ evd->callback_arg);
+ return orig;
+
default:
break;
}
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index b3672e3e5ad..b8682984eca 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -2393,6 +2393,8 @@ verify_rtx_sharing (rtx orig, rtx insn)
switch (code)
{
case REG:
+ case DEBUG_EXPR:
+ case VALUE:
case CONST_INT:
case CONST_DOUBLE:
case CONST_FIXED:
@@ -2593,6 +2595,8 @@ repeat:
switch (code)
{
case REG:
+ case DEBUG_EXPR:
+ case VALUE:
case CONST_INT:
case CONST_DOUBLE:
case CONST_FIXED:
@@ -2712,6 +2716,8 @@ repeat:
switch (code)
{
case REG:
+ case DEBUG_EXPR:
+ case VALUE:
case CONST_INT:
case CONST_DOUBLE:
case CONST_FIXED:
@@ -2783,6 +2789,8 @@ set_used_flags (rtx x)
switch (code)
{
case REG:
+ case DEBUG_EXPR:
+ case VALUE:
case CONST_INT:
case CONST_DOUBLE:
case CONST_FIXED:
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index e5b43dde96e..8e882f171f9 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -1117,6 +1117,8 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
t = scalar_tp, subname = "rt_int";
else if (i == VALUE && aindex == 0)
t = scalar_tp, subname = "rt_int";
+ else if (i == DEBUG_EXPR && aindex == 0)
+ t = tree_tp, subname = "rt_tree";
else if (i == REG && aindex == 1)
t = scalar_tp, subname = "rt_int";
else if (i == REG && aindex == 2)
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 66927d67c2c..c3ca0e37501 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -358,7 +358,8 @@ gsi_split_seq_before (gimple_stmt_iterator *i)
/* Replace the statement pointed-to by GSI to STMT. If UPDATE_EH_INFO
is true, the exception handling information of the original
- statement is moved to the new statement. */
+ statement is moved to the new statement. Assignments must only be
+ replaced with assignments to the same LHS. */
void
gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info)
@@ -368,6 +369,9 @@ gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info)
if (stmt == orig_stmt)
return;
+ gcc_assert (!gimple_has_lhs (orig_stmt)
+ || gimple_get_lhs (orig_stmt) == gimple_get_lhs (stmt));
+
gimple_set_location (stmt, gimple_location (orig_stmt));
gimple_set_bb (stmt, gsi_bb (*gsi));
@@ -470,6 +474,8 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
gimple_seq_node cur, next, prev;
gimple stmt = gsi_stmt (*i);
+ insert_debug_temps_for_defs (i);
+
/* Free all the data flow information for STMT. */
gimple_set_bb (stmt, NULL);
delink_stmt_imm_use (stmt);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index a75442eb6c7..5ba5e634a66 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -318,6 +318,12 @@ print_rtx (const_rtx in_rtx)
dump_addr (outfile, "/", (void*)val);
#endif
}
+ else if (i == 0 && GET_CODE (in_rtx) == DEBUG_EXPR)
+ {
+#ifndef GENERATOR_FILE
+ fprintf (outfile, " D#%i", DEBUG_TEMP_UID (XTREE (in_rtx, 0)));
+#endif
+ }
break;
case 'e':
diff --git a/gcc/rtl.c b/gcc/rtl.c
index feeb40bf61b..53a4992f482 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -232,6 +232,8 @@ copy_rtx (rtx orig)
switch (code)
{
case REG:
+ case DEBUG_EXPR:
+ case VALUE:
case CONST_INT:
case CONST_DOUBLE:
case CONST_FIXED:
@@ -381,6 +383,7 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
+ case DEBUG_EXPR:
case VALUE:
case SCRATCH:
case CONST_DOUBLE:
@@ -496,6 +499,7 @@ rtx_equal_p (const_rtx x, const_rtx y)
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
+ case DEBUG_EXPR:
case VALUE:
case SCRATCH:
case CONST_DOUBLE:
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 2aa76b1f6c8..acb7ee915b8 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -88,6 +88,10 @@ DEF_RTL_EXPR(UNKNOWN, "UnKnown", "*", RTX_EXTRA)
DECL codes in trees. */
DEF_RTL_EXPR(VALUE, "value", "0", RTX_OBJ)
+/* The RTL generated for a DEBUG_EXPR_DECL. It links back to the
+ DEBUG_EXPR_DECL in the first operand. */
+DEF_RTL_EXPR(DEBUG_EXPR, "debug_expr", "0", RTX_OBJ)
+
/* ---------------------------------------------------------------------
Expressions used in constructing lists.
--------------------------------------------------------------------- */
diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c
index 89230efa34c..d95235ee3ec 100644
--- a/gcc/sched-vis.c
+++ b/gcc/sched-vis.c
@@ -521,6 +521,10 @@ print_value (char *buf, const_rtx x, int verbose)
cur = safe_concat (buf, cur, t);
cur = safe_concat (buf, cur, "]");
break;
+ case DEBUG_EXPR:
+ sprintf (t, "D#%i", DEBUG_TEMP_UID (XTREE (x, 0)));
+ cur = safe_concat (buf, cur, t);
+ break;
default:
print_exp (t, x, verbose);
cur = safe_concat (buf, cur, t);
@@ -670,11 +674,18 @@ print_insn (char *buf, const_rtx x, int verbose)
if (DECL_P (INSN_VAR_LOCATION_DECL (insn)))
{
tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (insn));
+ char idbuf[32];
if (id)
name = IDENTIFIER_POINTER (id);
+ else if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn))
+ == DEBUG_EXPR_DECL)
+ {
+ sprintf (idbuf, "D#%i",
+ DEBUG_TEMP_UID (INSN_VAR_LOCATION_DECL (insn)));
+ name = idbuf;
+ }
else
{
- char idbuf[32];
sprintf (idbuf, "D.%i",
DECL_UID (INSN_VAR_LOCATION_DECL (insn)));
name = idbuf;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d6448ec1f9c..7e2c9ab6ff4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2009-10-12 Alexandre Oliva <aoliva@redhat.com>
+
+ PR debug/41343
+ PR debug/41447
+ PR debug/41264
+ PR debug/41338
+ * gcc.dg/guality/pr41447-1.c: New.
+ * gcc.dg/debug/pr41264-1.c: New.
+ * gcc.dg/debug/pr41343-1.c: New.
+
2009-10-12 Hans-Peter Nilsson <hp@axis.com>
PR target/26515
diff --git a/gcc/testsuite/gcc.dg/debug/pr41264-1.c b/gcc/testsuite/gcc.dg/debug/pr41264-1.c
new file mode 100644
index 00000000000..b5555b554ba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/pr41264-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+
+typedef unsigned int hashval_t;
+static hashval_t __attribute__((always_inline))
+iterative_hash_host_wide_int (long val, hashval_t val2)
+{
+ hashval_t a = (hashval_t) val;
+ int zero = 0;
+ hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 8 + zero));
+
+ a -= b; a -= val2; a ^= (val2>>13);
+ b -= val2; b -= a; b ^= (a<< 8);
+ val2 -= a; val2 -= b; val2 ^= ((b&0xffffffff)>>13);
+ a -= b; a -= val2; a ^= ((val2&0xffffffff)>>12);
+ b -= val2; b -= a; b = (b ^ (a<<16)) & 0xffffffff;
+ val2 -= a; val2 -= b; val2 = (val2 ^ (b>> 5)) & 0xffffffff;
+ a -= b; a -= val2; a = (a ^ (val2>> 3)) & 0xffffffff;
+ b -= val2; b -= a; b = (b ^ (a<<10)) & 0xffffffff;
+ val2 -= a; val2 -= b; val2 = (val2 ^ (b>>15)) & 0xffffffff;
+ return val2;
+}
+
+hashval_t
+bla (int nunits, int mode)
+{
+ hashval_t hashcode = 0;
+
+
+ hashcode = iterative_hash_host_wide_int (14, hashcode);
+ hashcode = iterative_hash_host_wide_int (nunits, hashcode);
+ hashcode = iterative_hash_host_wide_int (mode, hashcode);
+ if (nunits)
+ return 0;
+ else
+ return hashcode;
+}
diff --git a/gcc/testsuite/gcc.dg/debug/pr41343-1.c b/gcc/testsuite/gcc.dg/debug/pr41343-1.c
new file mode 100644
index 00000000000..6d56380383d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/pr41343-1.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+#define X(new,old) int i ## new = i ## old + i ## old;
+#define Y(pfx) X(pfx ## 1, pfx) \
+ X(pfx ## 2, pfx ## 1) \
+ X(pfx ## 3, pfx ## 2) \
+ X(pfx ## 4, pfx ## 3) \
+ X(pfx ## 5, pfx ## 4) \
+ X(pfx ## 6, pfx ## 5) \
+ X(pfx ## 7, pfx ## 6) \
+ X(pfx ## 8, pfx ## 7) \
+ X(pfx ## 9, pfx ## 8)
+
+void foo (int i1)
+{
+ Y(1)
+ Y(11)
+ Y(111)
+ asm ("" : : "X" (i1));
+}
diff --git a/gcc/testsuite/gcc.dg/guality/pr41447-1.c b/gcc/testsuite/gcc.dg/guality/pr41447-1.c
new file mode 100644
index 00000000000..675b0304661
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/guality/pr41447-1.c
@@ -0,0 +1,25 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-options "-g -O2" } */
+
+#include "guality.h"
+
+int a;
+
+int foo()
+{
+ int tmp = a;
+ int tmp2 = a;
+ int tmp3;
+ int res;
+ GUALCHKVAL (a);
+ GUALCHKVAL (tmp);
+ GUALCHKVAL (tmp2);
+ a = 0;
+ tmp3 = tmp2;
+ GUALCHKVAL (a);
+ GUALCHKVAL (tmp);
+ GUALCHKVAL (tmp2);
+ GUALCHKVAL (tmp3);
+ res = tmp - tmp2 + 1;
+ return res;
+}
diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
index 61ccc6ce792..7b7a85f5082 100644
--- a/gcc/tree-dump.c
+++ b/gcc/tree-dump.c
@@ -511,6 +511,10 @@ dequeue_and_dump (dump_info_p di)
dump_child ("cnst", DECL_INITIAL (t));
break;
+ case DEBUG_EXPR_DECL:
+ dump_int (di, "-uid", DEBUG_TEMP_UID (t));
+ /* Fall through. */
+
case VAR_DECL:
case PARM_DECL:
case FIELD_DECL:
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index 8e790aec784..85f1f5ef60a 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -637,10 +637,8 @@ typedef bool (*walk_use_def_chains_fn) (tree, gimple, void *);
extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
-void propagate_defs_into_debug_stmts (gimple, basic_block,
- const gimple_stmt_iterator *);
-void propagate_var_def_into_debug_stmts (tree, basic_block,
- const gimple_stmt_iterator *);
+void insert_debug_temps_for_defs (gimple_stmt_iterator *);
+void insert_debug_temp_for_var_def (gimple_stmt_iterator *, tree);
void release_defs_bitset (bitmap toremove);
/* In tree-into-ssa.c */
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index a325d75d914..cfc20a178ea 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -183,6 +183,8 @@ dump_decl_name (pretty_printer *buffer, tree node, int flags)
{
if (TREE_CODE (node) == LABEL_DECL && LABEL_DECL_UID (node) != -1)
pp_printf (buffer, "L.%d", (int) LABEL_DECL_UID (node));
+ else if (TREE_CODE (node) == DEBUG_EXPR_DECL)
+ pp_printf (buffer, "D#%i", DEBUG_TEMP_UID (node));
else
{
char c = TREE_CODE (node) == CONST_DECL ? 'C' : 'D';
@@ -1051,6 +1053,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
case VAR_DECL:
case PARM_DECL:
case FIELD_DECL:
+ case DEBUG_EXPR_DECL:
case NAMESPACE_DECL:
dump_decl_name (buffer, node, flags);
break;
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 67d0472cc59..7dd07c1ca2c 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -325,7 +325,13 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
break;
case GIMPLE_DEBUG:
- mark_stmt_necessary (stmt, false);
+ /* Debug temps without a value are not useful. ??? If we could
+ easily locate the debug temp bind stmt for a use thereof,
+ would could refrain from marking all debug temps here, and
+ mark them only if they're used. */
+ if (gimple_debug_bind_has_value_p (stmt)
+ || TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL)
+ mark_stmt_necessary (stmt, false);
return;
case GIMPLE_GOTO:
@@ -1071,7 +1077,7 @@ eliminate_unnecessary_stmts (void)
{
bool something_changed = false;
basic_block bb;
- gimple_stmt_iterator gsi;
+ gimple_stmt_iterator gsi, psi;
gimple stmt;
tree call;
VEC (basic_block, heap) *h;
@@ -1111,10 +1117,13 @@ eliminate_unnecessary_stmts (void)
bb = VEC_pop (basic_block, h);
/* Remove dead statements. */
- for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
+ for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi = psi)
{
stmt = gsi_stmt (gsi);
+ psi = gsi;
+ gsi_prev (&psi);
+
stats.total++;
/* If GSI is not necessary then remove it. */
@@ -1122,14 +1131,6 @@ eliminate_unnecessary_stmts (void)
{
remove_dead_stmt (&gsi, bb);
something_changed = true;
-
- /* If stmt was the last stmt in the block, we want to
- move gsi to the stmt that became the last stmt, but
- gsi_prev would crash. */
- if (gsi_end_p (gsi))
- gsi = gsi_last_bb (bb);
- else
- gsi_prev (&gsi);
}
else if (is_gimple_call (stmt))
{
@@ -1159,10 +1160,7 @@ eliminate_unnecessary_stmts (void)
}
notice_special_calls (stmt);
}
- gsi_prev (&gsi);
}
- else
- gsi_prev (&gsi);
}
}
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index 87795a28223..6ba800d8288 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -939,7 +939,6 @@ forward_propagate_addr_expr (tree name, tree rhs)
gimple use_stmt;
bool all = true;
bool single_use_p = has_single_use (name);
- bool debug = false;
FOR_EACH_IMM_USE_STMT (use_stmt, iter, name)
{
@@ -950,9 +949,7 @@ forward_propagate_addr_expr (tree name, tree rhs)
there is nothing we can do. */
if (gimple_code (use_stmt) != GIMPLE_ASSIGN)
{
- if (is_gimple_debug (use_stmt))
- debug = true;
- else
+ if (!is_gimple_debug (use_stmt))
all = false;
continue;
}
@@ -995,9 +992,6 @@ forward_propagate_addr_expr (tree name, tree rhs)
}
}
- if (all && debug)
- propagate_var_def_into_debug_stmts (name, NULL, NULL);
-
return all;
}
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 738249445b0..6c6a9f17a1d 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -764,6 +764,7 @@ rewrite_reciprocal (gimple_stmt_iterator *bsi)
gimple stmt, stmt1, stmt2;
tree var, name, lhs, type;
tree real_one;
+ gimple_stmt_iterator gsi;
stmt = gsi_stmt (*bsi);
lhs = gimple_assign_lhs (stmt);
@@ -798,8 +799,9 @@ rewrite_reciprocal (gimple_stmt_iterator *bsi)
/* Replace division stmt with reciprocal and multiply stmts.
The multiply stmt is not invariant, so update iterator
and avoid rescanning. */
- gsi_replace (bsi, stmt1, true);
- gsi_insert_after (bsi, stmt2, GSI_NEW_STMT);
+ gsi = *bsi;
+ gsi_insert_before (bsi, stmt1, GSI_NEW_STMT);
+ gsi_replace (&gsi, stmt2, true);
/* Continue processing with invariant reciprocal statement. */
return stmt1;
@@ -858,6 +860,8 @@ rewrite_bittest (gimple_stmt_iterator *bsi)
if (outermost_invariant_loop (b, loop_containing_stmt (stmt1)) != NULL
&& outermost_invariant_loop (a, loop_containing_stmt (stmt1)) == NULL)
{
+ gimple_stmt_iterator rsi;
+
/* 1 << B */
var = create_tmp_var (TREE_TYPE (a), "shifttmp");
add_referenced_var (var);
@@ -878,9 +882,14 @@ rewrite_bittest (gimple_stmt_iterator *bsi)
SET_USE (use, name);
gimple_cond_set_rhs (use_stmt, build_int_cst_type (TREE_TYPE (name), 0));
- gsi_insert_before (bsi, stmt1, GSI_SAME_STMT);
- propagate_defs_into_debug_stmts (gsi_stmt (*bsi), NULL, NULL);
- gsi_replace (bsi, stmt2, true);
+ /* Don't use gsi_replace here, none of the new assignments sets
+ the variable originally set in stmt. Move bsi to stmt1, and
+ then remove the original stmt, so that we get a chance to
+ retain debug info for it. */
+ rsi = *bsi;
+ gsi_insert_before (bsi, stmt1, GSI_NEW_STMT);
+ gsi_insert_before (&rsi, stmt2, GSI_SAME_STMT);
+ gsi_remove (&rsi, true);
return stmt1;
}
@@ -1060,7 +1069,6 @@ move_computations_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
mark_virtual_ops_for_renaming (stmt);
gsi_insert_on_edge (loop_preheader_edge (level), stmt);
- propagate_defs_into_debug_stmts (gsi_stmt (bsi), NULL, NULL);
gsi_remove (&bsi, false);
}
}
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index 28e6ec65826..6af31a437ea 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -894,6 +894,10 @@ get_expr_operands (gimple stmt, tree *expr_p, int flags)
add_stmt_operand (expr_p, stmt, flags);
return;
+ case DEBUG_EXPR_DECL:
+ gcc_assert (gimple_debug_bind_p (stmt));
+ return;
+
case MISALIGNED_INDIRECT_REF:
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags);
/* fall through */
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 55ce2f65a4f..5136aee5d32 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -1405,7 +1405,6 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex,
{
stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt1));
gsirhs1 = gsi_for_stmt (stmt2);
- propagate_defs_into_debug_stmts (stmt2, gimple_bb (stmt), &gsinow);
gsi_move_before (&gsirhs1, &gsinow);
gsi_prev (&gsinow);
stmt1 = stmt2;
@@ -1452,7 +1451,6 @@ linearize_expr (gimple stmt)
gsinow = gsi_for_stmt (stmt);
gsirhs = gsi_for_stmt (binrhs);
- propagate_defs_into_debug_stmts (binrhs, gimple_bb (stmt), &gsinow);
gsi_move_before (&gsirhs, &gsinow);
gimple_assign_set_rhs2 (stmt, gimple_assign_rhs1 (binrhs));
diff --git a/gcc/tree-ssa-sink.c b/gcc/tree-ssa-sink.c
index a9b4b67679b..be3fb7145fd 100644
--- a/gcc/tree-ssa-sink.c
+++ b/gcc/tree-ssa-sink.c
@@ -385,9 +385,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
*togsi = gsi_after_labels (commondom);
- if (debug_stmts)
- propagate_defs_into_debug_stmts (stmt, commondom, togsi);
-
return true;
}
@@ -406,8 +403,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
*togsi = gsi_for_stmt (use);
- propagate_defs_into_debug_stmts (stmt, sinkbb, togsi);
-
return true;
}
@@ -441,8 +436,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
*togsi = gsi_after_labels (sinkbb);
- propagate_defs_into_debug_stmts (stmt, sinkbb, togsi);
-
return true;
}
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 9015d19c189..9858b109d03 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -295,152 +295,198 @@ find_released_ssa_name (tree *tp, int *walk_subtrees, void *data_)
return NULL_TREE;
}
-/* Given a VAR whose definition STMT is to be moved to the iterator
- position TOGSIP in the TOBB basic block, verify whether we're
- moving it across any of the debug statements that use it, and
- adjust them as needed. If TOBB is NULL, then the definition is
- understood as being removed, and TOGSIP is unused. */
+/* Insert a DEBUG BIND stmt before the DEF of VAR if VAR is referenced
+ by other DEBUG stmts, and replace uses of the DEF with the
+ newly-created debug temp. */
+
void
-propagate_var_def_into_debug_stmts (tree var,
- basic_block tobb,
- const gimple_stmt_iterator *togsip)
+insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
{
imm_use_iterator imm_iter;
- gimple stmt;
use_operand_p use_p;
+ gimple stmt;
+ gimple def_stmt = NULL;
+ int usecount = 0;
tree value = NULL;
- bool no_value = false;
if (!MAY_HAVE_DEBUG_STMTS)
return;
- FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+ /* First of all, check whether there are debug stmts that reference
+ this variable and, if there are, decide whether we should use a
+ debug temp. */
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
{
- basic_block bb;
- gimple_stmt_iterator si;
+ stmt = USE_STMT (use_p);
- if (!is_gimple_debug (stmt))
+ if (!gimple_debug_bind_p (stmt))
continue;
- if (tobb)
+ if (usecount++)
+ break;
+
+ if (gimple_debug_bind_get_value (stmt) != var)
{
- bb = gimple_bb (stmt);
+ /* Count this as an additional use, so as to make sure we
+ use a temp unless VAR's definition has a SINGLE_RHS that
+ can be shared. */
+ usecount++;
+ break;
+ }
+ }
- if (bb != tobb)
- {
- gcc_assert (dom_info_available_p (CDI_DOMINATORS));
- if (dominated_by_p (CDI_DOMINATORS, bb, tobb))
- continue;
- }
- else
- {
- si = *togsip;
+ if (!usecount)
+ return;
- if (gsi_end_p (si))
- continue;
+ if (gsi)
+ def_stmt = gsi_stmt (*gsi);
+ else
+ def_stmt = SSA_NAME_DEF_STMT (var);
- do
- {
- gsi_prev (&si);
- if (gsi_end_p (si))
- break;
- }
- while (gsi_stmt (si) != stmt);
+ /* If we didn't get an insertion point, and the stmt has already
+ been removed, we won't be able to insert the debug bind stmt, so
+ we'll have to drop debug information. */
+ if (is_gimple_assign (def_stmt))
+ {
+ bool no_value = false;
- if (gsi_end_p (si))
- continue;
- }
+ if (!dom_info_available_p (CDI_DOMINATORS))
+ {
+ struct walk_stmt_info wi;
+
+ memset (&wi, 0, sizeof (wi));
+
+ /* When removing blocks without following reverse dominance
+ order, we may sometimes encounter SSA_NAMEs that have
+ already been released, referenced in other SSA_DEFs that
+ we're about to release. Consider:
+
+ <bb X>:
+ v_1 = foo;
+
+ <bb Y>:
+ w_2 = v_1 + bar;
+ # DEBUG w => w_2
+
+ If we deleted BB X first, propagating the value of w_2
+ won't do us any good. It's too late to recover their
+ original definition of v_1: when it was deleted, it was
+ only referenced in other DEFs, it couldn't possibly know
+ it should have been retained, and propagating every
+ single DEF just in case it might have to be propagated
+ into a DEBUG STMT would probably be too wasteful.
+
+ When dominator information is not readily available, we
+ check for and accept some loss of debug information. But
+ if it is available, there's no excuse for us to remove
+ blocks in the wrong order, so we don't even check for
+ dead SSA NAMEs. SSA verification shall catch any
+ errors. */
+ if ((!gsi && !gimple_bb (def_stmt))
+ || !walk_gimple_op (def_stmt, find_released_ssa_name,
+ &wi))
+ no_value = true;
}
- /* Here we compute (lazily) the value assigned to VAR, but we
- remember if we tried before and failed, so that we don't try
- again. */
- if (!value && !no_value)
+ if (!no_value)
+ value = gimple_assign_rhs_to_tree (def_stmt);
+ }
+
+ if (value)
+ {
+ /* If there's a single use of VAR, and VAR is the entire debug
+ expression (usecount would have been incremented again
+ otherwise), and the definition involves only constants and
+ SSA names, then we can propagate VALUE into this single use,
+ avoiding the temp.
+
+ We can also avoid using a temp if VALUE can be shared and
+ propagated into all uses, without generating expressions that
+ wouldn't be valid gimple RHSs.
+
+ Other cases that would require unsharing or non-gimple RHSs
+ are deferred to a debug temp, although we could avoid temps
+ at the expense of duplication of expressions. */
+
+ if (CONSTANT_CLASS_P (value)
+ || (usecount == 1
+ && (!gimple_assign_single_p (def_stmt)
+ || is_gimple_min_invariant (value)))
+ || is_gimple_reg (value))
+ value = unshare_expr (value);
+ else
{
- gimple def_stmt = SSA_NAME_DEF_STMT (var);
+ gimple def_temp;
+ tree vexpr = make_node (DEBUG_EXPR_DECL);
- if (is_gimple_assign (def_stmt))
- {
- if (!dom_info_available_p (CDI_DOMINATORS))
- {
- struct walk_stmt_info wi;
-
- memset (&wi, 0, sizeof (wi));
-
- /* When removing blocks without following reverse
- dominance order, we may sometimes encounter SSA_NAMEs
- that have already been released, referenced in other
- SSA_DEFs that we're about to release. Consider:
-
- <bb X>:
- v_1 = foo;
-
- <bb Y>:
- w_2 = v_1 + bar;
- # DEBUG w => w_2
-
- If we deleted BB X first, propagating the value of
- w_2 won't do us any good. It's too late to recover
- their original definition of v_1: when it was
- deleted, it was only referenced in other DEFs, it
- couldn't possibly know it should have been retained,
- and propagating every single DEF just in case it
- might have to be propagated into a DEBUG STMT would
- probably be too wasteful.
-
- When dominator information is not readily
- available, we check for and accept some loss of
- debug information. But if it is available,
- there's no excuse for us to remove blocks in the
- wrong order, so we don't even check for dead SSA
- NAMEs. SSA verification shall catch any
- errors. */
- if (!walk_gimple_op (def_stmt, find_released_ssa_name, &wi))
- no_value = true;
- }
+ def_temp = gimple_build_debug_bind (vexpr,
+ unshare_expr (value),
+ def_stmt);
+
+ DECL_ARTIFICIAL (vexpr) = 1;
+ TREE_TYPE (vexpr) = TREE_TYPE (value);
+ if (DECL_P (value))
+ DECL_MODE (vexpr) = DECL_MODE (value);
+ else
+ DECL_MODE (vexpr) = TYPE_MODE (TREE_TYPE (value));
- if (!no_value)
- value = gimple_assign_rhs_to_tree (def_stmt);
+ if (gsi)
+ gsi_insert_before (gsi, def_temp, GSI_SAME_STMT);
+ else
+ {
+ gimple_stmt_iterator ngsi = gsi_for_stmt (def_stmt);
+ gsi_insert_before (&ngsi, def_temp, GSI_SAME_STMT);
}
- if (!value)
- no_value = true;
+ value = vexpr;
}
+ }
- if (no_value)
- gimple_debug_bind_reset_value (stmt);
- else
+ FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+ {
+ if (!gimple_debug_bind_p (stmt))
+ continue;
+
+ if (value)
FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
- SET_USE (use_p, unshare_expr (value));
+ /* unshare_expr is not needed here. vexpr is either a
+ SINGLE_RHS, that can be safely shared, some other RHS
+ that was unshared when we found it had a single debug
+ use, or a DEBUG_EXPR_DECL, that can be safely
+ shared. */
+ SET_USE (use_p, value);
+ else
+ gimple_debug_bind_reset_value (stmt);
update_stmt (stmt);
}
}
-/* Given a STMT to be moved to the iterator position TOBSIP in the
- TOBB basic block, verify whether we're moving it across any of the
- debug statements that use it. If TOBB is NULL, then the definition
- is understood as being removed, and TOBSIP is unused. */
+/* Insert a DEBUG BIND stmt before STMT for each DEF referenced by
+ other DEBUG stmts, and replace uses of the DEF with the
+ newly-created debug temp. */
void
-propagate_defs_into_debug_stmts (gimple def, basic_block tobb,
- const gimple_stmt_iterator *togsip)
+insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
{
+ gimple stmt;
ssa_op_iter op_iter;
def_operand_p def_p;
if (!MAY_HAVE_DEBUG_STMTS)
return;
- FOR_EACH_SSA_DEF_OPERAND (def_p, def, op_iter, SSA_OP_DEF)
+ stmt = gsi_stmt (*gsi);
+
+ FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, op_iter, SSA_OP_DEF)
{
tree var = DEF_FROM_PTR (def_p);
if (TREE_CODE (var) != SSA_NAME)
continue;
- propagate_var_def_into_debug_stmts (var, tobb, togsip);
+ insert_debug_temp_for_var_def (gsi, var);
}
}
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 45183218a2c..bb0880260ff 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -206,7 +206,7 @@ release_ssa_name (tree var)
use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
if (MAY_HAVE_DEBUG_STMTS)
- propagate_var_def_into_debug_stmts (var, NULL, NULL);
+ insert_debug_temp_for_var_def (NULL, var);
#ifdef ENABLE_CHECKING
verify_imm_links (stderr, var);
diff --git a/gcc/tree.c b/gcc/tree.c
index 4c3f52bd7b7..9e463c04872 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -152,6 +152,9 @@ static const char * const tree_node_kind_names[] = {
static GTY(()) int next_decl_uid;
/* Unique id for next type created. */
static GTY(()) int next_type_uid = 1;
+/* Unique id for next debug decl created. Use negative numbers,
+ to catch erroneous uses. */
+static GTY(()) int next_debug_decl_uid;
/* Since we cannot rehash a type after it is in the table, we have to
keep the hash code. */
@@ -872,7 +875,10 @@ make_node_stat (enum tree_code code MEM_STAT_DECL)
DECL_ALIGN (t) = 1;
}
DECL_SOURCE_LOCATION (t) = input_location;
- DECL_UID (t) = next_decl_uid++;
+ if (TREE_CODE (t) == DEBUG_EXPR_DECL)
+ DECL_UID (t) = --next_debug_decl_uid;
+ else
+ DECL_UID (t) = next_decl_uid++;
if (TREE_CODE (t) == LABEL_DECL)
LABEL_DECL_UID (t) = -1;
@@ -948,7 +954,10 @@ copy_node_stat (tree node MEM_STAT_DECL)
if (TREE_CODE_CLASS (code) == tcc_declaration)
{
- DECL_UID (t) = next_decl_uid++;
+ if (code == DEBUG_EXPR_DECL)
+ DECL_UID (t) = --next_debug_decl_uid;
+ else
+ DECL_UID (t) = next_decl_uid++;
if ((TREE_CODE (node) == PARM_DECL || TREE_CODE (node) == VAR_DECL)
&& DECL_HAS_VALUE_EXPR_P (node))
{
diff --git a/gcc/tree.def b/gcc/tree.def
index c1ba96aa966..01d91b76a6f 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -351,6 +351,10 @@ DEFTREECODE (PARM_DECL, "parm_decl", tcc_declaration, 0)
DEFTREECODE (TYPE_DECL, "type_decl", tcc_declaration, 0)
DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
+/* A "declaration" of a debug temporary. It should only appear in
+ DEBUG stmts. */
+DEFTREECODE (DEBUG_EXPR_DECL, "debug_expr_decl", tcc_declaration, 0)
+
/* A namespace declaration. Namespaces appear in DECL_CONTEXT of other
_DECLs, providing a hierarchy of names. */
DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
diff --git a/gcc/tree.h b/gcc/tree.h
index 20463b4a18b..2487a1ce9fe 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2455,6 +2455,10 @@ struct function;
/* Every ..._DECL node gets a unique number. */
#define DECL_UID(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.uid)
+/* DEBUG_EXPR_DECLs get negative UID numbers, to catch erroneous
+ uses. */
+#define DEBUG_TEMP_UID(NODE) (-DECL_UID (TREE_CHECK ((NODE), DEBUG_EXPR_DECL)))
+
/* These two fields describe where in the source code the declaration
was. If the declaration appears in several places (as for a C
function that is declared first and then defined later), this
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index bdd3bdee34e..840128cf7c8 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -732,6 +732,7 @@ dv_is_decl_p (decl_or_value dv)
case (int)PARM_DECL:
case (int)RESULT_DECL:
case (int)FUNCTION_DECL:
+ case (int)DEBUG_EXPR_DECL:
case (int)COMPONENT_REF:
return true;
@@ -2222,7 +2223,7 @@ dataflow_set_union (dataflow_set *dst, dataflow_set *src)
/* Whether the value is currently being expanded. */
#define VALUE_RECURSED_INTO(x) \
- (RTL_FLAG_CHECK1 ("VALUE_RECURSED_INTO", (x), VALUE)->used)
+ (RTL_FLAG_CHECK2 ("VALUE_RECURSED_INTO", (x), VALUE, DEBUG_EXPR)->used)
/* Whether the value is in changed_variables hash table. */
#define VALUE_CHANGED(x) \
(RTL_FLAG_CHECK1 ("VALUE_CHANGED", (x), VALUE)->frame_related)
@@ -4112,6 +4113,9 @@ track_expr_p (tree expr, bool need_rtl)
rtx decl_rtl;
tree realdecl;
+ if (TREE_CODE (expr) == DEBUG_EXPR_DECL)
+ return DECL_RTL_SET_P (expr);
+
/* If EXPR is not a parameter or a variable do not track it. */
if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL)
return 0;
@@ -6271,11 +6275,12 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
decl_or_value dv;
variable var;
location_chain loc;
- rtx result;
+ rtx result, subreg, xret;
- if (GET_CODE (x) == SUBREG)
+ switch (GET_CODE (x))
{
- rtx subreg = SUBREG_REG (x);
+ case SUBREG:
+ subreg = SUBREG_REG (x);
if (GET_CODE (SUBREG_REG (x)) != VALUE)
return x;
@@ -6297,22 +6302,31 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
return result;
- }
- if (GET_CODE (x) != VALUE)
- return x;
+ case DEBUG_EXPR:
+ dv = dv_from_decl (XTREE (x, 0));
+ xret = NULL;
+ break;
+
+ case VALUE:
+ dv = dv_from_value (x);
+ xret = x;
+ break;
+
+ default:
+ return x;
+ }
if (VALUE_RECURSED_INTO (x))
- return x;
+ return NULL;
- dv = dv_from_value (x);
var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
if (!var)
- return x;
+ return xret;
if (var->n_var_parts == 0)
- return x;
+ return xret;
gcc_assert (var->n_var_parts == 1);
@@ -6332,7 +6346,7 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
if (result)
return result;
else
- return x;
+ return xret;
}
/* Expand VALUEs in LOC, using VARS as well as cselib's equivalence
@@ -6382,6 +6396,9 @@ emit_note_insn_var_location (void **varp, void *data)
decl = dv_as_decl (var->dv);
+ if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
+ goto clear;
+
gcc_assert (decl);
complete = true;