diff options
-rw-r--r-- | gcc/ChangeLog | 54 | ||||
-rw-r--r-- | gcc/cfgexpand.c | 12 | ||||
-rw-r--r-- | gcc/cselib.c | 12 | ||||
-rw-r--r-- | gcc/emit-rtl.c | 8 | ||||
-rw-r--r-- | gcc/gengtype.c | 2 | ||||
-rw-r--r-- | gcc/gimple-iterator.c | 8 | ||||
-rw-r--r-- | gcc/print-rtl.c | 6 | ||||
-rw-r--r-- | gcc/rtl.c | 4 | ||||
-rw-r--r-- | gcc/rtl.def | 4 | ||||
-rw-r--r-- | gcc/sched-vis.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/debug/pr41264-1.c | 36 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/debug/pr41343-1.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/guality/pr41447-1.c | 25 | ||||
-rw-r--r-- | gcc/tree-dump.c | 4 | ||||
-rw-r--r-- | gcc/tree-flow.h | 6 | ||||
-rw-r--r-- | gcc/tree-pretty-print.c | 3 | ||||
-rw-r--r-- | gcc/tree-ssa-dce.c | 26 | ||||
-rw-r--r-- | gcc/tree-ssa-forwprop.c | 8 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-im.c | 20 | ||||
-rw-r--r-- | gcc/tree-ssa-operands.c | 4 | ||||
-rw-r--r-- | gcc/tree-ssa-reassoc.c | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-sink.c | 7 | ||||
-rw-r--r-- | gcc/tree-ssa.c | 240 | ||||
-rw-r--r-- | gcc/tree-ssanames.c | 2 | ||||
-rw-r--r-- | gcc/tree.c | 13 | ||||
-rw-r--r-- | gcc/tree.def | 4 | ||||
-rw-r--r-- | gcc/tree.h | 4 | ||||
-rw-r--r-- | gcc/var-tracking.c | 41 |
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; |